第三章:GEM分析:gem_object 如何被 GPU 访问(下):gpuva 字段与映射反向索引
先说下要理解本节分析要按如下的的顺序gem_object 如何被 GPU 访问上旧模型 BO-list Relocation 隐式同步旧模型对象每次提交临时定址→ gpuva新模型drm_gpuvm把“对象 → 持久 GPU VA 映射”提取为通用框架→本文回到drm_gem_object自身看它如何持久记录“指向自己的全部映射”。因此本文只分析drm_gem_object自身携带的gpuva字段——它的设计目的、相关 API 与使用方法。至于drm_gpuvm/drm_gpuva框架的整体设计新需求、Split Merge、VM_BIND 流程等见 gpuva。1. 这个字段是什么drm_gem_object里有这样一小块struct{structlist_headlist;// 该对象参与的所有 (对象, VM) 组合链表structmutexlock;// 仅 IMMEDIATE_MODE 下保护 list6.18 引入}gpuva;它的作用只有一个让内核能从一个 GEM 对象出发反向找到这个对象被映射到了哪些 GPU 地址空间、以及每个空间里的哪些具体映射。注意一个极易误解的点gpuva.list挂的不是drm_gpuva而是drm_gpuvm_bo。它是一个两级链表结构见第 3 节。2. 从旧模型接续为什么现在对象需要这条反向链表回顾 gem_object 如何被 GPU 访问上旧模型里“一个gem_object参与了哪些提交、在哪些地址上被访问”是临时的——每次提交靠 BO-list 现场重建提交一结束就不再保留。因此旧模型里对象不需要持久记录“谁在用我”。到了新模型gpuva 的 VM_BIND映射变成持久的用户态预先把对象 bind 到稳定 GPU VA这些drm_gpuva映射会长期存在、跨越多次提交。于是产生一个旧模型没有的新需求——对象必须持久地知道“有哪些映射指向我、分布在哪些 VM”否则驱逐、销毁、校验时无从下手。gpuva字段就是这条持久反向索引它在语义上取代了旧模型里“每次提交临时重建的 BO-list 成员关系”。这条链表的出现本质上是一系列模型转变共同倒逼的结果。把两代模型的关键差异摆在一起看就能明白为什么“反向索引”从可有可无变成了必需维度旧模型BO-list Relocation 隐式同步新模型VM_BIND /drm_gpuvmGPU 地址稳定性早期 relocation 下地址不稳定每次提交可能重定位i915/UMAamdgpu 靠amdgpu_bo_va才有 per-VM 稳定地址用户态显式 bind 到稳定 GPU VA跨多次提交长期不变地址由谁决定内核在提交时隐式决定/修补地址relocation 由内核回填用户态显式分配并控制 VAVM_BIND ioctl映射生命周期临时随单次提交建立、提交结束即失效持久bind 后长期存在与提交解耦同步方式隐式同步内核依据 BO-list 自动串联依赖显式同步用户态用 fence/syncobj 自己表达依赖“谁在用我”如何表达每次提交靠 BO-list现场重建无持久结构靠对象自带的gpuva.list持久记录枚举对象映射的代价无需持久枚举提交上下文里就有完整 BO-list若无反向索引需遍历每个 VM 的整棵区间树 → 故必须内联反向链表控制权归属偏内核托管定址、同步、校验都在内核提交路径偏用户态自管定址、同步显式化内核只维护结构与一致性一句话概括这次演进从“内核隐式处理、地址临时不稳定”走向“用户态显式控制、地址持久稳定”——正是后者让“对象需要持久知道谁在映射自己”成为硬需求gpuva字段应运而生。换个角度看正向问题“某个 VA 映射到谁”由drm_gpuvm的区间树回答见 gpuva 第 3 节反向问题“某个对象参与了哪些映射”就靠本字段的链表。典型的反向操作它们在旧模型里本是每次提交的 BO-list 校验的一部分现在改由持久反向索引驱动对象被驱逐evictBO 从显存被换出后所有指向它的映射都要标记失效、下次使用前重建 PTE。必须能枚举“指向本对象的全部映射”。对象被销毁 / 强制解绑释放前要把它在各个 VM 里的映射全部拆掉。重新校验validate提交前确认对象已回迁并刷新相关映射。如果没有这条反向链表就只能遍历每个 VM 的整棵区间树去找匹配的对象代价高昂。因此框架把反向索引直接内联到 GEM 对象上——这正是gpuva字段存在的理由。它与对象里另一个方向的字段形成对称也正好对应新旧两个阶段对“对象被访问”的不同管理方式字段管的方向回答vma_nodeCPU 侧对象被哪些进程 mmapCPU 地址空间gpuva.listGPU 侧对象被绑定到哪些 GPU 地址空间及其映射对照旧模型旧模型里“GPU 侧”的关系是靠 BO-list 每次提交临时表达的无持久结构新模型把它固化为gpuva.list这条持久链表。3. 两级链表结构gpuva.list的组织是对象 → 每个 VM 一个drm_gpuvm_bo→ 该 VM 内的每条drm_gpuvaVM_2 中该对象的映射VM_1 中该对象的映射第一级: 每个 VM 一个 drm_gpuvm_bolist.entry.gemlist.entry.gemlist.gpuva / gem.entrylist.gpuva / gem.entrydrm_gem_objectgpuva.listdrm_gpuvm_bo (obj, VM_1)drm_gpuvm_bo (obj, VM_2)drm_gpuva [a,r)off0drm_gpuva [b,r)off1drm_gpuva [c,r)off0第一级drm_gem_object.gpuva.list串起若干drm_gpuvm_bo每个代表本对象 × 某个 VM这一唯一组合链接字段是drm_gpuvm_bo.list.entry.gem。第二级每个drm_gpuvm_bo.list.gpuva串起本对象在该 VM 内的全部drm_gpuva链接字段是drm_gpuva.gem.entry。为什么要中间加一层drm_gpuvm_bo而不是让对象直接挂一堆drm_gpuva因为同一对象在同一个 VM里可能有多条映射不同 offset → 不同 VA。用(对象,VM)组合作为聚合点既能按 VM 分组枚举映射又能让 extobj/evicted 等 per-VM 列表复用同一个drm_gpuvm_bo表项。4. 相关 API4.1 启用与初始化API / 标志作用DRIVER_GEM_GPUVAdrm_driver.driver_features驱动声明支持用户自定义 GPU VA 绑定。使用本字段的前提。drm_gem_gpuva_init(obj)初始化gpuva.listINIT_LIST_HEAD。在驱动创建 GEM 对象时调用。staticinlinevoiddrm_gem_gpuva_init(structdrm_gem_object*obj){INIT_LIST_HEAD(obj-gpuva.list);}4.2 遍历宏遍历对象说明drm_gem_for_each_gpuvm_bo(vm_bo, obj)第一级所有drm_gpuvm_bo即对象被绑定的每个 VMdrm_gem_for_each_gpuvm_bo_safe(vm_bo, next, obj)同上可在遍历中删除drm_gpuvm_bo_for_each_va(va, vm_bo)第二级某vm_bo下所有drm_gpuva需持有 GEM 的 gpuva 锁drm_gpuvm_bo_for_each_va_safe(va, next, vm_bo)同上可安全删除嵌套两层即可枚举本对象的全部映射structdrm_gpuvm_bo*vm_bo;structdrm_gpuva*va;drm_gem_for_each_gpuvm_bo(vm_bo,obj)drm_gpuvm_bo_for_each_va(va,vm_bo)do_something(va);// va-vm 是所属 VMva-va.addr/range 是映射区间4.3 锁API作用drm_gem_gpuva_assert_lock_held(gpuvm, obj)lockdep 断言按模式检查持有正确的锁锁规则由 GPUVM 的模式决定默认模式gpuva.list由GEM 的dma_resv锁obj-resv保护。DRM_GPUVM_IMMEDIATE_MODE6.18改由内置的gpuva.lockmutex保护以便在 dma-fence 信号临界路径中修改。在该锁下不得分配内存。断言宏正是据此二选一#definedrm_gem_gpuva_assert_lock_held(gpuvm,obj)\lockdep_assert(drm_gpuvm_immediate_mode(gpuvm)?\lockdep_is_held((obj)-gpuva.lock):\dma_resv_held((obj)-resv))提示头文件里drm_gem_gpuva_init()注释的 “See also drm_gem_gpuva_set_lock()” 是过时引用——早期版本用drm_gem_gpuva_set_lock()设置外部锁现已改为内置gpuva.lockmutex 上述模式判定。4.4 建立/摘除链接跨到框架侧对象侧链表的表项增删由框架侧函数完成这里列出交界处的常用者API作用drm_gpuvm_bo_obtain()/_obtain_locked()/_obtain_prealloc()获取/新建(obj, vm)的drm_gpuvm_bo并挂入对象的gpuva.listdrm_gpuvm_bo_find(vm, obj)查找已存在的drm_gpuvm_bodrm_gpuva_link(va, vm_bo)/drm_gpuva_unlink(va)把一条drm_gpuva挂入/摘出vm_bo即二级链表drm_gpuvm_bo_gem_evict(obj, evict)遍历对象的所有vm_bo批量置驱逐标志5. 使用方法5.1 驱动接入的最小步骤在drm_driver.driver_features里置上DRIVER_GEM_GPUVA。在创建 GEM 对象的路径里调用drm_gem_gpuva_init(obj)。bind 时拿到/新建drm_gpuvm_bodrm_gpuvm_bo_obtain*再对每条映射drm_gpuva_link()unbind 时对应drm_gpuva_unlink()。需要枚举对象映射时驱逐/销毁/校验用 4.2 的两级遍历宏并按 4.3 持好锁。5.2 典型场景 1对象被驱逐时标记全部映射失效/* 持有 obj-resv默认模式或 gpuva.lockimmediate 模式 */voiddriver_bo_evicted(structdrm_gem_object*obj){structdrm_gpuvm_bo*vm_bo;structdrm_gpuva*va;drm_gem_for_each_gpuvm_bo(vm_bo,obj){drm_gem_gpuva_assert_lock_held(vm_bo-vm,obj);/* 该对象在这个 VM 里进入 evicted 列表 */drm_gpuvm_bo_evict(vm_bo,true);/* 逐条映射标记失效下次提交前重建 PTE */drm_gpuvm_bo_for_each_va(va,vm_bo)drm_gpuva_invalidate(va,true);}}上例中drm_gpuvm_bo_gem_evict(obj, true)已封装了遍历 vm_bo 置驱逐标志的部分。5.3 典型场景 2销毁对象前解绑所有映射drm_gem_for_each_gpuvm_bo_safe(vm_bo,next_bo,obj){structdrm_gpuva*va,*next_va;drm_gpuvm_bo_for_each_va_safe(va,next_va,vm_bo){drm_gpuva_unlink(va);// 摘出二级链表drm_gpuva_remove(va);// 从 VM 区间树移除driver_free_pt_and_va(va);// 驱动清理 PTE 与 drm_gpuva 内存}/* vm_bo 的引用释放后会自动摘出对象的 gpuva.list */}6. 小结从演进线看旧模型用临时 BO-list表达“谁在用我”新模型映射持久化后对象改用gpuva字段持久记录这个关系。drm_gem_object.gpuva是对象侧的反向索引从对象快速找到“它参与的所有 GPU 映射”服务于驱逐、销毁、校验等需要按对象枚举映射的场景。它是两级链表对象 →drm_gpuvm_bo每 VM 一个→drm_gpuva每条映射一个。别把gpuva.list当成drm_gpuva的直接列表。用法要点DRIVER_GEM_GPUVAdrm_gem_gpuva_init()初始化drm_gem_for_each_gpuvm_bo()套drm_gpuvm_bo_for_each_va()遍历按模式持obj-resv或gpuva.lock。它与vma_node对称一个记录对象在 CPU 地址空间的映射一个记录在 GPU 地址空间的映射。

相关新闻

企业级AI Agent架构设计与工程实践:以理赔系统为例

企业级AI Agent架构设计与工程实践:以理赔系统为例

在数字化转型浪潮中,企业级 AI Agent(智能体)的应用正从概念走向落地。然而,许多团队在引入 Agent 技术时,常常面临一个典型困境:技术能力在核心部门或少数场景中“扎堆”,却难以有效扩散到整个…

2026/9/17 1:02:21 阅读更多 →
RHEL 9.7系统性能优化实战指南

RHEL 9.7系统性能优化实战指南

1. RHEL 9.7系统优化全景解读 作为企业级Linux发行版的标杆,RHEL 9.7在性能、安全性和稳定性方面都达到了新的高度。但默认安装配置往往无法充分发挥其潜力,特别是在高负载生产环境中。本文将分享我在金融行业核心系统中优化RHEL 9.7的实战经验&#xff…

2026/9/23 7:48:14 阅读更多 →
杭州GEO优化公司怎么选?这份评测把爱搜索、博盈等五家讲透了

杭州GEO优化公司怎么选?这份评测把爱搜索、博盈等五家讲透了

先给结论:在杭州乃至国内GEO优化服务商里,爱搜索、微甜科技、博盈科技排在前三。爱搜索胜在GEO技术全链路自研,微甜科技强在电商广告大盘的承接能力,博盈科技则靠腾讯生态与温州本地化服务站稳一席。这个排序不是简单的名气榜&…

2026/9/20 2:19:36 阅读更多 →

最新新闻

工程车辆目标检测数据集:YOLO格式解析与训练避坑指南

工程车辆目标检测数据集:YOLO格式解析与训练避坑指南

简介:一份面向目标检测与计算机视觉开发者的工程车辆数据集,聚焦混凝土搅拌车、自卸卡车、挖掘机三类工程车辆,采用YOLO格式标注,可直接用于建筑工地智能监控、智能交通、自动驾驶环境感知等场景的模型训练。压缩包共902个文件&am…

2026/9/23 23:03:25 阅读更多 →
宜搭低代码四层建模逻辑:表单、流程、数据权限与集成

宜搭低代码四层建模逻辑:表单、流程、数据权限与集成

简介:本资源是阿里巴巴官方出品的《0 代码,搭应用——宜搭开发手册》PDF电子手册,面向企业数字化转型负责人、业务部门人员及低代码初学者,聚焦解决传统信息化建设中系统缺失、流程脱节、数据孤岛与开发成本高等痛点。手册系统讲解…

2026/9/23 23:03:25 阅读更多 →
俄罗斯实拍47类军民飞机YOLO数据集与细粒度识别实战

俄罗斯实拍47类军民飞机YOLO数据集与细粒度识别实战

简介:本资源为面向计算机视觉算法研究者的飞机型号识别专用数据集(第二批),聚焦军民飞机目标检测与细粒度分类任务,适用于YOLO、Faster R-CNN等模型的训练与评估,特别适合开展跨机场场景下的军机识别&#…

2026/9/23 23:03:24 阅读更多 →
Java多语言融合的交通流量分析与拥堵预警系统实战

Java多语言融合的交通流量分析与拥堵预警系统实战

简介:一套基于Java核心并融合Vue、Python、JavaScript等多语言的智能交通流量数据分析与拥堵预警系统源码,适合学习微服务架构、多语言协作开发以及交通数据可视化应用的开发者。压缩包共91个文件,约214KB,其中包含64个Java后端源…

2026/9/23 23:03:24 阅读更多 →
Python火车票管理系统源码解析:从环境搭建到项目实战

Python火车票管理系统源码解析:从环境搭建到项目实战

简介:这份Python火车票管理系统源码面向具备Python基础、希望理解完整项目开发流程的学习者,可用于课程设计、毕业设计参考或自学练手。系统模拟真实购票场景,涵盖车次查询、车票预订、退票等核心功能,并借助面向对象思想划分用户…

2026/9/23 23:03:15 阅读更多 →
EverOS 记忆工作原理:Markdown 为源、SQLite 与 LanceDB 为派生索引的分层存储与同步管线

EverOS 记忆工作原理:Markdown 为源、SQLite 与 LanceDB 为派生索引的分层存储与同步管线

EverOS 记忆工作原理:Markdown 为源、SQLite 与 LanceDB 为派生索引的分层存储与同步管线 【免费下载链接】EverOS One portable memory layer for every AI agent: local-first, Markdown-native, user-owned, and self-evolving across apps, tools, and workflow…

2026/9/23 23:02:14 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/23 9:53:41 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/23 9:53:40 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/23 9:53:40 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/23 9:53:40 阅读更多 →