开发者
资源

虚拟内存管理

Runtime提供了一套虚拟内存管理的API接口,可供开发者更加精细化的管理其内存,例如:可以提前申请好大片的连续的虚拟内存,以简化后续的管理使用,同时可以按需在使用过程中申请物理内存并与虚拟内存做地址映射,即可以精细化管理,也可以最大化利用物理内存;此外还可以在进程之间利用虚拟内存管理中的handle来实现物理内存共享。

以下是一个虚拟内存的基本使用示例,申请好物理内存以及虚拟内存后,通过aclrtMapMem接口进行映射,即可通过虚拟地址访问对应的数据:
void SampleTest()
{
    // 1. 查询内存申请粒度,并对size做对齐处理
    // 设置要申请的物理内存属性
    aclrtPhysicalMemProp prop = {};
    prop.handleType = ACL_MEM_HANDLE_TYPE_NONE;            // handle类型,当前仅支持 ACL_MEM_HANDLE_TYPE_NONE
    prop.allocationType = ACL_MEM_ALLOCATION_TYPE_PINNED;  // 内存分配类型,当前仅支持分配锁页内存
    prop.memAttr = ACL_HBM_MEM_NORMAL;                     // 内存属性,这里申请HBM内存
    prop.location.type = ACL_MEM_LOCATION_TYPE_DEVICE;     // 内存所在位置,这里申请Device内存,且deviceId为0
    prop.location.id = 0;
    // 查询申请最小内存粒度
    size_t granularity = 0UL;
    aclrtMemGetAllocationGranularity(&prop, ACL_RT_MEM_ALLOC_GRANULARITY_MINIMUM, &granularity);
    // 根据查询到的内存申请粒度做内存对齐,以便节约内存
    const size_t dataSize = 1024 * sizeof(float);
    size_t alignedSize =  ((dataSize + granularity - 1U) / granularity) * granularity;

    // 2. 申请物理内存
    // 获取存放物理内存信息的handle,用于后续申请虚拟内存使用,需要注意的是handle并不能直接当虚拟地址访问
    aclrtDrvMemHandle handle = nullptr;
    aclrtMallocPhysical(&handle, alignedSize, &prop, 0);  // 最后一个flag参数当前默认填0

    // 3. 申请预留虚拟内存
    void *virPtr;
    // virPtr即为申请预留的虚拟地址指针,alignedSize为申请预留的内存大小
    aclrtReserveMemAddress(&virPtr, alignedSize, 0, nullptr, 0);

    // 4. 映射虚拟内存到物理内存上
    // 将申请物理内存时获取的handle与申请预留的虚拟地址空间关联起来
    // 需要注意的是,映射的内存大小alignedSize要与申请物理内存时设置的size大小一致
    aclrtMapMem(virPtr, alignedSize, 0, handle, 0);

    // 5. 设置虚拟内存访问权限
    aclrtMemAccessDesc accessDesc = {};
    accessDesc.flags = ACL_RT_MEM_ACCESS_FLAGS_READWRITE;
    accessDesc.location.type = ACL_MEM_LOCATION_TYPE_DEVICE;
    accessDesc.location.id = 0;
    aclrtMemSetAccess(virPtr, alignedSize, &accessDesc, 1);

    // 6. 内存访问
    // 这里以Device->Host的内存拷贝为例,展示正常访问映射后的内存地址
    int *hostPtr;
    aclrtMallocHost(reinterpret_cast<void**>(&hostPtr), alignedSize);
    aclrtMemcpy(hostPtr, alignedSize, virPtr, alignedSize, ACL_MEMCPY_DEVICE_TO_HOST);
    aclrtFreeHost(hostPtr);

    // 7. 取消虚拟内存与物理内存的映射
    aclrtUnmapMem(virPtr);

    // 8. 释放虚拟内存
    aclrtReleaseMemAddress(virPtr);

    // 9. 释放物理内存
    aclrtFreePhysical(handle);
}