当前位置: 代码迷 >> CUDA >> cuda的Pinned Memory(分页锁定内存储器)
  详细解决方案

cuda的Pinned Memory(分页锁定内存储器)

热度:1003   发布时间:2016-04-29 10:45:05.0
cuda的Pinned Memory(分页锁定内存)

当为了提高CUDA程序的主机内存和设备内存传输消耗时,可以尝试一下两种方案

一:使用分页锁定内存,分页锁定内存和显存之间的拷贝速度大约是6GB/s,普通的分页内存和GPU间的速度大约是3GB/s,(另外:GPU内存间速度是30G,CPU间内存速度是10GB/s),但是这种方法会带来额外的cpu内存间的拷贝时间

二:使用内存映射(Zero Copy)让GPU直接使用CPU的内存,减少主机和设备间内存传输的时间,但是这种方法对于2.2以后的cuda版本未必管用

最好办法是通过实验对比方案一和二是否取得效果。

========================================================================================================

cuda运行时提供了使用分页锁定主机存储器(也称为pinned)的函数(与常规的使用malloc()分配的可分页的主机存储器不同):

cudaHostAlloc()和cudaFreeHost()分配和释放分页锁定主机存储器;
cudaHostRegister()分页锁定一段使用malloc()分配的存储器。
如前文(可阅读以上文章)提到的,在某些设备上,设备存储器和分页锁定主机存储器间数据拷贝可与内核执行并发进行;
  在一些设备上,分页锁定主机内存可映射到设备地址空间,减少了和设备间的数据拷贝,详见3.2.4.3节;
  在有前端总线的系统上,如果主机存储器是分页锁定的,主机存储器和设备存储器间的带宽会高些,如果再加上3.2.4.2节所描述的写结合(write-combining)的话,带宽会更高。

  然而分页锁定主机存储器是稀缺资源,所以可分页内存分配得多的话,分配会失败。另外由于减少了系统可分页的物理存储器数量,分配太多的分页锁定内存会降低系统的整体性能。 SDK中的simple zero-copy例子中有分页锁定API的详细文档

1、可分享存储器(portable memory)
  一块分页锁定存储器可被系统中的所有设备使用(参看前文以了解更多的多设备系统细节),但是默认的情况下,上面说的使用分布锁定存储器的好处只有分配它时,正在使用的设备可以享有(如果可能的话,所有的设备共享同一个地址空间,参见“相关阅读”中的文章)。为了让所有线程可以使用分布锁定共享存储器的好处,可以在使用cudaHostAlloc()分配时传入cudaHostAllocPortable标签,或者在使用cudaHostRegister()分布锁定存储器时,传入cudaHostRegisterPortable标签。
  2、写结合存储器
  默认情况下,分页锁定主机存储器是可缓存的。可以在使用cudaHostAlloc()分配时传入cudaHostAllocWriteCombined标签使其被分配为写结合的。写结合存储器没有一级和二级缓存资源,所以应用的其它部分就有更多的缓存可用。另外写结合存储器在通过PCI-e总线传输时不会被监视(snoop),这能够获得高达40%的传输加速。 从主机读取写结合存储器极其慢,所以写结合存储器应当只用于那些主机只写的存储器。
  3、被映射存储器
  在一些设备上,在使用cudaHostAlloc()分配时传入cudaHostAllocMapped标签或者在使用cudaHostRegister()分布锁定一块主机存储器时使用cudaHostRegisterMapped标签,可分配一块被映射到设备地址空间的分页锁定主机存储器。这块存储器有两个地址:一个在主机存储器上,一个在设备存储器上。主机指针是从cudaHostAlloc()或malloc()返回的,设备指针可通过cudaHostGetDevicePointer()函数检索到,可以使用这个设备指针在内核中访问这块存储器。唯一的例外是主机和设备使用统一地址空间时,参见前文(可阅读“相关阅读”的文章)。
        从内核中直接访问主机存储器有许多优点:
  ①无须在设备上分配存储器,也不用在这块存储器和主机存储器间显式传输数据;数据传输是在内核需要的时候隐式进行的。
  ②无须使用流(参见3.2.5.4节)重叠数据传输和内核执行;数据传输和内核执行自动重叠。
  由于被映射分页锁定存储器在主机和设备间共享,应用必须使用流或事件(参见3.2.5节)来同步存储器访问以避免任何潜在的读后写,写后读,或写后写危害。
  为了在给定的主机线程中能够检索到被映射分页锁定存储器的设备指针,必须在调用任何CUDA运行时函数前调用cudaSetDeviceFlags(),并传入cudaDeviceMapHost标签。否则,cudaHostGetDevicePointer()将会返回错误。
  一块分页锁定存储器可同时分配为被映射的和可分享的(前面的文章中提过),这种情况下,每个要映射这块存储器的主机线程必须调用cudaHostGetDevicePointer()检索设备指针,因为每个主机线程持有的设备指针一般不同。
  如果设备不支持被映射分页锁定存储器,cudaHostGetDevicePointer()将会返回错误。应用可以检查canMapHostMemory属性应用以查询这种能力,如果支持映射分页锁定主机存储器,将会返回1。 注意:从主机和其它设备的角度看,操作被映射分页锁定存储器的原子函数不是原子的

  相关解决方案