ROCm HIP:amd::Context 源码剖析,以及 device context 与 host context 的区别
本文基于 AMD ROCm 开源栈rocm-systems/projects/clr的源码剖析 ROCclr 运行时中核心对象amd::Context的设计与职责并结合 HIP 运行时hipamd说明两种典型上下文——per-deviceprimarycontext与host context——的差异。适合想深入理解 ROCm/HIP 内存管理与设备抽象的读者。目录1、背景ROCclr 在 ROCm 栈中的位置2、amd::Context是什么3、核心职责逐条拆解3.1 设备集合管理与引用计数3.2 主机内存分配 hostAlloc / hostFree3.3 SVM 分配 svmAlloc / svmFree3.4 互操作与属性4、device context vs host context4.1 device context单设备的 primary context4.2 host context跨全部设备的全局上下文4.3 对照表5、调用链6、总结1、背景ROCclr 在 ROCm 栈中的位置ROCm 的用户态运行时大致分层如下HIP API (hipamd) - 用户直接调用的 hipMalloc / hipLaunchKernel 等 | ROCclr (rocclr) - Common Language Runtime设备抽象、内存对象、命令队列 | ROCr / HSA runtime - 硬件抽象层直接和 KFD/驱动打交道 | amdgpu / KFD (内核态)amd::Context属于ROCclr 层是连接“上层 API 语义”和“下层设备资源”的关键枢纽对象。无论是 OpenCL 的cl_context还是 HIP 的设备上下文最终都落到这个类上。2、amd::Context是什么打开头文件rocclr/platform/context.hpp类定义的第一行就点明了它的身份classContext:publicRuntimeObject{std::vectorDevice*devices_;// ...};RuntimeObject继承自ReferenceCountedObject和ICDDispatchedObject这意味着Context是引用计数对象通过retain()/release()管理生命周期而非裸delete是可被 OpenCL ICD 分发的对象可以在cl_context和内部对象之间安全转换。一句话概括它的本质Context就是“一组Device*的聚合”同时是这组设备之上一切内存分配与资源生命周期的“归属域ownership domain”。值得强调的是Context类本身并不区分“host”还是“device”。所谓 host context / device context 的差异完全取决于构造它时传入了哪些设备。这是理解本文后半部分的关键。3、核心职责逐条拆解下面结合实现文件rocclr/platform/context.cpp逐条分析。3.1 设备集合管理与引用计数构造函数遍历传入的设备列表对每个设备retain()并在此过程中筛选出两类“特殊设备”Context::Context(conststd::vectorDevice*devices,constInfoinfo):devices_(devices),info_(info),properties_(NULL),glenv_(NULL),customHostAllocDevice_(NULL){for(constautodevice:devices){device-retain();// 1) 第一个具备“自定义 host 分配器”的设备if(customHostAllocDevice_NULLdevice-customHostAllocator()){customHostAllocDevice_device;}// 2) 所有支持 SVM 的设备if(device-svmSupport()){svmAllocDevice_.push_back(device);}}// 多设备场景下把“细粒度系统不支持”的设备排到最前优先在它上面分配if(svmAllocDevice_.size()1){uint isFirstDeviceFGSEnabledsvmAllocDevice_.front()-isFineGrainedSystem(true);for(autodev:svmAllocDevice_){if(isFirstDeviceFGSEnabled!dev-isFineGrainedSystem(true)){std::swap(svmAllocDevice_.front(),dev);break;}}}}析构函数则做对称的清理解绑 D3D/GL interop、通知设备ContextDestroy()、逐个release()设备。Context因此成为设备生命周期的持有者。3.2 主机内存分配 hostAlloc / hostFreeContext提供统一的主机内存分配入口。它优先使用设备提供的“自定义 host 分配器”通常是 pinned / page-locked 内存DMA 更快否则退回普通对齐分配void*Context::hostAlloc(size_t size,size_t alignment,boolatomics)const{if(customHostAllocDevice_!NULL){returncustomHostAllocDevice_-hostAlloc(size,alignment,atomics?Device::MemorySegment::kAtomics:Device::MemorySegment::kNoAtomics);}returnAlignedMemory::allocate(size,alignment);}voidContext::hostFree(void*ptr)const{if(customHostAllocDevice_!NULL){customHostAllocDevice_-hostFree(ptr);return;}AlignedMemory::deallocate(ptr);}3.3 SVM 分配 svmAlloc / svmFreeSVMShared Virtual Memory共享虚拟内存是让 CPU 和多个 GPU 使用同一虚拟地址访问同一块内存的机制。Context的svmAlloc会在所有支持 SVM 的设备上把同一地址映射一遍void*Context::svmAlloc(size_t size,size_t alignment,cl_svm_mem_flags flags,constamd::Device*curDev,void*svmPtr){unsignedintnumSVMDevsvmAllocDevice_.size();if(numSVMDev1){returnnullptr;}void*svmPtrAllocedsvmPtr;amd::ScopedLocklock(ctxLock_);// 优先在“当前设备”上分配if(curDev!nullptr){if(!(flagsCL_MEM_SVM_ATOMICS)||(curDev-info().svmCapabilities_CL_DEVICE_SVM_ATOMICS)){svmPtrAllocedcurDev-svmAlloc(*this,size,alignment,flags,svmPtrAlloced);if(svmPtrAllocednullptr)returnnullptr;}}// 再在其余支持 SVM 的设备上映射同一地址for(constautodev:svmAllocDevice_){if(devcurDev)continue;if((flagsCL_MEM_SVM_ATOMICS)!(dev-info().svmCapabilities_CL_DEVICE_SVM_ATOMICS)){continue;// 该设备不支持平台原子跳过}svmPtrAlloceddev-svmAlloc(*this,size,alignment,flags,svmPtrAlloced);if(svmPtrAllocednullptr)returnnullptr;}returnsvmPtrAlloced;}svmFree中还有一处值得注意的多 GPU 竞态防护先原子地从全局映射表移除该内存对象再逐设备释放 GPU 虚拟地址最后才真正release()避免并发分配复用同一 VA 时被错误释放voidContext::svmFree(void*ptr)const{amd::ScopedLocklock(ctxLock_);amd::Memory*svmMemamd::MemObjMap::FindAndRemoveMemObj(ptr);if(svmMem!nullptr!svmAllocDevice_.empty()){svmAllocDevice_.front()-SetSvmAttributes(ptr,svmMem-getSize(),amd::MemoryAdvice::ResetAttributes);}for(constautodev:svmAllocDevice_){dev-svmFree(ptr);}if(svmMem!nullptr){svmMem-release();}}3.4 互操作与属性除了内存分配Context还保存了Info info_D3D10/D3D11/GL 等 interop 标志与句柄cl_context_properties* properties_原始属性GLFunctions* glenv_OpenGL 上下文Monitor ctxLock_对上下文串行化访问的锁Windows 平台上的 D3D10/D3D11 扩展缓存。4、device context vs host context明确了Context的本质后来看代码库里两种典型的实例。它们复用同一个amd::Context类差别仅在于构造时传入的设备列表。4.1 device context单设备的 primary context在每个 ROCm 设备初始化时rocclr/device/rocm/rocdevice.cpp会为该设备单独创建一个 Context源码注释直接写着 “dummy context”amd::Context::Info info{0};std::vectoramd::Device*devices{this};// 注意只有 this 一个设备// Create a dummy contextcontext_newamd::Context(devices,info);这个 Context 存放在amd::Device::context_中通过amd::Device::context()暴露。到了 HIP 层hip::Device直接复用它而不是新建// hipamd/src/hip_context.cpp init()for(size_t i0;idevice_count;i){amd::Device*constamd_devicedevices[i];amd_device-SetActiveWait(true);// 复用 amd::Device 里已有的“永生”上下文auto*devicenewDevice(amd_device-context(),static_castunsignedint(i));// ...}hip::Device通过asContext()返回这个单设备上下文它就相当于 CUDA 里每个设备的primary context// hipamd/src/hip_internal.hppclassDevice:publicamd::ReferenceCountedObject{amd::Context*asContext()const{returncontext_;}// ...amd::Context*context_;//! ROCclr context单设备};由于它的devices_里只有 1 个设备所有基于它的 buffer、内核、命令队列、内存分配都绑定到这一个 GPU。4.2 host context跨全部设备的全局上下文在 HIP 初始化的末尾hip_context.cpp又创建了一个覆盖全部 GPU的全局上下文host_context// hipamd/src/hip_context.cppamd::Context*host_contextnullptr;// 全局变量voidinit(bool*status){// ... 枚举全部 GPU 到 devices ...// Create and initialize host contexthost_contextnewamd::Context(devices,amd::Context::Info());// 传入全部设备if(!host_context||CL_SUCCESS!host_context-create(nullptr)){// ...}amd::RuntimeTearDown::RegisterObject(host_context);}它的用途是处理不绑定到具体设备的分配最典型的是纯 SVM / 系统内存可访问的分配。getNullStream()对此有专门判断——当传入的 ctx 是host_context时选哪个设备的 null stream 都无所谓hip::Stream*getNullStream(amd::Contextctx,boolwait){for(constautoit:g_devices){if(it-asContext()ctx){// 命中某个 device contextreturnit-NullStream(wait);}}// 纯 SVM / 系统内存访问用哪个设备默认流都行if(hip::host_contextctx){returngetNullStream(wait);// 回退到当前设备}returnnullptr;}因为它的devices_含全部 GPUsvmAlloc()会在每个设备上都映射同一地址从而实现跨设备统一寻址。补充ROCclr 内部还有一个类似性质的glb_ctx_见rocdevice.cpp同样覆盖全部设备专供 P2P staging 等驱动内部分配使用属于更底层的“全设备上下文”。4.3 对照表维度device contextprimaryhost context创建位置rocclr/device/rocm/rocdevice.cppcontext_ new amd::Context(...)hipamd/src/hip_context.cpphost_context new amd::Context(...)devices_内容单个设备this全部 GPU归属层ROCclramd::Device拥有HIP 全局单例典型用途该设备上的 buffer / 内核 / 队列per-device 分配跨设备 SVM / 系统内存、与设备无关的分配SVM 行为只在 1 个设备上映射在所有设备上映射同一 VAHIP 暴露方式hip::Device::asContext()全局hip::host_context语义类比CUDA 的 device primary context一个“与具体设备无关”的兜底上下文5、调用链HIP 层 (hipamd)ROCclr 层拥有asContext 复用devices_ 1 个 GPUdevices_ 全部 GPUamd::Devicedevice contextamd::Context(devices{this})单设备glb_ctx_amd::Context(全部设备)驱动内部 P2Phip::Devicehost_contextamd::Context(全部设备)全局单例per-device 分配绑定单个 GPUSVM / 系统内存跨设备统一寻址6、总结amd::Context是 ROCclr 中引用计数的“设备集合 分配归属域”统一承载 host 内存分配、SVM 分配、interop 属性与资源生命周期。它本身不区分host / device差异完全来自构造时传入的设备列表范围。device context只含单个 GPU是每个设备的 primary contextHIP 通过hip::Device::asContext()复用per-device 的 buffer、内核、分配都落在这一个设备上。host context覆盖全部 GPU是 HIP 的全局单例专门服务跨设备 SVM / 与具体设备无关的主机侧分配。二者共用同一套svmAlloc逻辑但因设备列表不同一个只映射单卡地址一个在所有卡上映射同一 VA从而支撑起 ROCm 的统一虚拟内存模型。理解这两类 Context 的分工是读懂 HIP 内存管理hipMalloc/hipMallocManaged/ SVM与多 GPU 寻址的基础。

相关新闻

MSP430BT5190外设深度解析:从寄存器到低功耗系统设计实战

MSP430BT5190外设深度解析:从寄存器到低功耗系统设计实战

1. 项目概述:为什么我们需要深入理解MCU外设?在嵌入式开发这条路上摸爬滚打了十几年,我见过太多项目卡在“知其然,不知其所以然”的瓶颈上。很多工程师,尤其是刚入行的朋友,拿到一块像MSP430BT5190这样的微…

2026/9/29 5:06:17 阅读更多 →
从芯片到系统:ADS8353/7853评估板实战指南与高精度ADC设计要点

从芯片到系统:ADS8353/7853评估板实战指南与高精度ADC设计要点

1. 项目概述:从芯片到系统,如何用好一块ADC评估板在嵌入式系统、精密测量或者工业控制领域,但凡涉及到将现实世界的物理量(比如温度、压力、振动)转换成数字信号进行处理,模数转换器(ADC&#x…

2026/10/13 4:16:33 阅读更多 →
如何用qmcdump一键解密QQ音乐加密音频:终极免费工具完整指南

如何用qmcdump一键解密QQ音乐加密音频:终极免费工具完整指南

如何用qmcdump一键解密QQ音乐加密音频:终极免费工具完整指南 【免费下载链接】qmcdump 一个简单的QQ音乐解码(qmcflac/qmc0/qmc3 转 flac/mp3),仅为个人学习参考用。 项目地址: https://gitcode.com/gh_mirrors/qm/qmcdump …

2026/10/13 14:57:26 阅读更多 →

最新新闻

AnyPS5跨平台图像处理管线:色彩管理与批量处理实战避坑指南

AnyPS5跨平台图像处理管线:色彩管理与批量处理实战避坑指南

1. 项目缘起与核心定位AnyPS5 这个名字第一次出现在我视野里的时候,我正被一堆跨平台图像处理的需求折腾得够呛。团队里有人用 Windows 做设计,有人用 macOS 做后期,还有几个同事习惯在 Linux 环境下跑批处理脚本,每次交付素材都要…

2026/10/14 4:26:51 阅读更多 →
GridView + AJAX 效果实战:Web Forms老项目异步升级指南

GridView + AJAX 效果实战:Web Forms老项目异步升级指南

简介:这是一份专门面向ASP.NET开发者的GridView实用实例,旨在解决Visual Studio自带GridView在数据增删改操作与交互体验上的明显短板。资源基于ASP.NET 4.0与SQL Server 2008环境,实现了完整的无刷新Ajax增删改功能,代码量少、结…

2026/10/14 4:26:51 阅读更多 →
Flutter迁移开源鸿蒙实战:逆向匹配算法设计与踩坑记录

Flutter迁移开源鸿蒙实战:逆向匹配算法设计与踩坑记录

从拿到这个标题到真正把App跑在开源鸿蒙设备上,中间隔了整整两个周末的调试时间。这篇东西不是教程式的堆砌,而是把我做“flutter_for_openharmony逆向思维训练app实战逆向匹配实现”这个项目时踩过的坑、想通的原理、反复验证过的代码逻辑,全…

2026/10/14 4:26:51 阅读更多 →
开源八卦怎么吃?从项目细节中读出真实信号

开源八卦怎么吃?从项目细节中读出真实信号

我最初入行写代码那几年,对“开源”的理解很单纯:一堆互相不认识的人,在某个仓库里合写代码,因为共同的兴趣走到一起。直到后来亲历了几场“项目圈内事件”,才意识到开源世界里的“八卦”根本不是茶余饭后的消遣——它…

2026/10/14 4:26:51 阅读更多 →
范畴论入门必刷:Algebra Chapter 0集合练习题复盘与映射思维训练

范畴论入门必刷:Algebra Chapter 0集合练习题复盘与映射思维训练

1. 为什么“集合练习题”值得单独拎出来做一篇复盘很多人看到“Algebra: Chapter 0”这个书名,第一反应是“范畴论入门”,然后翻两页就被各种交换图劝退。但真正卡住新手的往往不是后面的泛函、自然变换,而是第0章里那些看起来人畜无害的集合…

2026/10/14 4:26:51 阅读更多 →
考研数据结构复试高频考点、手写代码与面试应对策略

考研数据结构复试高频考点、手写代码与面试应对策略

初试成绩出来之后,很多同学会陷入一种“不知道该干什么”的状态。刷题吧,好像复试不考这么细;看论文吧,又不知道从哪看起;真要准备机试,又发现手生的厉害。我自己当年备考“考研数据结构复试题目整理”的时…

2026/10/14 4:25:51 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →