CUDA实践指南(十二)

Zero Copy:
零拷贝是CUDA工具包2.2版中添加的一项功能。 它使GPU线程可以直接访问主机内存。 为此,它需要映射固定(不可分页)内存。 在集成GPU上(即CUDA设备属性结构的集成字段设置为1的GPU),映射固定内存始终是性能增益,因为它避免了多余的副本,因为集成的GPU和CPU内存在物理上是相同的。 在独立的GPU上,映射固定内存仅在某些情况下才有优势。 由于数据未在GPU上缓存,映射的固定内存应该只读取或写入一次,并且读取和写入内存的全局加载和存储应该合并。 可以使用零拷贝代替流,因为内核发起的数据传输会自动覆盖内核执行,而无需设置和确定最佳数据流的开销。
低优先级:对于CUDA Toolkit 2.2及更高版本,在集成GPU上使用零拷贝操作。
零拷贝主机代码:

float *a_h, *a_map;
...
cudaGetDeviceProperties(&prop, 0);
if (!prop.canMapHostMemory)
exit(0);
cudaSetDeviceFlags(cudaDeviceMapHost);
cudaHostAlloc(&a_h, nBytes, cudaHostAllocMapped);
cudaHostGetDevicePointer(&a_map, a_h, 0);
kernel << <gridSize, blockSize >> >(a_map);

在此代码中,由cudaGetDeviceProperties()返回的结构的canMapHostMemory字段用于检查设备是否支持将主机内存映射到设备的地址空间。 通过使用cudaDeviceMapHost调用cudaSetDeviceFlags()来启用页面锁定内存映射。 请注意,必须在设置设备或进行需要状态的CUDA调用(即本质上,在创建上下文之前)之前调用cudaSetDeviceFlags()。 页面锁定的映射主机内存使用cudaHostAlloc()进行分配,指向映射设备地址空间的指针通过函数cudaHostGetDevicePointer()获取。 在零拷贝主机代码的代码中,kernel()可以使用指针a_map来引用映射的固定主机内存,其方式与如果a_map引用设备内存中的位置完全相同。
映射固定主机内存允许您将CPU-GPU内存传输与计算重叠,同时避免使用CUDA流。 但由于对这些内存区域的任何重复访问都会导致重复的PCIe传输,因此请考虑在设备内存中创建第二个区域以手动缓存先前读取的主机内存数据。
统一虚拟寻址:
计算能力2.0和更高版本的设备在使用TCC驱动程序模式时,支持在64位Linux,Mac OS和Windows XP以及Windows Vista / 7上称为统一虚拟寻址(UVA)的特殊寻址模式。 使用UVA,所有安装的受支持设备的主机内存和设备内存共享一个虚拟地址空间。
在UVA之前,应用程序必须跟踪哪些指向设备内存(以及哪个设备)的指针,哪些指向主机内存作为每个指针的单独元数据位(或者程序中的硬编码信息)。 另一方面,使用UVA,通过使用cudaPointerGetAttributes()检查指针的值,可以简单地确定指针指向的物理内存空间。
在UVA下,与cudaHostAlloc()一起分配的固定主机内存将具有相同的主机和设备指针,因此不必为此类分配调用cudaHostGetDevicePointer()。 然而,事后通过cudaHostRegister()固定的主机内存分配将继续具有与其主机指针不同的设备指针,因此在这种情况下,cudaHostGetDevicePointer()仍然是必需的。
在受支持的配置中,UVA也是通过PCIe总线直接支持对等(P2P)数据传输以支持GPU的必要先决条件,绕过主机内存。

上一篇:ASP.NET CORE系列【五】webapi整理以及RESTful风格化


下一篇:2022,你的团队距离持续部署还有多远?