CUDA学习之零拷贝内存

1.简介

       我们可以通过调用cudaHostAlloc( )来分配固定内存(或者说页锁定内存), 这种新型的主机内存能够确保不会交换出物理内存,并且传递参数 cudaHostAllocDefault来获得默认的固定内存。 这里介绍在分配固定内存时可以使用的其他参数值,除了cudaHostAllocDefauIt 外,还可以传递的标志之一是 cudaHostAllocMapped。通过cudaHostAllocMapped 分配的主机内存也是固定的, 它与通过 cudaHostAllocDefault分配的固定内存有着相同的属性,特别是当它不能从物理内存中交换出去或者重新定位时。 但这种内存除了可以用于主机与GPU之间的内存复制外, 还可以打破主机内存规则之一: 可以在CUDA C核函数中直接访问这种类型的主机内存。 由与这种内存不需要复制到GPU, 因此也称为零拷贝内存。

2.零拷贝内存的分配

       零拷贝内存是固定(不可分页)内存,该内存映射到设备地址空间中。可以通过下列函数创建一个到固定内存的映射:
              cudaError_t cudaHostAlloc(void **pHost, size_t count, unsigned int flags );
       这个函数分配了count字节的主机内存,该内存是页面锁定的且设备可访问的。用这个函数分配的内存必须用cudaFreeHost函数释放。flags参数可以对已分配内存的特殊属性进一步进行配置:
cudaHostAllocDefault
cudaHostAllocPortable
cudaHostAllocWriteCombined
cudaHostAllocMapped
       cudaHostAllocDefault函数使cudaHostAlloc函数的行为与cudaMallocHost函数一致。设置cudaHostAllocPortable函数可以返回能被所有CUDA上下文使用的固定内存,而不仅是执行内存分配的那一个。标志cudaHostAllocWriteCombined返回写结合内存,该内存可以在某些系统配置上通过PCIe总线上更快地传输,但是它在大多数主机上不能被有效地读取。因此,写结合内存对缓冲区来说是一个很好的选择,该内存通过设备使用映射的固定内存或主机到设备的传输。零拷贝内存的最明显的标志cudaHostAllocMapped,该标志返回,可以实现主机写入和设备读取被映射到设备地址空间中的主机内存。
       在使用标志cudaHostAllocMapped来分配主机内存后, 就可以从GPU中访问这块内存。 然而, GPU的虚拟内存空间与CPU是不同的, 因此在GPU上访间它们与在CPU上访间它们有着不同的地址。 调用cudaHostAlloc()将返回这块内存在CPU 上的指针,因此需要调用 cudaHostGetDevicePointer()来获得这块内存在GPU上的有效指针。这些指针将被传递给核函数, 并在随后由GPU对这块内存执行读取和写入等操作,可以使用下列函数获取映射到固定内存的设备指针:
              cudaError_t cudaHostGetDevicePointer(void **pDevice, void *pHost, unsigned int flags)
       该函数返回了一个在pDevice中的设备指针,该指针可以在设备上被引用以访问映射得到的固定主机内存。如果设备不支持映射得到的固定内存,该函数将失效。flag将留作以后使用。现在,它必须被置为0。

3. 注

  1. 当使用零拷贝内存来共享主机和设备间的数据时,必须同步主机和设备间的内存访问,同时更改主机和设备的零拷贝内存中的数据将导致不可预知的后果。
  2. 有两种常见的异构计算系统架构:集成架构和离散架构。
    在集成架构中,CPU和GPU集成在一个芯片上,并且在物理地址上共享主存。在这种架构中,由于无须在PCIe总线上备份,所以零拷贝内存在性能和可编程性方面可能更佳。
    对于通过PCIe总线将设备连接到主机的离散系统而言,零拷贝内存只在特殊情况下有优势。
  3. 因为映射的固定内存在主机和设备之间是共享的,必须同步内存访问来避免任何潜在的数据冲突,这种数据冲突一般是由多线程异步访问相同的内存而引起的。
  4. 注意不要过度使用零拷贝内存。由于其延迟较高,从零拷贝内存中读取设备核函数可能很慢。

猜你喜欢

转载自blog.csdn.net/weixin_43332627/article/details/84503518
今日推荐