Virtual Memory Management

Runtime provides a set of APIs for virtual memory management, allowing you to manage memory more precisely. For example, you can allocate a large contiguous block of virtual memory in advance to simplify subsequent management and usage. Additionally, you can allocate physical memory on demand and map it to virtual memory addresses, enabling precise management and maximizing the utilization of physical memory. Furthermore, you can use handles in virtual memory management to share physical memory between processes.

The following is a basic example of using the virtual memory. After allocating the physical memory and virtual memory, you can use the aclrtMapMem API to map the physical memory to the virtual memory. Then, you can access the corresponding data using the virtual address.
void SampleTest()
{
    // 1. Query the memory allocation granularity and align the size.
    // Set the attributes of the physical memory to be allocated.
    aclrtPhysicalMemProp prop = {};
    prop.handleType = ACL_MEM_HANDLE_TYPE_NONE;            // Handle type. Currently, only ACL_MEM_HANDLE_TYPE_NONE is supported.
    prop.allocationType = ACL_MEM_ALLOCATION_TYPE_PINNED;  // Memory allocation type. Currently, only page-locked memory can be allocated.
    prop.memAttr = ACL_HBM_MEM_NORMAL;                     // Memory attribute. HBM memory is allocated here.
    prop.location.type = ACL_MEM_LOCATION_TYPE_DEVICE;     // Memory location. Device memory is allocated here, and the device ID is 0.
    prop.location.id = 0;
    // Query the minimum memory allocation granularity.
    size_t granularity = 0UL;
    aclrtMemGetAllocationGranularity(&prop, ACL_RT_MEM_ALLOC_GRANULARITY_MINIMUM, &granularity);
    // Align the memory based on the queried memory allocation granularity to save memory.
    const size_t dataSize = 1024 * sizeof(float);
    size_t alignedSize =  ((dataSize + granularity - 1U) / granularity) * granularity;

    // 2. Allocate physical memory.
    // Obtain the handle for storing physical memory information, which is used to allocate virtual memory. Note that the handle cannot be directly used as a virtual address for access.
    aclrtDrvMemHandle handle = nullptr;
    aclrtMallocPhysical(&handle, alignedSize, &prop, 0);  // The last flag parameter is set to 0 by default.

    // 3. Allocate reserved virtual memory.
    void *virPtr;
    // virPtr is the reserved virtual address pointer, and alignedSize is the size of the reserved memory.
    aclrtReserveMemAddress(&virPtr, alignedSize, 0, nullptr, 0);

    // 4. Map the virtual memory to the physical memory.
    // Associate the handle obtained during physical memory allocation with the reserved virtual address space.
    // Note that the size of the mapped memory (alignedSize) must be the same as the size set during physical memory allocation.
    aclrtMapMem(virPtr, alignedSize, 0, handle, 0);

    // 5. Set the access permission for the virtual memory.
    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. Memory access
    // The following uses device-to-host memory copy as an example to show how to normally access the mapped memory address.
    int *hostPtr;
    aclrtMallocHost(reinterpret_cast<void**>(&hostPtr), alignedSize);
    aclrtMemcpy(hostPtr, alignedSize, virPtr, alignedSize, ACL_MEMCPY_DEVICE_TO_HOST);
    aclrtFreeHost(hostPtr);

    // 7. Unmap the virtual memory from the physical memory.
    aclrtUnmapMem(virPtr);

    // 8. Free the virtual memory.
    aclrtReleaseMemAddress(virPtr);

    // 9. Free the physical memory.
    aclrtFreePhysical(handle);
}