3. ROCm HIP 内存分配接口到 libhsakmt 的调用路径分析

1. 核心结论

HIP 内存分配链路的核心,是看清楚用户态指针 API 如何逐层转换成 ROCclr memory object、ROCr HSA memory/SVM 操作,以及最终的 libhsakmt/KFD 资源管理动作。

主路径可以概括为:

cpp 复制代码
hipMalloc / hipMallocManaged / hipHostMalloc
  -> HIP Runtime API 层
  -> ihipMalloc / ihipMallocManaged / ihipHostMalloc
  -> hip::Device / amd::Context
  -> amd::SvmBuffer / amd::Buffer / amd::Memory
  -> roc::Memory / roc::Device
  -> Hsa::memory_pool_allocate / Hsa::svm_attributes_set
  -> ROCr Runtime
  -> hsaKmtAllocMemory / hsaKmtMapMemoryToGPUNodes / hsaKmtSVMSetAttr
  -> KFD ioctl

这条链路里有三个关键转换:

阶段 看到的对象 说明
HIP API void* 用户只看到裸指针
HIP/ROCclr amd::Memory / amd::Buffer runtime 用内存对象保存大小、flags、context、device 等元数据
ROCr/libhsakmt HSA memory pool / SVM range / KFD allocation 真正和 KFD 交互的底层资源
text 复制代码
根据当前 hip::Device 找到 amd::Context
  -> 创建 ROCclr memory object
  -> 在 ROCm 后端创建 roc::Memory
  -> 通过 ROCr/HSA 分配真实内存或建立 SVM range
  -> 把返回的裸指针登记到 runtime 的内存对象表

HIP 内存相关 API 很多,本文先把它们按语义分组:

类型 HIP API 典型语义
Device memory hipMalloc / hipFree 分配和释放 GPU device memory
Managed memory hipMallocManaged / hipMemAdvise / hipMemPrefetchAsync 分配和控制 HMM/SVM 管理内存
Host memory hipHostMalloc / hipHostRegister pinned host memory / registered memory
Copy path hipMemcpy / hipMemcpyAsync 不一定分配,但依赖内存对象查询
Memory query hipPointerGetAttributes / hipMemGetInfo 查询 runtime 元数据或后端状态
Memory pool hipMemPool* / async malloc HIP runtime 侧的池化分配路径

本文主线先关注这些接口:

text 复制代码
hipMalloc
hipFree
hipMallocManaged
hipMemAdvise
hipMemPrefetchAsync
hipHostMalloc / hipHostRegister

其中 hipMemAdvise 的完整属性翻译链放在了下一篇:HIP hipMemAdvise 到 libksamkt中的 hsaKmtSVMSetAttr 调用链分析;本文只把它放到内存分配体系里,说明它和 SVM range、libhsakmt 的关系。

2. 前置背景:Topology 发现之后有什么

内存分配发生在 HIP runtime 初始化之后。前一篇 topology 文档已经说明,初始化后 HIP 层具备这些对象:

text 复制代码
hip::g_devices[N]
  -> hip::Device
    -> amd::Context
      -> amd::Device
        -> roc::Device
          -> hsa_agent_t
          -> HSA memory pools
          -> CPU agent / NUMA 信息
          -> P2P/link 信息

这一步对内存分配很重要,因为 hipMalloc 后续需要回答几个问题:

  1. 当前线程的 current device 是哪个 hip::Device
  2. 这个 hip::Device 对应哪个 amd::Context
  3. 这个 context 里的 amd::Device 在 ROCm 后端下是哪一个 roc::Device
  4. 这个 roc::Device 有哪些 GPU memory pool、fine-grain pool、CPU agent、NUMA 信息?
  5. 如果分配的是 managed/host memory,是否需要 HMM/SVM 属性初始化?

所以 topology 发现结束后,不只是"知道有几个 GPU",而是为后续内存分配准备好了:

text 复制代码
当前 HIP device
  -> ROCclr context
  -> ROCclr device
  -> ROCm backend device
  -> HSA agent + memory pool

3. HIP Runtime API 入口模式

HIP 内存 API 入口一般分成两层:

text 复制代码
公共 HIP API
  -> HIP_INIT_API / 参数检查 / stream capture 检查
  -> ihip* 内部实现

hipMalloc 为例:

cpp 复制代码
hipError_t hipMalloc(void** ptr, size_t sizeBytes) {
  HIP_INIT_API(hipMalloc, ptr, sizeBytes);
  CHECK_STREAM_CAPTURE_SUPPORTED();
  HIP_RETURN_DURATION(ihipMalloc(ptr, sizeBytes, 0), ReturnPtrValue(ptr));
}

HIP_INIT_API 的意义是:如果 runtime 还没有初始化,就先触发 hip::init(),完成 device/topology/context 初始化。真正分配逻辑在 ihipMalloc()

hipFree 也类似:

cpp 复制代码
hipError_t hipFree(void* ptr) {
  HIP_INIT_API(hipFree, ptr);
  CHECK_STREAM_CAPTURE_SUPPORTED();
  HIP_RETURN(ihipFree(ptr));
}

所以调试时,公共 API 适合确认用户参数和初始化是否发生,ihip* 函数才是看业务逻辑的主要入口。

4. Device Memory 主路径:hipMalloc

hipMalloc 的核心实现是 ihipMalloc()

简化后的逻辑是:

cpp 复制代码
hipError_t ihipMalloc(void** ptr, size_t sizeBytes, unsigned int flags) {
  bool useHostDevice = (flags & CL_MEM_SVM_FINE_GRAIN_BUFFER) != 0;
  amd::Context* curDevContext = hip::getCurrentDevice()->asContext();
  amd::Context* amdContext = useHostDevice ? hip::host_context : curDevContext;

  const auto& dev_info = amdContext->devices()[0]->info();
  hip::getCurrentDevice()->SetActiveStatus();

  *ptr = amd::SvmBuffer::malloc(*amdContext, flags, sizeBytes,
                                dev_info.memBaseAddrAlign_,
                                useHostDevice ? curDevContext->svmDevices()[0] : nullptr);

  amd::Memory* memObj = getMemoryObject(hip::getCurrentDevice(), *ptr, offset);
  memObj->getUserData().deviceId = hip::getCurrentDevice()->deviceId();
  return hipSuccess;
}

这里有几个关键点。

第一,hipMalloc 默认使用当前 device 的 per-device context:

text 复制代码
hip::getCurrentDevice()
  -> asContext()
  -> 当前 device 对应的 amd::Context

第二,真正创建内存对象的入口是 ROCclr 的:

cpp 复制代码
amd::SvmBuffer::malloc(...)

SvmBuffer::malloc() 再转到 context:

cpp 复制代码
void* SvmBuffer::malloc(Context& context, cl_svm_mem_flags flags,
                        size_t size, size_t alignment,
                        const amd::Device* curDev, void* hostptr) {
  void* ret = context.svmAlloc(size, alignment, flags, curDev, hostptr);
  Add(ret_u, ret_u + size);
  return ret;
}

第三,context.svmAlloc() 会根据 context 里的 device 选择后端实现。ROCm 后端是:

text 复制代码
amd::Context::svmAlloc
  -> amd::Device::svmAlloc 虚接口
  -> roc::Device::svmAlloc

roc::Device::svmAlloc() 会创建一个隐藏的 ROCclr buffer:

cpp 复制代码
mem = new (context) amd::Buffer(context, flags, size, svmPtrUsed);
mem->create(nullptr);
amd::MemObjMap::AddMemObj(mem->getSvmPtr(), mem);
return mem->getSvmPtr();

到这里,HIP 用户拿到的是 void*,但 runtime 内部已经有了:

text 复制代码
用户指针 ptr
  -> amd::MemObjMap
    -> amd::Memory / amd::Buffer
      -> roc::Memory
        -> HSA allocation

4.1 roc::Memory 如何走到 HSA memory pool

amd::Buffer::create() 会为具体 device 创建后端 memory。ROCm 后端对应 roc::Memory::Buffer::create()

对于普通 device local memory,最终会走到:

cpp 复制代码
deviceMemory_ = dev().deviceLocalAlloc(size(), flags);

roc::Device::deviceLocalAlloc() 会选择一个 HSA memory pool:

cpp 复制代码
const hsa_amd_memory_pool_t& pool =
    flags.pseudo_fine_grain_ && gpu_ext_fine_grained_segment_.handle
        ? gpu_ext_fine_grained_segment_
    : flags.atomics_ && gpu_fine_grained_segment_.handle
        ? gpu_fine_grained_segment_
        : gpuvm_segment_;

然后调用 ROCr/HSA 扩展 API:

cpp 复制代码
hsa_status_t stat = Hsa::memory_pool_allocate(pool, size, hsa_mem_flags, &ptr);

Hsa::memory_pool_allocate() 是 ROCclr 对动态加载 ROCr 符号的包装,实际符号是:

text 复制代码
hsa_amd_memory_pool_allocate

因此 hipMalloc 的 device memory 主路径可以写成:

text 复制代码
hipMalloc
  -> ihipMalloc
  -> amd::SvmBuffer::malloc
  -> amd::Context::svmAlloc
  -> roc::Device::svmAlloc
  -> amd::Buffer::create
  -> roc::Memory::Buffer::create
  -> roc::Device::deviceLocalAlloc
  -> Hsa::memory_pool_allocate
  -> hsa_amd_memory_pool_allocate
  -> ROCr Runtime::AllocateMemory
  -> hsaKmtAllocMemory
  -> hsaKmtMapMemoryToGPUNodes
  -> KFD

5. amd::Memory 和内存对象登记

HIP API 对外暴露的是裸指针,但 runtime 必须知道这个指针对应的内存类型、大小、context、device、flags 等信息。这个信息由 amd::Memory 保存。

分配完成后,ROCm 后端会把内存对象登记到全局映射表:

cpp 复制代码
amd::MemObjMap::AddMemObj(mem->getSvmPtr(), mem);

后续很多 API 都会通过用户指针反查:

cpp 复制代码
amd::Memory* memObj = getMemoryObject(hip::getCurrentDevice(), ptr, offset);

这个设计解释了几个现象。

第一,hipFree(ptr) 不能直接释放裸指针,它必须先找到 amd::Memory

cpp 复制代码
ptr
  -> getMemoryObject
  -> amd::Memory
  -> 判断是否来自 memory pool / SVM / external memory
  -> 选择正确释放路径

第二,hipMemcpy 也需要查内存对象,因为它要判断 src/dst 是 host、device、managed、registered host memory,还是普通 CPU 指针。

第三,hipPointerGetAttributeshipMemRangeGetAttributehipMemAdvise 这类 API 本质上都是围绕这个 runtime metadata 工作。

所以 amd::Memory 是 HIP 指针式 API 和 ROCclr 对象式内存模型之间的桥:

text 复制代码
HIP 用户模型:void* ptr
ROCclr 内部模型:amd::Memory / roc::Memory
底层驱动模型:HSA allocation / SVM range / KFD BO

6. Managed Memory / SVM 路径

hipMallocManaged 不走普通 per-device context,而是使用 hip::host_context

cpp 复制代码
amd::Context& ctx = *hip::host_context;
const amd::Device& dev = *ctx.devices()[0];

*ptr = amd::SvmBuffer::malloc(ctx,
                              CL_MEM_SVM_FINE_GRAIN_BUFFER | CL_MEM_ALLOC_HOST_PTR,
                              size,
                              dev.info().memBaseAddrAlign_);

这里的关键点是:managed memory 需要表达"系统内存 / SVM / 多 GPU 可访问 / 可迁移"的语义,因此它使用包含所有可见 GPU 的 host_context,而不是某个 hip::Device 的单设备 context。

简化路径是:

text 复制代码
hipMallocManaged
  -> ihipMallocManaged
  -> hip::host_context
  -> amd::SvmBuffer::malloc
  -> amd::Context::svmAlloc
  -> roc::Device::svmAlloc
  -> amd::Buffer / roc::Memory
  -> HMM/SVM 初始化
  -> Hsa::svm_attributes_set
  -> hsa_amd_svm_attributes_set
  -> ROCr Runtime::SetSvmAttrib
  -> hsaKmtSVMSetAttr
  -> AMDKFD_IOC_SVM

在 HMM 支持路径下,ROCm 后端会对系统内存做 SVM 初始化:

cpp 复制代码
if (dev().info().hmmSupported_) {
  deviceMemory_ = dev().reserveMemory(size(), amd::Os::pageSize());
  dev().SvmAllocInit(deviceMemory_, size());
}

SvmAllocInit() 内部会调用:

text 复制代码
roc::Device::SetSvmAttributesInt(..., first_alloc = true)
  -> Hsa::svm_attributes_set
  -> hsa_amd_svm_attributes_set

这一步不是普通的 VRAM allocation,而是给一段 SVM/HMM 地址范围建立初始访问属性,例如让 GPU agent 可以访问这段系统内存。

6.1 hipMemAdvise

hipMemAdvise 不负责分配新内存,但它会修改已有 SVM range 的属性。它的核心路径是:

text 复制代码
hipMemAdvise / hipMemAdvise_v2
  -> ihipMemAdvise
  -> getMemoryObject
  -> amd::Device::SetSvmAttributes
  -> roc::Device::SetSvmAttributesInt
  -> Hsa::svm_attributes_set
  -> hsa_amd_svm_attributes_set
  -> ROCr Runtime::SetSvmAttrib
  -> hsaKmtSVMSetAttr
  -> AMDKFD_IOC_SVM

属性会经历几次翻译:

text 复制代码
hipMemoryAdvise
  -> amd::MemoryAdvice
  -> HSA_AMD_SVM_ATTRIB_*
  -> HSA_SVM_ATTR_* / HSA_SVM_FLAG_*
  -> KFD_IOCTL_SVM_ATTR_*

这条路径和 managed memory 关系很近,因为它操作的是同一类 SVM/HMM 地址范围。

6.2 hipMemPrefetchAsync

hipMemPrefetchAsync 也不分配新内存,但它会触发 managed/SVM range 向目标位置迁移或建立目标访问倾向。

简化路径是:

text 复制代码
hipMemPrefetchAsync
  -> ihipMemPrefetchAsync
  -> getMemoryObject
  -> 解析目标 location / CPU 或 GPU agent
  -> ROCclr command 或 ROCr SVM prefetch/attribute 路径
  -> hsa_amd_svm_prefetch_async 或 hsaKmtSVMSetAttr(prefetch loc)
  -> KFD SVM range 迁移 / 预取

不同 ROCm 版本和 HMM 配置下,prefetch 可能表现为显式 prefetch API,也可能体现为 SVM 属性更新和迁移请求。调试时要同时关注 ROCr 的 hsa_amd_svm_prefetch_async 和 libhsakmt 的 hsaKmtSVMSetAttr

7. Host Memory 路径:hipHostMalloc / hipHostRegister

hipHostMalloc 最终也是调用 ihipMalloc(),但会传入 fine-grain / atomics / NUMA / uncached 等 flags:

cpp 复制代码
unsigned int ihipFlags = CL_MEM_SVM_FINE_GRAIN_BUFFER;

if (flags & hipHostMallocUncached) {
  ihipFlags |= ROCCLR_MEM_HSA_UNCACHED;
}

if (flags == 0 || flags & hipHostMallocMapped || HIP_HOST_COHERENT) {
  ihipFlags |= CL_MEM_SVM_ATOMICS;
}

if (flags & hipHostMallocNumaUser) {
  ihipFlags |= CL_MEM_FOLLOW_USER_NUMA_POLICY;
}

hipError_t status = ihipMalloc(ptr, sizeBytes, ihipFlags);

因为带有 CL_MEM_SVM_FINE_GRAIN_BUFFERihipMalloc() 会选择:

cpp 复制代码
amd::Context* amdContext = hip::host_context;

所以 hipHostMalloc 的核心路径是:

text 复制代码
hipHostMalloc
  -> ihipHostMalloc
  -> ihipMalloc(..., CL_MEM_SVM_FINE_GRAIN_BUFFER | ...)
  -> hip::host_context
  -> amd::SvmBuffer::malloc
  -> amd::Context::svmAlloc
  -> roc::Device::svmAlloc
  -> roc::Memory::Buffer::create
  -> hostAlloc / HMM reserve / SVM init
  -> ROCr/libhsakmt/KFD

hipHostRegister 的语义不同:它不是分配一块新 host memory,而是把用户已有的 host pointer 注册成 GPU 可访问。它通常会涉及:

text 复制代码
用户已有 host pointer
  -> HIP runtime 创建/登记 memory object
  -> ROCclr/ROCm 后端 lock/register host memory
  -> ROCr HSA memory_register / memory_lock / SVM attributes
  -> libhsakmt pin/map userptr
  -> KFD 建立 GPU 可访问映射

因此,hipHostMalloc 更像"runtime 分配 pinned/SVM host memory",hipHostRegister 更像"把已有 CPU 地址范围纳入 GPU 可访问管理"。

8. Free 路径:hipFree

hipFree 的关键不是直接释放 ptr,而是先通过 ptr 找到 runtime 内部的 amd::Memory

cpp 复制代码
hipError_t ihipFree(void* ptr) {
  if (ptr == nullptr) {
    return hipSuccess;
  }

  amd::Memory* memory_object = getMemoryObject(hip::getCurrentDevice(), ptr, offset);
  if (memory_object != nullptr) {
    auto device_id = memory_object->getUserData().deviceId;

    if (!g_devices[device_id]->FreeMemory(memory_object, nullptr)) {
      g_devices[device_id]->SyncAllStreams();

      if (memory_object->getSvmPtr() == nullptr) {
        amd::MemObjMap::RemoveMemObj(ptr);
        memory_object->release();
      } else {
        amd::SvmBuffer::free(memory_object->getContext(), ptr);
      }
    }
    return hipSuccess;
  }
  return hipErrorInvalidValue;
}

释放路径大致是:

text 复制代码
hipFree
  -> ihipFree
  -> getMemoryObject
  -> 判断是否属于 HIP memory pool
  -> 必要时同步相关 stream
  -> amd::SvmBuffer::free / amd::Memory::release
  -> amd::Context::svmFree
  -> roc::Device / roc::Memory free
  -> hsa_amd_memory_pool_free / hsa_memory_free
  -> hsaKmtFreeMemory
  -> KFD

这里要注意,释放时使用的是 allocation 时记录在 memObj->getUserData().deviceId 里的 device,而不是简单使用当前线程 current device。这是为了避免用户切换 device 后释放指针时找错设备上下文。

9. Copy / Prefetch 为什么也依赖内存对象

hipMemcpy 本身不是分配接口,但它强依赖内存对象表。原因是 hipMemcpyDefault、managed memory、host registered memory、device pointer 都要通过 runtime metadata 判断。

典型逻辑是:

text 复制代码
hipMemcpyAsync
  -> 解析 stream
  -> getMemoryObjectPairs(src, dst)
  -> 判断 src/dst 分别是什么内存
  -> 创建 ROCclr copy command
  -> 提交到 hip::Stream / amd::HostQueue
  -> ROCm 后端生成 SDMA 或 kernel/blit 命令

也就是说,分配阶段建立的 ptr -> amd::Memory 映射,会直接影响后续 copy 路径:

text 复制代码
hipMalloc / hipHostMalloc / hipMallocManaged
  -> MemObjMap 登记
  -> hipMemcpy / hipFree / hipMemAdvise / hipPointerGetAttributes 反查

hipMemPrefetchAsync 更接近 managed memory 的控制路径:它先通过 getMemoryObject 找到 SVM allocation,再根据目标 location 决定是迁移到 GPU、迁移到 CPU,还是设置 NUMA/agent 相关属性。

10. 到 libhsakmt 的边界在哪里

这一节重点看 ROCr Runtime 进入 libhsakmt 的边界:上层已经完成 HIP/ROCclr 对象转换之后,底层会根据内存类型进入 allocation/map/free 或 SVM attribute 路径。

不同 HIP 语义到 libhsakmt 的落点大致如下:

HIP 语义 ROCclr/ROCr 落点 libhsakmt/KFD 可能涉及
hipMalloc device memory hsa_amd_memory_pool_allocate hsaKmtAllocMemoryhsaKmtMapMemoryToGPUNodes
hipFree hsa_amd_memory_pool_free / hsa_memory_free hsaKmtFreeMemory
hipMallocManaged SVM/HMM allocation + hsa_amd_svm_attributes_set hsaKmtSVMSetAttrAMDKFD_IOC_SVM
hipHostMalloc fine-grain/SVM host allocation hsaKmtAllocMemory、map/pin、SVM attributes
hipHostRegister host memory register/lock userptr pin/map、GPU mapping
hipMemAdvise hsa_amd_svm_attributes_set hsaKmtSVMSetAttr
hipMemPrefetchAsync SVM prefetch / prefetch location attribute hsaKmtSVMSetAttr 或 prefetch ioctl 相关路径

以 device memory 为例,ROCr 的 hsa_amd_memory_pool_allocate() 最终调用:

cpp 复制代码
core::Runtime::AllocateMemory
  -> hsaKmtAllocMemory
  -> hsaKmtMapMemoryToGPUNodes

libhsakmt 的 memory path 会进入:

c 复制代码
libhsakmt/src/memory.c
  -> hsaKmtAllocMemoryCtx
  -> hsaKmtAllocMemoryAlignCtx
  -> ioctl(KFD allocation/map memory path)

以 SVM 属性为例,ROCr 的 hsa_amd_svm_attributes_set() 最终调用:

cpp 复制代码
core::Runtime::SetSvmAttrib
  -> hsaKmtSVMSetAttr
  -> libhsakmt/src/svm.c
  -> hsakmt_ioctl(AMDKFD_IOC_SVM)

所以如果目标是观察"HIP 内存 API 什么时候到 libhsakmt",断点不应该只打在 HIP 层,还要打在 ROCr 和 libhsakmt 边界。

11. 调试建议

可以按层级设置断点。

HIP 层:

text 复制代码
hipMalloc
hipFree
hipHostMalloc
hipMallocManaged
hipMemAdvise
hipMemPrefetchAsync
ihipMalloc
ihipFree
ihipHostMalloc
ihipMallocManaged
ihipMemAdvise
ihipMemPrefetchAsync
getMemoryObject
getMemoryObjectPairs

ROCclr 层:

text 复制代码
amd::SvmBuffer::malloc
amd::SvmBuffer::free
amd::Context::svmAlloc
amd::Context::svmFree
amd::Buffer::create
amd::MemObjMap::AddMemObj
amd::MemObjMap::FindMemObj
roc::Device::svmAlloc
roc::Device::deviceLocalAlloc
roc::Device::hostAlloc
roc::Device::SetSvmAttributes
roc::Device::SetSvmAttributesInt
roc::Device::SvmAllocInit
roc::Memory::Buffer::create

ROCr 层:

text 复制代码
hsa_amd_memory_pool_allocate
hsa_amd_memory_pool_free
hsa_amd_svm_attributes_set
hsa_amd_svm_attributes_get
hsa_amd_svm_prefetch_async
core::Runtime::AllocateMemory
core::Runtime::SetSvmAttrib

libhsakmt 层:

text 复制代码
hsaKmtAllocMemory
hsaKmtAllocMemoryAlign
hsaKmtMapMemoryToGPU
hsaKmtMapMemoryToGPUNodes
hsaKmtFreeMemory
hsaKmtSVMSetAttr
hsaKmtSVMGetAttr
hsakmt_ioctl

如果只想看 hipMalloc 主路径,推荐第一轮断点是:

text 复制代码
hipMalloc
  -> ihipMalloc
  -> amd::SvmBuffer::malloc
  -> roc::Device::svmAlloc
  -> roc::Memory::Buffer::create
  -> roc::Device::deviceLocalAlloc
  -> hsa_amd_memory_pool_allocate
  -> core::Runtime::AllocateMemory
  -> hsaKmtAllocMemory
  -> hsaKmtMapMemoryToGPUNodes

如果只想看 managed/SVM 路径,推荐第一轮断点是:

text 复制代码
hipMallocManaged
  -> ihipMallocManaged
  -> amd::SvmBuffer::malloc
  -> roc::Device::svmAlloc
  -> roc::Device::SvmAllocInit
  -> roc::Device::SetSvmAttributesInt
  -> hsa_amd_svm_attributes_set
  -> core::Runtime::SetSvmAttrib
  -> hsaKmtSVMSetAttr
  -> hsakmt_ioctl(AMDKFD_IOC_SVM)

12. 总结

HIP 内存分配接口到 libhsakmt 的链路可以压缩成一张图:

text 复制代码
HIP API
  -> HIP runtime object model
  -> ROCclr context/device/memory model
  -> ROCm backend roc::Device / roc::Memory
  -> ROCr HSA memory/SVM API
  -> libhsakmt thunk
  -> KFD ioctl

其中最重要的是两个对象桥接:

text 复制代码
hip::Device
  -> amd::Context
    -> amd::Device / roc::Device

和:

text 复制代码
void* ptr
  -> amd::MemObjMap
    -> amd::Memory / roc::Memory

前者决定"这次分配属于哪个 device/context",后者决定"后续拿着这个裸指针还能不能找回 runtime 内部的内存对象"。

所以,hipMalloc 到 libhsakmt 不是一条简单的函数转发链,而是一条分层资源建模链:

  1. HIP 层提供 CUDA-like 指针 API。
  2. ROCclr 层创建 context-scoped memory object。
  3. ROCm 后端选择 HSA memory pool 或 SVM/HMM 路径。
  4. ROCr Runtime 翻译成底层 allocation / map / SVM attribute 操作。
  5. libhsakmt 把这些操作提交给 KFD。

理解这条链路后,再看 hipFreehipMemcpyhipMemAdvisehipMemPrefetchAsync 就会顺很多:它们都是围绕同一个 amd::Memory 元数据和同一组 ROCr/libhsakmt 底层能力展开。

相关推荐
DeeplyMind2 个月前
ROCm rocr-libhsakmt分析系列5-1: Event 机制全景—从 Doorbell 到 Signal
libhsakmt·rocr-runtime·hsa event
DeeplyMind2 个月前
Rocm rocr-libhsakmt Event 机制技术文章预告
libhsakmt·rocr-runtime·hsa event
DeeplyMind5 个月前
ROCm rocr-libhsakmt分析系列4: HsaMemFlags分析
rocm·rocr·libhsakmt·hsamemflags
DeeplyMind9 个月前
rocr专栏介绍
linux·ai·amdgpu·rocm·rocr·libhsakmt·thunk