[译文] GEM vs. TTM

本文探讨了Linux下GPU内存管理的挑战,对比了翻译表映射(TTM)和图形执行管理器(GEM)两个解决方案。GEM通过使用普通内存、避免内存映射、简化隔离机制以及提供灵活API等方式,为桌面和嵌入式驱动开发者提供了更优的性能和易用性。尽管GEM尚处于初期阶段,但其潜力和与Intel的紧密合作表明它可能是未来GPU内存管理系统的有力竞争者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[译文] GEM vs. TTM

By Jonathan Corbet 
May 28, 2008 
王旭于2008年8月8日译   http://wangxu.me/blog/?p=124
http://lwn.net/Articles/283793/

在 Linux 下,即使是在有了基础硬件的编程接口信息的情况系,得到高性能的 3D 渲染仍然是非常具有挑战性的。这个问题的一个原因就是内存管理:一个 GPU 本质上说是一个拥有它自己的独立的内存的计算机系统。要想管理GPU 的内存 —— 以及以它的视角看到的系统内存,让系统能够跑起来就必须要小心,更不要说还要获得可接受的性能了。

不久以前,这个问题看上去要被翻译表映射(TTM)子系统 解决了。TTM 目前仍然没有进入主线内核,依赖于它的所有驱动自然也没有进入。最近的一个关于 TTM 如何才能进入主线的提问引发了一场有趣的讨论,最终使得局面急转直下,TTM 可能根本就不是未来的显存管理系统。

很多关于 TTM 的抱怨都已经浮现出来了。它的 API 远大于任意一个开源 Linux 驱动的需求;换句话说,大量的代码都是用于二进制发布的驱动的。隔离机制(fence, 管理 CPU 和 GPU 的并发性的机制)非常复杂而难于使用,而且并不是总能得到很好的性能。大量的使用内存映射缓冲会给它自己带来性能问题。TTM API 尝试着提供所有情况下的一切东西;结果对于很多开发者来说很难让特定的硬件去匹配这些 API,很难开始使用 TTM,也缺乏足够的灵活性。对于使用TTM的开源驱动来说,这是一个重大的不足。所以 Dave Airlie 担忧地说 :

现在,我希望有一个 radeon 或是什么新的驱动已经使用了 TTM,或者,至少有个 demo 展示了如何使用它,可是现在什么也没有,这让我很痛苦……真正的问题是 TTM 是不是真的适合于 Linux 桌面和嵌入式驱动的开发者们,至少我在桌面方面还没看到足够的正面反馈。

所有这些但有看来都是徒劳的,毕竟 TTM 已经在那了,而且也没有什么其他的替代品。然而,事情发生了,一个转机发生了,它就叫做图形执行管理器(这名字翻译的好难听阿,对不起观众了),简称 GEM。Intel 资助的 GEM 项目已经有一个月了(译注:原文写于08年5月底,目前 GEM 形势大好阿)。GEM 的开发者其实还没完全准备好来对外公布他们的工作,不过 TTM 的讨论让他们提前走上了前台。

Keith Packard (译注:Intel 的开源图形驱动项目的带头人)的 GEM 介绍 中包含了一个已有 API 的描述文档。GEM 在处理上面有很多显着不同。首先 GEM 使用普通、匿名、用户空间内存来用于分配图形缓冲对象。这意味着这些缓冲区可以在必要的时候被交换出物理内存。这个方法有其显着的优越性,不仅仅是内存使用的灵活性:它让挂起和恢复的实现可以直接通过恢复所有缓冲对象的方式自动完成了。

GEM API 尽量避免将缓冲区到用户空间的映射。映射工作代价高昂而且而且带来了 CPU 与 GPU 之间的缓存一致性问题。所以,GEM 用简单的 read() 和 write() 调用来取代映射,访问缓冲区对象。或者,至少,在 GEM 开发者能给每个缓冲对象附加一个文件描述符的时候的处理方法。而内核不会那么轻易管理这么多文件描述符,这样,实际的 API 使用了不同的缓冲对象 handle 和一系列的 ioctl() 调用。

也就是说,GEM可能映射一个缓冲对象到用户空间。不过,用户空间的驱动必须显示地承担管理缓存一致性的责任。为此,有一组 ioctl() 调用用于管理缓冲的“域”;所谓“域”,本质上说就是描述了系统中的哪个组件拥有这块缓冲区并有权操作它。改变一个缓冲的域(两类域,其一用于读访问,而另一个是写)将会进行必要的缓存刷新。在某种意义上说,这个机制重现了流 DMA API,DMA API 中的 DMA 缓冲区的所有权就可以在 CPU 和 外设控制器之间交换。不必惊讶,他们解觉得也是类似的问题。

GEM API 不需要显示的屏蔽 (fence) 操作。相反,当 CPU 操作需要访问缓冲区的时候,如果必要的话 CPU 就会简单地等待 GPU 完成对该缓冲区的操作。

最后,GEM API 并没有想要独自解决所有问题;很多重要操作(比如执行一组 GPU 指令)被留给硬件特定的驱动来实现了。GEM 本身在目前非常适于 Intel 驱动的需求;它不需要达到所有的 TTM 所有达到的目标。Eric Anholt 描述 到:

TTM 的问题是它要对所有硬件提供一套统一的 API,即使我们的驱动不希望这样的时候也是如此……我们尽量从另一个方面来达到这一目的:实现一个驱动。当其他人实现了另一个驱动,又发现这里面有些代码应该是公共的,那么就将它移动到支撑库里并共享它。

这种方法的有点是更容易来给 Intel 新加入一些东西。而且这可能是个好的开始,一组工作的驱动总比没有强。另一方面,这也意味着要让 GEM 支持其它硬件的驱动还需要大量的工作。对于这些工作如何去做,目前大概有两种观点:(1) GEM 为新的驱动的需求增加新的能力,或者 (2) 让驱动使用它自己的内存管理器。

第一种方法在很多情况下看起来更漂亮。但它也预示着 GEM API 会经常发生很多变化。这可能会延缓整个系统进入主线内核的脚步;GEM API 会输出到用户空间,所以必须保持变化的兼容性。看起来必须要不断演进的 API 会在快速的进入主线内核的时候受到阻力。

而对于第二种方法,Dave Airlie 给出了最好的解释 :

嗯,事情是我不能相信我们还不足够知道如何以一种通用的方法来做到这点,不过 TTM vs GEM 可能已经证明了这是不可能的了。那么我们可以赌一赌每个驱动一个内存管理器,不过我怀疑这将成为一个维护的噩梦,所以如果人们决定了这就是下一步要走的,我会很高兴地看到他发生。不过提交第 n+1 个内存管理器的人必须解事情出接口后面的机制,而且解释清楚为什么不能复用内存管理器 1 到 n。

一个还没被讨论过的问题就是性能。Keith Whitwell 给出了一组评分结果 ,该结果显示对于 i915 驱动,使用 TTM 或 GEM 的时候,性能会比不使用的情况显着降低。而 Keith Packard 的到了不同的结果 ,他的结果显示 GEM 驱动的性能明显更好。显然,目前需要一组一致的 benchmark;图形性能是重要的,但如果不能有效地测量也就没法优化。

使用匿名内存也会引起一些性能考虑:如果第一人称射击游戏 (FPS) 的血腥像素们要不停地被换页的话,体验可能就不尽如人意了。匿名内存可以位于高位内存,而且这样就不必使用32位指针来访问。一些 GPU 硬件不能访问高位内存;这将可能影响 kernel 的 bounce buffer (不好意思啊,这个不知道怎么翻译好了)。最后,GEM 还需要去证明它可以提供良好的性能,GEM的开发者们非常主动地使他们的硬件看起来很好,这也让工作在上面的东西有了一个更好的机会。(这句话翻译的比较晕)

所有这些能得到的结论是GPU的内存管理问题还不能简单认为是已经解决了。GEM可能最终称为这个答案,但它还是非常新的API,仍然需要大量的工作。这个领域中似乎还有很多的工作需要做。

(感谢 Timo Jyrinki 建议这个话题。)

未经特殊声明,本站作品均为原创,同时会通过ifttt 转发至 本人 wordpress.com 博客,原则上不反对转载,但建议保留本文链接。

<think>好的,用户之前已经询问过关于GPU Linux内核模式开发所需的技能,现在他们又问了关于TTM内存管理器的介绍。我需要先回顾之前的对话,确保这次回答的一致性和连贯性。 首先,用户可能是在深入学习之前提到的技能点中的DRM框架和内存管理部分。他们可能正在研究GPU驱动开发,尤其是内存管理相关的知识。TTM作为DRM中的核心组件,用户需要了解其工作原理和应用场景。 接下来,我需要明确TTM的基本概念。TTM全称是Translation Table Maps,但更常见的是指DRM中的内存管理子系统。要解释清楚它的主要职责:显存管理、内存共享、异构内存支持等。同时,可能需要对比GEM,指出两者的区别和TTM的优势。 用户可能想知道TTM的具体结构,比如缓冲区对象、内存域、迁移机制等。这部分需要详细但清晰地解释,避免过于技术化,但又要涵盖关键点。例如,内存域中的VRAM、GTT、SYSTEM,这些是GPU内存管理中的常见概念。 然后,应用场景部分要举例说明,比如多GPU环境、交换机制、DMA映射等,这样用户能更好地理解TTM的实际用途。代码示例可以增强理解,比如展示TTM的初始化流程或缓冲区分配代码,但要注意不要太过复杂,保持简洁。 最后,对比TTMGEM,帮助用户理解为什么有些情况下选择TTM而不是GEM。可能需要提到TTM的灵活性和GEM的简洁性,以及不同项目中的选择依据。 用户可能的深层需求是希望在实际开发中应用TTM,或者解决内存管理中的问题。因此,需要强调TTM在复杂场景下的优势,以及学习TTM的建议步骤,如阅读内核文档、分析现有驱动等。 确保回答结构清晰,分点说明,使用代码块和示例来辅助解释。同时保持语言口语化,避免生硬的术语堆砌。检查技术细节的准确性,比如函数名和流程是否正确,避免误导用户。</think>TTM(Translation Table Maps)内存管理器是Linux DRM(Direct Rendering Manager)子系统中的核心内存管理模块,专为GPU等图形设备设计。以下从技术实现角度进行分层解析: --- ### **一、核心设计目标** 1. **异构内存统一管理** - 同时管理**显存(VRAM)**和**系统内存(RAM)** - 实现CPU/GPU内存空间的动态映射 - 支持NUMA架构下的非对称内存访问 2. **内存生命周期控制** ```c // 典型TTM缓冲区声明周期 ttm_bo_init() → ttm_bo_validate() → ttm_bo_unref() ``` --- ### **二、关键架构组件** 1. **缓冲区对象(Buffer Object)** - 基础数据结构: ```c struct ttm_buffer_object { struct drm_gem_object gem; // GEM兼容层 struct ttm_resource *resource; // 物理内存绑定 enum ttm_bo_type type; // 类型标识 }; ``` 2. **内存域(Memory Domain)** - `TTM_PL_VRAM`(显存) - `TTM_PL_TT`(GTT映射内存) - `TTM_PL_SYSTEM`(系统内存) 3. **迁移引擎** - 实现内存页的动态迁移(如:VRAM ↔ SYSTEM) - 基于LRU算法的自动交换机制 --- ### **三、核心工作机制** 1. **内存分配策略** ```c // 显存优先分配示例 struct ttm_place places[] = { { .flags = TTM_PL_FLAG_VRAM, .fpfn = 0, .lpfn = 0 }, { .flags = TTM_PL_FLAG_TT, .fpfn = 0, .lpfn = 0 } }; ttm_bo_validate(bo, &placement, &ctx); ``` 2. **地址空间管理** - 通过`ttm_bo_device`管理多个地址空间 - 支持每进程独立GPU虚拟地址空间 3. **内存回收机制** - 当显存不足时自动回退到GTT内存 - 使用`ttm_bo_swapout`守护进程管理内存压力 --- ### **四、关键技术特性** 1. **内存共享机制** - 通过DMA-BUF实现跨驱动共享 - 支持PRIME跨进程内存传递 2. **原子内存操作** ```c // 原子提交操作 struct drm_atomic_state *state; drm_atomic_helper_swap_state(dev->dev_private, state, true); ``` 3. **缓存一致性控制** - 通过`ttm_bo_kmap`实现CPU缓存映射 - 自动处理WC(Write-Combining)缓存策略 --- ### **五、典型应用场景** 1. **多GPU环境** - 实现不同GPU间的显存共享 - 支持PCIe BAR重映射 2. **大内存工作负载** - 动态交换超过物理显存容量的数据 - 4K/8K纹理处理 3. **计算加速** - 为OpenCL/CUDA计算提供统一内存视图 - 实现Zero-Copy数据传输 --- ### **六、与GEM的对比** | 特性 | TTM | GEM | |---------------------|------------------------------|-----------------------| | 内存类型支持 | 显存+系统内存+自定义域 | 仅系统内存 | | 迁移能力 | 支持动态页迁移 | 固定分配 | | 复杂度 | 高(20000+行核心代码) | 低(基础实现) | | 典型应用 | 独立显卡(AMD/NVIDIA) | 集成显卡(Intel) | --- ### **七、调试方法** 1. **状态监控** ```bash $ cat /sys/kernel/debug/dri/0/ttm_page_pool ``` 2. **内存泄漏检测** ```c # 内核配置开启CONFIG_DEBUG_KMEMLEAK ``` --- **学习建议**:从AMDGPU驱动代码(`drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c`)入手,重点研究`ttm_bo_validate`和`ttm_tt_populate`函数实现流程。实际开发中需特别注意内存域的锁定顺序,避免死锁发生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值