内存映射:
在将原来的在CPU上运行的程序改为到GPU上进行并行的程序时,主机与设备之间数据传输的时间的问题将被暴露出来,通常程序处理只需几十毫秒甚至更少,但数据传输的时间将远远大于传输的时间,内存映射的方法能很好解决,不必传输数据。
通过将标志cudaHostAllocMapped传递给cudaHostAlloc()或将标志cudaHostRegisterMapped传递给cudaHostRegister(),可以将一个分页面锁定主机内存块映射到设备的地址空间中。
因此,这样的块通常有两个地址:一个是由cudaHostAlloc()或malloc()返回的主机内存,另一个是可以使用cudaHostGetDevicePointer()获取的设备内存中的地址,然后用于访问内核中的块。 唯一的例外情况是使用cudaHostAlloc()分配的指针以及统一虚拟地址空间中提到的统一地址空间用于主机和设备。
直接从内核访问主机内存有几个好处:
1 不需要在设备内存中分配一个块,并在该块和主机内存中的块之间复制数据。 内核根据需要隐式执行数据传输;
2 无需使用流将数据传输与内核执行重叠; 内核发起的数据传输自动与内核执行重叠。
因为映射的页面锁定内存在主机和设备之间共享, 所以应用程序必须使用流或事件同步内存访问以避免任何可能的 read-after-write, writeafter-read, 或者write-after-write的危害。
为了能够检索指向任何映射页面锁定内存的设备指针,在执行任何其他CUDA调用之前,必须通过使用cudaDeviceMapHost标志调用cudaSetDeviceFlags()来启用页锁内存映射。 否则,cudaHostGetDevicePointer()将返回一个错误
如果设备不支持映射的页面锁定主机内存,cudaHostGetDevicePointer()也会返回一个错误。 应用程序可以通过检查canMapHostMemory设备属性来查询此功能,对于支持映射页面锁定主机内存的设备,该属性等于1。
请注意,从主机或其他设备的角度来看,在映射页面锁定内存上运行的原子函数(请参阅Atomic Functions)不是原子的。
另请注意,CUDA运行时需要将从设备发起的1字节,2字节,4字节和8字节自然对齐的加载和存储到主机内存的内容保存为从主机和其他角度的单个访问 设备。 在某些平台上,原子到内存可能会被硬件分解成单独的加载和存储操作。 这些组件加载和存储操作对保存自然对齐的访问具有相同的要求。 例如,CUDA运行时不支持PCI Express总线拓扑,PCI Express桥接器将8字节自然对齐的写入分为设备和主机之间的两个4字节写入。