资讯动态

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

发布时间:2026/10/27 1:52:41 来源:尧图企业网站定制
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及其创建过程。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑