news 2026/5/26 16:34:32

11.1 KFD Context 的设计动机:从单进程单上下文到多上下文隔离

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
11.1 KFD Context 的设计动机:从单进程单上下文到多上下文隔离

摘要:libhsakmt 最初的设计是"一个进程 = 一个 KFD 上下文"。全局变量hsakmt_primary_kfd_ctx持有进程唯一的/dev/kfd文件描述符,所有线程共享同一份拓扑、内存、队列、事件状态。这个模型简单高效,但无法满足多租户 / 容器化 / 调试器隔离等新兴需求。本篇分析 KFD Context 机制的引入动机、数据结构设计以及新旧 API 的衔接策略。


1. 原始模型:单进程单上下文

在 1.1 篇中我们已经详细分析过,hsaKmtOpenKFDCtx()/dev/kfd只执行一次open()调用,后续所有请求都通过引用计数返回同一个全局上下文:

// openclose.cHsaKFDContext hsakmt_primary_kfd_ctx={.fd=-1,.hsakmt_is_primary_ctx=true,.hsakmt_is_svm_api_supported=false,};

这个全局变量就是整个进程的 GPU “身份证”。所有 ioctl 都通过hsakmt_primary_kfd_ctx.fd发往内核,所有子系统(拓扑、内存、队列、事件、调试、性能计数器)的状态都挂在这个结构体下。

在这个模型中,进程 = KFD 上下文 = 内核侧kfd_process,三者是一一对应的。这也是 KFD 内核驱动长期以来的假设 —— 它以pid为粒度管理 GPU 资源:每个进程拥有独立的 GPU 虚拟地址空间(GPUVM)、页表、队列和事件。

这个设计干净利落,但有一个根本限制:同一个进程内无法拥有多个相互隔离的 GPU 资源域


2. 为什么需要多上下文

2.1 容器化与多租户 GPU 共享

在云计算和容器化场景中,多个"租户"(容器 / 虚拟机 / 用户进程)可能通过同一个宿主进程间接访问 GPU。例如,一个 GPU 虚拟化代理进程需要同时为多个容器提供隔离的 GPU 服务。如果 libhsakmt 只有一个全局上下文,所有容器的 GPU 资源就混在一起 —— 队列共享、内存可互相访问、事件可互相干扰。这显然不能满足隔离需求。

2.2 调试器隔离

GPU 调试器(如 ROCgdb)需要在不干扰目标进程正常 GPU 操作的前提下,建立自己的 KFD 通信通道来设置断点、检查队列状态、读取 GPU 内存。如果调试器和被调试程序共享同一个上下文,调试操作与计算操作之间的状态干扰将难以避免。

2.3 DRM 层面的 VM 隔离

当一个进程内的多个"应用"需要独立的 GPU 虚拟地址空间时,每个应用需要自己的 DRM file handle。这在 GPU 虚拟化(VirtIO-GPU)场景中尤为关键 —— 宿主侧的代理进程需要为每个 Guest 维护独立的 VM 空间,以实现 Guest 之间的地址空间隔离和隐式同步。


3. HsaKFDContext:上下文数据结构

为了支持多上下文,AMD 工程师引入了HsaKFDContext结构体,将原本散落在全局变量中的所有子系统状态收归其下:

// kfdcontext.htypedefstruct_HsaKFDContext{intfd;// KFD 文件描述符bool hsakmt_is_primary_ctx;// 是否为 Primary 上下文bool hsakmt_is_svm_api_supported;// SVM API 支持标志structhsa_kfd_topology_context*topology_context;// 拓扑信息structhsa_kfd_queue_context*queue_context;// 队列资源structhsa_kfd_fmm_context*fmm_context;// 内存管理(FMM)structhsa_kfd_event_context*event_context;// 事件structhsa_kfd_debug_context*debug_context;// 调试structhsa_kfd_perf_context*perf_context;// 性能计数器}HsaKFDContext;

这是一个典型的聚合根设计 ——HsaKFDContext本身只持有文件描述符和几个标志位,实际的资源状态通过六个指针分别指向各子系统的上下文结构。

每个子上下文都是按需分配的。以 FMM 上下文为例:

// fmm.cstructhsa_kfd_fmm_context{gpu_mem_t*gpu_mem;// 每个 GPU 节点的内存 apertureunsignedintgpu_mem_count;gpu_mem_t*first_gpu_mem;uint32_tall_gpu_id_array_size;uint32_t*all_gpu_id_array;void*dgpu_shared_aperture_base;// dGPU 共享 aperture 基址void*dgpu_shared_aperture_limit;svm_tsvm;// SVM 管理manageable_aperture_tcpuvm_aperture;// CPU VM aperturemanageable_aperture_tmem_handle_aperture;intdrm_render_fds[128];// DRM render 节点 fdstructamdgpu_device*amdgpu_handle[128];// AMDGPU 设备句柄};

这意味着每个HsaKFDContext拥有自己独立的 GPU 内存视图、DRM 设备句柄和 aperture 地址空间 —— 不同上下文之间的内存分配互不可见。

头文件中的注释明确了隔离原则:

Multiple HsaKFDContext instances can coexist simultaneously, each maintaining its own independent set of resources. These contexts are fully isolated from one another and must not have their resources mixed. If resources need to be shared between contexts, they must be explicitly exported and imported using the appropriate APIs.

多个上下文可以同时存在,各自维护独立的资源集。上下文之间完全隔离,资源不得混用。如需跨上下文共享,必须通过显式的导出/导入 API。


4. Primary vs Secondary:两种上下文类型

4.1 Primary Context

Primary Context 就是原来的全局上下文,由hsaKmtOpenKFDCtx()创建,全进程唯一:

// openclose.c — hsaKmtOpenKFDCtx()if(hsakmt_kfd_open_count==0){fd=open(kfd_device_name,O_RDWR|O_CLOEXEC);hsakmt_kfdcontext_init_context(fd,&hsakmt_primary_kfd_ctx);hsakmt_kfd_open_count=1;*pCtx=&hsakmt_primary_kfd_ctx;}

它的特点:

  • 全局静态分配,生命周期与进程相同
  • 引用计数管理,支持多次 Open/Close
  • 支持 SVM、调试等全部功能
  • DRM 设备初始化使用amdgpu_device_initialize()(启用设备去重)

4.2 Secondary Context

Secondary Context 由hsaKmtOpenSecondaryKFDCtx()创建,可以有多个:

// openclose.c — hsaKmtOpenSecondaryKFDCtx()kfd_fd=open(kfd_device_name,O_RDWR|O_CLOEXEC);// 新的 fdstructkfd_ioctl_create_process_argsargs={};hsakmt_ioctl(kfd_fd,AMDKFD_IOC_CREATE_PROCESS,&args);// 内核侧创建新进程上下文new_ctx=calloc(1,sizeof(HsaKFDContext));hsakmt_kfdcontext_init_context(kfd_fd,new_ctx);new_ctx->hsakmt_is_primary_ctx=false;new_ctx->hsakmt_is_svm_api_supported=false;*pCtx=new_ctx;

关键区别在三处:

① 独立的文件描述符。每个 Secondary Context 都会执行一次open("/dev/kfd"),获得自己的 fd。加上AMDKFD_IOC_CREATE_PROCESSioctl,内核侧会为这个 fd 建立独立的进程上下文。

② 独立的 DRM VM 空间。初始化 DRM 设备时使用amdgpu_device_initialize2(fd, false, ...),第二个参数false禁用设备去重,使得每个上下文获得自己的 DRM file handle 和独立的 GPU 虚拟地址空间:

// fmm.c — 初始化 DRM 设备if(ctx->hsakmt_is_primary_ctx)dev_init_ret=amdgpu_device_initialize(fd,...);elseif(hsakmt_fn_amdgpu_device_initialize2)dev_init_ret=hsakmt_fn_amdgpu_device_initialize2(fd,false,...);

③ 功能限制。Secondary Context 不支持调试操作和 userptr 映射:
这个可能是暂时的,后面有可能被支持。实现与primay context一样的效果。

// debug.c — 调试接口拒绝 Secondary Contextif(!ctx->hsakmt_is_primary_ctx)returnHSAKMT_STATUS_NOT_SUPPORTED;// fmm.c — Secondary 禁用 userptrif(!ctx->hsakmt_is_primary_ctx)fmm_ctx->svm.userptr_for_paged_mem=false;

4.3 生命周期对比

维度Primary ContextSecondary Context
创建hsaKmtOpenKFDCtx()hsaKmtOpenSecondaryKFDCtx()
数量全进程唯一可创建多个
存储全局静态变量calloc动态分配
引用计数有(hsakmt_kfd_open_count
fd 关闭进程退出或 fork 后清理hsaKmtCloseSecondaryKFDCtx()显式关闭
DRM 初始化amdgpu_device_initializeamdgpu_device_initialize2(fd, false)
调试支持完整支持不支持
SVM / userptr支持禁用

销毁 Secondary Context 时,资源清理更加彻底 —— 因为没有引用计数保护,关闭即意味着完全释放:

// openclose.c — hsaKmtCloseSecondaryKFDCtx()hsakmt_clear_events_page(ctx);hsakmt_destroy_counter_props(ctx);hsakmt_destroy_device_debugging_memory(ctx);hsakmt_fmm_clear_all_aperture(ctx);close(ctx->fd);// 关闭 fd → 内核侧释放进程上下文hsakmt_kfdcontext_clear_context(ctx);// 释放六个子上下文free(ctx);// 释放结构体本身

5. 新旧 API 的衔接:Ctx 后缀模式

引入多上下文后,每个操作都需要知道"在哪个上下文上执行"。但 libhsakmt 已有大量不带上下文参数的遗留 API,不能破坏兼容性。

解决方案是双层 API 设计

┌──────────────────────────────────┐ │ hsakmt.h(遗留 API,无上下文参数)│ ← 上层调用者使用 ├──────────────────────────────────┤ │ hsakmtctx.h(Ctx API,带上下文) │ ← 新场景使用 ├──────────────────────────────────┤ │ 具体实现(各模块 .c 文 │ └──────────────────────────────────┘

Ctx API(定义在hsakmtctx.h)是真正的实现入口,每个函数的第一个参数都是HsaKFDContext *ctx

// hsakmtctx.hHSAKMT_STATUS HSAKMTAPIhsaKmtAllocMemoryCtx(HsaKFDContext*ctx,HSAuint32 PreferredNode,HSAuint64 SizeInBytes,HsaMemFlags MemFlags,void**MemoryAddress);HSAKMT_STATUS HSAKMTAPIhsaKmtCreateQueueExtCtx(HsaKFDContext*ctx,HSAuint32 NodeId,HSA_QUEUE_TYPE Type,unsignedintQueuePercentage,...);

遗留 API(定义在hsakmt.h)变成了简单的转发层,自动传入 Primary Context:

// queues.cHSAKMT_STATUShsaKmtCreateQueueExt(...){returnhsaKmtCreateQueueExtCtx(&hsakmt_primary_kfd_ctx,...);}HSAKMT_STATUShsaKmtDestroyQueue(HSA_QUEUEID QueueId){returnhsaKmtDestroyQueueCtx(&hsakmt_primary_kfd_ctx,QueueId);}// topology.cHSAKMT_STATUShsaKmtAcquireSystemProperties(HsaSystemProperties*SystemProperties){returnhsaKmtAcquireSystemPropertiesCtx(&hsakmt_primary_kfd_ctx,SystemProperties);}

这个设计的优雅之处在于:

  • 完全向后兼容—— 不修改任何现有调用者的代码,遗留 API 行为不变
  • 无代码重复—— 实现逻辑只存在于*Ctx()函数中,遗留 API 是零逻辑的转发
  • 渐进式迁移—— 新代码可以直接使用 Ctx API,老代码保持不变,自然过渡

测试框架也通过一个巧妙的宏来在两套 API 之间切换:

// KFDTestUtil.hpp#ifdefHSAKMT_CTX#defineHSAKMT_CALL(func,ctx,...)func##Ctx(ctx,##__VA_ARGS__)#else#defineHSAKMT_CALL(func,ctx,...)func(__VA_ARGS__)#endif

编译时定义HSAKMT_CTX,所有测试自动切换到 Ctx API 路径;再加上HSAKMT_SECONDARY_CTX,测试可以运行在 Secondary Context 上,验证隔离性。


6. 小结

要素说明
原始模型单进程单上下文,全局hsakmt_primary_kfd_ctx,所有线程共享
新需求容器化多租户隔离、调试器隔离、DRM VM 空间隔离
核心数据结构HsaKFDContext聚合 fd + 六个子上下文指针(topology / queue / fmm / event / debug / perf)
Primary Context全局唯一,引用计数管理,功能完整
Secondary Context动态分配,独立 fd +AMDKFD_IOC_CREATE_PROCESS,独立 VM 空间,部分功能受限
API 兼容策略双层设计 ——hsakmtctx.h(Ctx API)为实现层,hsakmt.h(遗留 API)为转发层
隔离粒度内存 aperture / DRM 设备句柄 / GPU VM 空间 / 队列 / 事件,各上下文完全独立

KFD Context 的引入是 libhsakmt 架构的一次重要演进。它在保持向后兼容的前提下,将原本"进程 = 上下文"的刚性绑定松开,使得同一进程内可以划分出多个相互隔离的 GPU 资源域。
ROCm的虚拟化是一个很长的技术栈,涉及到guest/host的双系统的栈。如果大家对此感兴趣,可以关注下AMD工程师的相关其他软件库的提交。


下一篇 11.2 将深入分析六个子上下文的内部结构与按需初始化机制。文章审核中…

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 16:33:01

手持式激光测云仪

手持式激光测云仪专为户外手持机动测云打造,整机重量轻盈、机身小巧紧凑,彻底摒弃传统云高仪笨重、占地大、无法移动的短板。凭借重量轻、体积小、携带方便的核心优势,工作人员可单手手持操作、轻松携带转运,无需车辆搭载、无需固…

作者头像 李华
网站建设 2026/5/26 16:29:17

学术写作必备!GPT-5.5辅助三重校验法:从逻辑到术语精准的创新点锁定指南

各位同仁好,我是七哥。一个在高校里从事人工智能相关领域研究,钻研用大模型AI实操的学术人。可以和七哥交流学术写作或Gemini、GPT、Claude等大模型学术实操相关问题,多多交流,相互成就,共同进步。 研究者常常面临一个隐形困境:尽管语法无误,但论文总被评审指出表述不清…

作者头像 李华
网站建设 2026/5/26 16:26:33

HarmonyOS ArkTS DeviceUtil 设备标识符完整指南:DeviceId、ODID、OAID、AAID

文章目录前言一、为什么有这么多"设备 ID"?二、DeviceUtil 标识符相关方法源码三、DeviceId 的特殊设计:卸载后不消失四、Demo 完整演示代码五、四种 ID 选择建议六、小结前言 近期发现一款很有意思的HarmonyOS 三方库, 地址 pura/harmony-uti…

作者头像 李华
网站建设 2026/5/26 16:25:17

小样本学习与注意力机制在婴儿表情识别中的实战应用

1. 项目概述:当深度学习遇见婴儿的“喜怒哀乐”在计算机视觉的浩瀚海洋里,面部表情识别一直是个既迷人又充满挑战的领域。我们成年人可以通过语言和复杂的表情传递情绪,但对于尚在襁褓中的婴儿,他们的“语言”几乎完全由面部表情、…

作者头像 李华
网站建设 2026/5/26 16:24:26

Java算法练习day3

一、游游的重组偶数Java代码import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {// 纯数学运算实现 dep 函数,和你C逻辑完全一样public static int dep(int x) {int temp x;int k 0;// 保存最后一位数字int last …

作者头像 李华
网站建设 2026/5/26 16:24:08

ApuEmo混合模型:基于SaBERT与多路RNN的西班牙语社交媒体情感分类实践

1. 项目概述与核心挑战情感分类,或者说情绪识别,是自然语言处理领域里一个既经典又充满挑战的任务。简单来说,就是让机器读懂文字背后的喜怒哀乐。在英语世界,得益于海量的标注数据和成熟的预训练模型,这项技术已经相当…

作者头像 李华