开发者
资源

Host锁页内存使用

在CANN编程框架中,Host内存可以是Pageable内存,也可以是Page-Locked内存(也称锁页内存或Pinned内存):

  • Pageable内存,由操作系统统一管理。开发者可使用malloc、mmap等传统接口申请内存,使用free、munmap等接口释放内存当内存压力较大时,Pageable内存会被换出到后备存储提供的交换空间中。当Pageable内存中的数据被传输到Device时,数据首先会被复制到缓冲区,然后通过DMA(Direct Memory Access)通道传输到Device。
  • Page-Locked内存,即锁页内存。开发者需要用Runtime提供的API进行锁页内存的申请和释放,例如aclrtMallocHost、aclrtFreeHost等接口对于锁页内存,虚拟页与物理页的映射关系固定,在其生命周期内不会被换出至交换空间。当锁页内存中的数据被传输至Device时,直接通过DMA通道传输,无需经过缓冲区,传输性能更优。
    在Runtime中,使用锁页内存的好处如下
    • 设备可以直接通过DMA访问主机内存,无需经过缓冲区,可以提供更好的传输性能;
    • 数据搬运过程无需CPU参与,可以实现数据的异步传输;
    • 数据的异步传输,使传输过程和计算过程可以相互掩盖,减少传输+计算的整体时长。
锁页内存可直接通过aclrtMallocHost接口申请,示例代码如下。如果需要在申请时指定内存的其他配置,例如自定义模块ID、配置VA(virtual address)一致性等,也可以使用aclrtMallocHostWithCfg接口申请。
// 资源初始化
......

// 申请锁页内存
void *hostPtr = NULL;
aclrtMallocHost(&hostPtr, size);

// 申请Device内存
void *devicePtr = NULL;
aclrtMalloc(&devicePtr, size, ACL_MEM_MALLOC_NORMAL_ONLY);

// 内存初始化
......

// 异步H2D
aclrtMemcpyAsync(devicePtr, size, hostPtr, size, ACL_MEMCPY_HOST_TO_DEVICE, stream);

// 等待异步拷贝完成
aclrtSynchronizeStream(stream);

// 资源释放
if (devicePtr) (void)aclrtFree(devicePtr);
if (hostPtr) (void)aclrtFreeHost(hostPtr);
......
若使用malloc/mmap等内存管理接口申请Pageable内存,当前Runtime提供了aclrtHostRegisterV2接口,用于将Pageable内存转换为锁页内存,供Device访问。请注意,当OS内核版本为5.10或更低时,此方法会导致异常,此时应通过aclrtMallocHost接口申请锁页内存。
// 申请Pageable内存
void *hostPtr = malloc(size);

// 注册为锁页内存(ACL_HOST_REG_PINNED),并映射到Device(ACL_HOST_REG_MAPPED)
aclrtHostRegisterV2(hostPtr, size, ACL_HOST_REG_PINNED|ACL_HOST_REG_MAPPED);

// 获取Device地址
void *devicePtr = NULL;
aclrtHostGetDevicePointer(hostPtr, &devicePtr, 0);

// 任务通过Device地址访问对应内存
...

// 资源释放
aclrtHostUnregister(hostPtr);
free(hostPtr);

若涉及Host内存的VA(virtual address)一致性:

  • Host内存可以通过aclrtHostRegister接口注册到Device,根据Host指针映射得到Device指针,供Device使用;默认情况下,对于同一块Host内存,Host和Device看到的虚拟地址是不同的;
  • 如果需要Host和Device的虚拟地址保持一致,可以使用aclrtMallocHostWithCfg接口申请锁页内存,并在aclrtMallocConfig参数中指定ACL_RT_MEM_ATTR_VA_FLAG属性,后续再注册获取到的Device虚拟地址即可与Host虚拟地址一致。