4.3 为什么选择 shmem:从 BO 需求到 GEM 框架,再到 shmem

发布时间:2026/10/27 1:52:36

4.3 为什么选择 shmem:从 BO 需求到 GEM 框架,再到 shmem 4.2 的 DMA-CMA 将分配链路缩至最短代价是内存一次分配后即固定不变。对于 UMA 设备上数以百计乃至千计的 BO这种方式代价过高。DRM 提供的通用方案是shmem每个 BO 以一个 shmem 文件作为后备。本节按以下三个步骤说明为何选择 shmem 文件从 BO 的使用方式归纳出对后备存储的需求分析 GEM框架层将这些需求体现为哪些接口以及由此对后备提出的具体要求逐层检验shmem满足了哪些要求哪些须由 helper 补充。1、需求BO 在 UMA 设备上的使用方式一个 BO 从创建到释放通常经历以下环节用户态创建 BO经mmap映射后填入数据BO 提交给 GPU由 GPU 通过 DMA 读写内核偶尔通过vmap访问它例如 fbdev 控制台有时 BO 被导出为 dma-buf供显示控制器或视频编码器使用各方均不再使用后BO 被释放。这一过程体现出三个特点持有者多handle、dma-buf 与正在执行的 GPU 任务都可能引用同一个 BO。创建它的进程退出后BO 仍可能被其他持有者使用访问方多用户态、内核、本设备与其他设备都可能访问同一批页且可能同时访问量大且常闲置BO 体积大帧缓冲、纹理通常达数 MB数量多一个进程可拥有数百乃至上千个且大部分时间处于闲置状态。在 UMA 设备上这些内存还与普通应用共享同一份系统内存。由此得出后备存储须满足的六项需求需求来源N1 内容归 BO 所有仅在最后一个引用消失时释放持有者多N2 访问有序CPU、本设备与其他设备之间的访问不得相互冲突访问方多N3 CPU 可访问用户态mmap、内核vmap访问方多N4 设备可访问包括导出给其他设备访问方多N5 设备可正确访问地址可达、访问期间不被迁移、缓存一致设备直接访问物理内存N6 闲置时减少内存占用按需分配、闲置时可换出、不再需要时可丢弃量大且常闲置且与 CPU 共享内存2、框架层GEM 中与需求对应的接口GEM 核心并不规定后备的具体形式但通过struct drm_gem_object的字段与struct drm_gem_object_funcs的回调对后备提出了要求。按强制程度这些要求可分为四层层次对应需求GEM 接口对后备的要求必选N1、N2free唯一必选的回调引用计数归零时调用size注释写明对象生命期内不可变resvvmap、evict等回调要求持锁调用随对象释放大小固定状态变更在dma_resv下进行按功能N3、N4mmap/vm_opsvmap/vunmappin/unpindma-buf 导入方 attach 时调用get_sg_table导出时调用随后以导入方设备进行 DMA 映射可按页插入用户页表可组合为连续的内核地址可被固定可表示为由struct page组成的 sg 表可选回收N6evictdrm_gem_lrustatus中的 RESIDENT / PURGEABLErss允许部分驻留、可被驱逐、可被 purge框架不涉及N5无对应接口仅在dma_map_sgtable时交由 DMA API 处理由驱动与 DMA API 负责需要说明以下几点功能层隐含了「后备由普通内存页组成」这一前提。get_sg_table的注释指出这套导出 helper 不能用于指向驱动私有内存区域的 sg 表。因此若要使用通用的共享路径后备必须是具有struct page的普通内存框架仅强制要求必选层。回收层仅提供钩子rss可以小于size表明框架允许后备仅部分驻留在内存中但并不强制。然而对 UMA 设备而言N6 恰恰最为重要因为 BO 与普通应用竞争同一份内存框架具有默认后备。drm_gem_object中filp字段的注释为 “SHMEM file node used as backing storage for swappable buffer objects”内核文档drm-mm.rst亦写道 “GEM uses shmem to allocate anonymous pageable memory”。这与 GEM 的起源有关GEM 最初为没有独立显存的 Intel 集成显卡设计BO 即以 shmem 文件作为后备i915 至今仍以这种方式处理集成显卡上的 BOi915_gem_shmem.c创建 shmem 文件这一步也因此位于 GEM 核心而非 helper 中3.2.2。不使用 shmem 的对象称为私有对象由drm_gem_private_object_init()初始化其存储由驱动自行管理。3、shmem 是否满足逐层检验3.1 必选层满足shmem 文件在drm_gem_object_init()中按对象大小创建在drm_gem_object_release()中随对象一起经fput释放。其大小在创建时确定生命期与对象一致与创建该对象的进程无关。持锁约定由 helper 遵守见 4.3.2。3.2 功能层所需条件均已具备shmem 文件的页即普通的 page cache 页文件内容在内存中的页由文件的address_space按偏移索引每页均有对应的struct page。将这些页取出并组织为pages[]后mmap发生缺页时将对应的页插入用户页表vmap通过内核的vmap()将分散的页映射为一段连续地址get_sg_table通过drm_prime_pages_to_sg()生成 sg 表。仅pin的语义须由 helper 自行实现维护一个 pin 计数保证计数大于 0 时页不会被驱动 purge见 4.3.3。3.3 回收层天然满足这是 shmem 最核心的优势其关键在于内容保存在 shmem 文件中页数组仅是对文件页的引用。shmem BO 的内容归属于其后备的shmem 文件而非pages[]数组获取页helper 需要页时按偏移从文件中获取。若页尚不存在则即时分配若已被换出则即时从 swap 换回此即按需分配归还页helper 使用完毕后仅释放对页的引用页仍保留在文件的 page cache 中。此后内存紧张时内核可像处理普通 tmpfs 文件一样将其换出至 swap下次获取页时再换回。由于内容始终归属于文件因此不会丢失丢弃将文件截断为空即可页与 swap 槽位随之一并释放此即 purge见 4.3.6。由此可见shmem 文件将「内容保存」与「内存回收」交由内核已有的机制完成helper 仅需负责获取页与归还页。3.4 框架不涉及的设备层需要修补shmem 为普通文件而设计不考虑设备访问因此不满足 N5 的各项要求。helper 中最关键的几段代码均用于修补这一层设备层要求shmem 的情况helper 的修补详见访问期间不被迁移文件的页默认从 MOVABLE 区分配可能被迁移在该区域长期 pin 还会妨碍内存规整并与 CMA 冲突创建时将文件的 GFP 掩码改为GFP_HIGHUSER不含__GFP_MOVABLE4.3.1访问期间不被回收内核可能随时回收文件的页持有页期间将文件标记为 unevictable内核不再回收本设备访问期间由驱动保证不进行 purge内核 vmap 及导出给其他设备时另行 pin4.3.2 / 4.3.3地址可达、不要求连续页在物理上分散位置亦不受控制将页数组转换为sg_table经dma_map_sgtable映射由 IOMMU 或 swiotlb 处理寻址4.3.5缓存一致page cache 页默认按 cached 方式映射驱动设置map_wc后helper 在 x86 上将页属性改为 WCvmap 与 mmap 亦以 write-combined 方式映射4.3.2 / 4.3.44、对照其他候选方案的不足所在将其他几种内存来源置于同一框架下比较候选必选层功能层回收层设备层dma_alloc/ CMA4.2✓✓✗ 一次分配后固定不变✓ 连续且常驻一次性满足驱动自行alloc_pages✓✓✗ 内核无法换出只能自行实现需自行处理用户态匿名内存userptr✗ 内存归进程所有✓BO 无法控制需先 pinshmem 文件✓✓✓ 天然满足需 helper 修补关键差异在于回收层设备层的不足可以通过一层通用代码弥补第 3.4 节所述即为 helper 的工作回收层的能力则难以弥补。驱动自行分配的页不属于任何文件或进程映射内核的换出机制无法处理这些页若要换出只能自行将内容拷贝至他处。TTM 正是采用这种方式ttm_tt_swapout()先创建一个 shmem 文件将页内容拷贝进去再由内核换出该文件见 5.10。因此即便是 TTM换出时最终也须借助 shmem 文件。CMA 恰好相反设备层一次性满足回收层则完全放弃因此适用于必须使用物理连续内存的设备见 4.1 第 4 节。5、从 shmem 到 helper在 helper 出现之前每个 UMA 驱动都须自行编写几乎相同的代码创建 shmem 文件按需获取页供设备使用时 pin 页并构建sg_table实现用户态mmap与缺页处理实现vmap供内核访问释放时归还页。这些逻辑高度雷同且容易出错各驱动又各自实现一套。drm_gem_shmem_helper2018 年引入将其抽象为一层公共代码第 3 节中功能层的操作与设备层的修补均由它统一完成。其定位有两点是 helper而非 framework它是一组可选的公共函数。驱动只需内嵌drm_gem_shmem_object并将回调指向 helper 的实现即可直接复用见 4.3.7仅实现 UMA 所需的功能分配页、pin、sg_table、vmap、mmap、缺页、回收、释放。放置、迁移、VRAM 驱逐均不在其范围内这正是它与 TTM 的分工界线。6、shmem 系列路线第 3.3 节指出BO 的内容保存在 shmem 文件中helper 持有的仅是对文件页的引用。后续七篇即围绕「一份内容多份引用」这一主线展开依次回答四个问题页从哪里来、由谁使用、何时能够收回、驱动如何接入。问题小节内容对应需求页从哪里来4.3.1 对象与创建struct drm_gem_shmem_object的字段以及drm_gem_shmem_create如何建立 shmem 文件、分配伪偏移、设定 GFP 掩码对象创建完成时只有文件尚未持有任何页N1、N54.3.2 取页与还页get_pages/put_pages从文件获取页与归还页以及所有状态变更共用的dma_resv锁后续所有访问路径均建立在这一对操作之上N2、N5、N6由谁使用4.3.3 引用的强弱use 与 pin 两种强度的引用、三层计数的持有者以及由此决定的四种对象状态N2、N5、N64.3.4 CPU 访问vmap与mmap两条 CPU 访问路径以及缺页处理N34.3.5 设备访问本设备经get_pages_sgt进行 DMA其他设备经 PRIME / dma-buf 导出与导入共享N4、N5何时能够收回4.3.6 回收换出至 swap 与驱动 purge 两条回收路径以及 shrinker 的接入方式N6驱动如何接入4.3.7 驱动集成驱动如何内嵌对象、填写回调表并使用gem_create_object以 virtio-gpu 为例—7、本节小结需求BO 持有者多、访问方多、量大且常闲置由此得出 N1N6 六项需求框架层GEM 将需求体现为必选、按功能、可选回收三层接口设备层则不在框架范围内shmem满足必选层与功能层并天然满足回收层因为内容保存在文件中pages[]仅是引用设备层由 helper 修补对照设备层的不足可由通用代码弥补回收层则难以弥补即便 TTM 换出也须借助 shmem 文件。下一节4.3.1阐明选择依据之后下一节介绍 helper 的核心数据结构struct drm_gem_shmem_object及其创建过程。
延伸阅读

更多相关文章

2026/10/27 1:52:36

【零基础学智能仿真-54】参数化仿真与敏感度分析

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

2026/10/27 1:52:36

威胁情报驱动防御升级,从被动告警转向主动狩猎

威胁情报已经从单纯的 “攻击信息参考” 升级为企业安全运营的核心输入。高质量威胁情报能够帮助企业提前识别攻击者 IP、域名、恶意文件、漏洞利用工具、攻击组织战术和目标行业偏好,使安全团队从 “收到告警再处置” 转向 “基于情报提前检测、提前封堵、提前防御…

2026/10/27 1:47:36

Wails 安装环境搭建指南:Go 跨平台桌面应用一步到位

Wails 安装环境搭建指南:Go 跨平台桌面应用一步到位 【免费下载链接】wails Create beautiful applications using Go 项目地址: https://gitcode.com/gh_mirrors/wa/wails Wails 是「Go 写后端 网页技术写前端」的跨平台桌面应用框架,一条命令就…

2026/10/27 2:47:46

Unity物理绳子实现:ConfigurableJoint关节链深度解析

1. 项目概述:为什么一根“会动的绳子”在Unity里比看起来难得多在Unity3D项目里,当你需要让角色拽着一根软软的缆绳攀爬、让吊灯在风中自然摇晃、或者让机械臂末端拖着柔性导管运动时,你很快会发现——Unity自带的LineRenderer画出来的只是一…

2026/10/27 2:47:46

机器人技术十年演进:从传感器革命到大模型赋能

1. 从实验室走向产业化的十年征程2015年那个闷热的夏天,我在深圳华强北电子市场的地下仓库里,第一次见到了能自主规划路径的物流机器人原型机。这个由三个大学生用树莓派和二手电机拼凑的装置,在堆满纸箱的过道里跌跌撞撞地行进,却…

2026/10/27 2:47:46

无人机道路损坏识别数据集与分割模型实践

1. 数据集项目概述这个无人机视角路面损坏和冲刷道路滑坡预警识别分割数据集,是一个专门为道路基础设施监测设计的专业图像数据集。它包含了579张高分辨率无人机航拍图像,覆盖了四种典型的道路损坏和自然灾害类别。作为一名长期从事计算机视觉和基础设施…

2026/10/27 2:47:46

Linux内核模块开发实战:Rootkit源码深度解析与调试

简介:这是一份面向Linux内核安全与逆向学习者的轻量级Rootkit开发实践资源,适用于具备C语言基础和Linux系统调用认知的中级开发者,用于理解内核模块加载、进程/模块隐藏等典型Rootkit技术原理。压缩包共46个文件,总大小仅36KB&…

2026/10/27 2:47:46

基于知识蒸馏的高光谱图像轻量化分类方案

1. 项目背景与核心价值高光谱图像分类是遥感领域的重要研究方向,相比传统RGB三通道图像,高光谱图像包含数十甚至数百个连续光谱波段,能够提供更丰富的地物特征信息。然而这种数据优势也带来了计算复杂度高、模型参数量大等实际问题&#xff0…

2026/10/27 2:42:45

LeetCode 829题解:连续整数求和的数学与算法

1. 问题背景与理解LeetCode 829题"连续整数求和"要求我们找出所有可能的连续正整数序列,这些序列的和等于给定的整数n。这道题看似简单,但蕴含着数学规律和编程技巧的结合。我们先从一个具体例子入手理解题目要求:假设n15&#xff…

2026/10/26 0:20:20

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/26 1:53:47

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑