对CUDA架构而言,主机端的内存被分为两种,一种是可分页内存(pageable memroy)和页锁定内存(page-lock或 pinned)。可分页内存是由操作系统API malloc()在主机上分配的,页锁定内存是由CUDA函数cudaHostAlloc()在主机内存上分配的,页锁定内存的重要属性是主机的操作系统将不会对这块内存进行分页和交换操作,确保该内存始终驻留在物理内存中。

GPU知道页锁定内存的物理地址,可以通过“直接内存访问(Direct Memory Access,DMA)”技术直接在主机和GPU之间复制数据,速率更快。由于每个页锁定内存都需要分配物理内存,并且这些内存不能交换到磁盘上,所以页锁定内存比使用标准malloc()分配的可分页内存更消耗内存空间。

页锁定内存的内配、操作和可分页内存的对比:

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "iostream"
#include <stdio.h> using namespace std; float cuda_host_alloc_test(int size, bool up)
{
//耗时统计
cudaEvent_t start, stop;
float elapsedTime;
cudaEventCreate(&start);
cudaEventCreate(&stop); int *a, *dev_a; //在主机上分配页锁定内存
cudaError_t cudaStatus = cudaHostAlloc((void **)&a, size * sizeof(*a), cudaHostAllocDefault);
if (cudaStatus != cudaSuccess)
{
printf("host alloc fail!\n");
return -1;
} //在设备上分配内存空间
cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(*dev_a));
if (cudaStatus != cudaSuccess)
{
fprintf(stderr, "cudaMalloc failed!\n");
return -1;
} //计时开始
cudaEventRecord(start, 0); for (int i = 0; i < 100; i++)
{ //从主机到设备复制数据
cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(*dev_a), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess)
{
fprintf(stderr, "cudaMemcpy Host to Device failed!\n");
return -1;
} //从设备到主机复制数据
cudaStatus = cudaMemcpy(a, dev_a, size * sizeof(*dev_a), cudaMemcpyDeviceToHost);
if (cudaStatus != cudaSuccess)
{
fprintf(stderr, "cudaMemcpy Device to Host failed!\n");
return -1;
}
}
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime, start, stop); cudaFreeHost(a);
cudaFree(dev_a);
cudaEventDestroy(start);
cudaEventDestroy(stop); return (float)elapsedTime / 1000; } float cuda_host_Malloc_test(int size, bool up)
{
//耗时统计
cudaEvent_t start, stop;
float elapsedTime;
cudaEventCreate(&start);
cudaEventCreate(&stop); int *a, *dev_a; //在主机上分配可分页内存
a = (int*)malloc(size * sizeof(*a)); //在设备上分配内存空间
cudaError_t cudaStatus = cudaMalloc((void **)&dev_a, size * sizeof(*dev_a));
if (cudaStatus != cudaSuccess)
{
fprintf(stderr, "cudaMalloc failed!\n");
return -1;
} //计时开始
cudaEventRecord(start, 0); for (int i = 0; i < 100; i++)
{ //从主机到设备复制数据
cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(*dev_a), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess)
{
fprintf(stderr, "cudaMemcpy Host to Device failed!\n");
return -1;
} //从设备到主机复制数据
cudaStatus = cudaMemcpy(a, dev_a, size * sizeof(*dev_a), cudaMemcpyDeviceToHost);
if (cudaStatus != cudaSuccess)
{
fprintf(stderr, "cudaMemcpy Device to Host failed!\n");
return -1;
}
}
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime, start, stop); free(a);
cudaFree(dev_a);
cudaEventDestroy(start);
cudaEventDestroy(stop); return (float)elapsedTime / 1000;
} int main()
{
float allocTime = cuda_host_alloc_test(100000, true);
cout << "页锁定内存: " << allocTime << " s" << endl;
float mallocTime = cuda_host_Malloc_test(100000, true);
cout << "可分页内存: " << mallocTime << " s" << endl;
getchar();
return 0;
}

对比效果,页锁定内存的访问时间约为可分页内存的访问时间的一半:

CUDA页锁定内存(Pinned Memory)的更多相关文章

  1. 6.1 CUDA: pinned memory固定存储

    CPU和GPU内存交互 在CUDA编程中,内存拷贝是非常费时的一个动作. 从上图我们可以看出:1. CPU和GPU之间的总线bus是PCIe,是双向传输的. 2. CPU和GPU之间的数据拷贝使用DM ...

  2. 如何启用“锁定内存页”选项 (Windows)

    默认情况下,禁用 Windows 策略"锁定内存页"选项.必须启用此权限才能配置地址窗口化扩展插件 (AWE).此策略将确定哪些帐户可以使用进程将数据保留在物理内存中,从而阻止系统 ...

  3. [SPDK/NVMe存储技术分析]015 - 理解内存注册(Memory Registration)

    使用RDMA, 必然关系到内存区域(Memory Region)的注册问题.在本文中,我们将以mlx5 HCA卡为例回答如下几个问题: 为什么需要注册内存区域? 注册内存区域有嘛好处? 注册内存区域的 ...

  4. linux内核剖析(十一)进程间通信之-共享内存Shared Memory

    共享内存 共享内存是进程间通信中最简单的方式之一. 共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区. 共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程 ...

  5. 内存管理 - MEMORY POOL

    内存池优势: 效率高,频繁的new和delete效率低下 减少内存碎片,反复向系统申请和释放内存会产生大量内存碎片 防止内存泄露 内存池设计思路: 内存池可以根据实际需要,设计成不同的样子.下面是针对 ...

  6. 内存分配器 (Memory Allocator)

    对于大多数开发人员而言,系统的内存分配就是一个黑盒子,就是几个API的调用.有你就给我,没有我就想别的办法. 来UC前,我就是这样觉得的.实际深入进去时,才发现这个领域里也是百家争鸣.非常热闹.有操作 ...

  7. 从五大结构体,带你掌握鸿蒙轻内核动态内存Dynamic Memory

    摘要:本文带领大家一起剖析了鸿蒙轻内核的动态内存模块的源代码,包含动态内存的结构体.动态内存池初始化.动态内存申请.释放等. 本文分享自华为云社区<鸿蒙轻内核M核源码分析系列九 动态内存Dyna ...

  8. Android 内存管理 &Memory Leak & OOM 分析

    转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...

  9. 关于Linux的缓存内存 Cache Memory详解<转>

    转自 http://www.ha97.com/4337.html PS:前天有童鞋问我,为啥我的Linux系统没运行多少程序,显示的可用内存这么少?其实Linux与Win的内存管理不同,会尽量缓存内存 ...

随机推荐

  1. GridView与ArrayAdapter的结合

    activity_main.xml: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android ...

  2. Kinect开发笔记之三Kinect开发环境配置具体解释

            0.前言:        首先说一下我的开发环境,Visual Studio是2013的,系统是win8的64位版本号,SDK是Kinect for windows SDK 1.8版本 ...

  3. UVA 11178 - Morley's Theorem 向量

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...

  4. (转)ipv4的网段表示方法

    简单一点举例说明:ip段:10.0.0.1-10.0.0.255            的表示方法:10.0.0.0/24ip段:10.0.0.1-10.0.255.255        的表示方法: ...

  5. radare, the reverse engineering framework

    History The radare project [http://radare.org/] started in February of 2006 aiming to provide a free ...

  6. SoC总线专题

    SoC总线专题 TileLink ARM系列总线 APB AHB AXI CHI Wishbone

  7. widow下svn上传项目时的文件可执行权限问题

    还是项目上发现的问题,要上传Android的源码项目.这里客户端是windows的机器, 测试后发现俩个问题. 1. 文件后缀是.so的文件默认上传不了.    2. 文件后缀是.sh的文件,上传后, ...

  8. 小型机与pc服务器区别

    按CPU的类型来区分,小型机是基于RISC(精简指令集)架构的专用服务器,而服务器是基于CISC(复杂指令集)架构的PC服务器.小型机相对于普通服务器来说,一直有不可比拟的优势.(1)如必能稳定,它具 ...

  9. MFC注册窗口类以及FindWindow按窗口类名查询(避免用#32770获取窗口句柄)

    呵呵,最近在研究SendMessage函数,其中需要用到m_hWnd,之后延伸着又尝试获得窗口的句柄,于是遇到了FindWindow函数,原型如下: HWND FindWindow ( LPCSTR ...

  10. 【JAVA编码专题】总结 分类: B1_JAVA 2015-02-11 15:11 290人阅读 评论(0) 收藏

    第一部分:编码基础 为什么需要编码:用计算机看得懂的语言(二进制数)表示各种各样的字符. 一.基本概念 ASCII.Unicode.big5.GBK等为字符集,它们只定义了这个字符集内有哪些字符,以及 ...