CUDA| 锁页主机内存和零拷贝

本文介绍了零拷贝技术,一种通过在CPU和GPU间直接传输数据以提高效率的方法。它利用锁页主机内存避免内存拷贝,尤其适用于集成显卡和独立显卡的不同场景。使用cudaMallocHost和cudaHostAlloc等API进行内存管理是实现零拷贝的关键。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

锁页主机内存和零拷贝(Zero Copy)

锁页主机内存

虚拟内存:现代操作系统都支持虚拟内存,虚拟内存是通过将内存中暂时不使用的内容换出到外存上,从而腾出空间存放将要调入内存的内容。

分页存储管理方式:分页的基本方法是将地址空间等分成某一个固定大小的页,来方便管理。

锁页主机内存(Pinned Host Memory或Page-locked Host Memory):锁页就是将内存页面标记为不可被操作系统换出的内存,也就是不会被换出到磁盘中。锁页内存又可以称为固定内存、不可分页内存。

零拷贝

CPU内存管理默认是虚拟内存管理,也就是pageable(可分页),而GPU内存管理默认都是锁页的。

零拷贝(Zero Copy):通过设置CPU锁页内存,允许GPU通过物理地址直接访问CPU内存(Direct Memory Access,DMA),直接在主机和GPU之间复制数据。

原理:在内存和设备之间传输数据的时候,零拷贝可以避免从外存到内存的复制操作,从而提高数据传输效率。
对于可分页的CPU内存,会先分配锁页主机内存,再将需要的数据拷贝到这个锁页主机内存,然后从锁页内存传输数据给设备内存。因为对于可分页的CPU内存,可能会被CPU换出了内存,所以GPU需要拷贝该数据的时候并不能安全访问到。
但是对于已经锁页的CPU内存,GPU可以根据物理地址直接访问,Kernel就可以直接使用指针来访问主机内存了,读取的数据会直接写入寄存器中。

优势:

  • 锁页内存的地址可以从主机地址空间映射到CUDA 地址空间,免去了从外存换入内存的拷贝开销,也就是实现零拷贝。
  • 当设备内存不足的情况下可以利用主机内存。
  • 提高PCIe传输率,因为GPU不需要先等CPU内容拷贝到GPU再进行运算,就可以进行流水线,也就边传输边计算。

零拷贝的使用情况

集成显卡和独立显卡:

  • 集成显卡:集成显卡集成在主板上,通常和CPU集成在同一个芯片组,通常与系统内存共享一部分空间,对系统内存的性能产生一定的影响。
  • 独立显卡:独立显卡是独立的图形处理器,插在主板上的PCIe插槽中,拥有自己的独立显存,可以很方便更新换代

PCIe总线:总线就是处理器连接多个硬件之间的一条电路,PCIe是个规范。

零拷贝的使用:

  • 集成显卡:一定能提高性能,和CPU本身就共享内存,使用锁页主机内存后,能够避免外存拷贝到内存的开销。
  • 独立显卡:
    • 数据不适合GPU内存,例如数据太大GPU存不下。
    • 该数据GPU只和CPU进行一次读写,如果需要进行多次读写的话会产生GPU和CPU数据多次搬运开销,不如一次性复制到GPU。

注意:锁页主机内存是稀缺资源,分配太多会使得虚拟内存的物理存储器数量减少,会降低系统的整体性能。

如何使用零拷贝

GPU内存默认都是锁业内存的,并不支持虚拟内存,也就是不支持把内存交换到磁盘上。

CPU内存默认都是可分页的,支持虚拟内存,也就是支持把内存交换到磁盘上。所以如果先要在主机上分配锁页内存,那么就不能用之常用的分配内存方式。而是需要用cudaMallocHost() 和cudaHostAlloc()来分配锁页主机内存,或者cudaHostRegister() 把可分页内存标记为锁页内存,从而实现零拷贝。

__host__ ​cudaError_t cudaMallocHost ( void** ptr, size_t size )
__host__ ​cudaError_t cudaHostAlloc ( void** pHost, size_t size, unsigned int  flags )
__host__ ​cudaError_t cudaHostRegister(void *ptr, size_tsize, unsigned int flags )

其中cudaHostAlloc中的flags参数有四种:

  • cudaHostAllocDefault:默认,等价于cudaMallocHost。
  • cudaHostAllocPortable:多个CPU线程通过共享一块页锁定内存,从而实现cpu线程间的通信。
  • cudaHostAllocWriteCombined:提升块锁页在PCIE总线(用于主机和外部设备的连接)上传输速率, 对主机来说没什么提升效率。对于主机写和设备读的情况来说,比较适合。
  • cudaHostAllocMapped:分配的内存可以被kernel(核函数)直接访问。

而cudaHostRegister中的flags参数只有cudaHostAllocPortable和cudaHostAllocMapped。

注意,锁页主机内存需要用cudaFreeHost()来释放。

__host__ ​cudaError_t cudaFreeHost ( void* ptr )
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值