1. 引言
前面的几篇文章在原理上进行了啰里啰嗦的讲述,本篇给出AMDGPU的具体实现,来看下大厂的应用案例。
AMDGPU 作为 AMD 显卡的开源驱动,采用了多层次的内存管理机制。其中,amdgpu_bo_create 是分配和初始化 GPU Buffer Object(BO,缓冲区对象)的核心函数。该函数的实现离不开对显存(VRAM)、GTT(Graphics Translation Table,通常指系统内存映射到 GPU)等地址空间的精细管理。而在这些地址空间的分配与回收过程中,drm_mm 和 drm_mm_node 这两个数据结构起到了基础且关键的作用。
本文将围绕 amdgpu_bo_create 的实现流程,详细剖析 drm_mm 和 drm_mm_node 在其中的具体调用点、作为drm_mm应用的重要用例来理解drm_mm 和drm_mm_node 。
2. amdgpu_bo_create 的实现流程
amdgpu_bo_create 是 AMDGPU 驱动中用于创建 buffer object(BO,缓冲区对象)的核心函数。它负责分配和初始化显存或系统内存中的一块区域,并返回一个 BO 句柄,供 GPU 或用户空间使用。其实现大致分为以下几个阶段:
-
参数校验与对象分配
检查输入参数的合法性,分配并初始化amdgpu_bo结构体。 -
内存类型与放置策略选择
根据调用者需求(如分配 VRAM、GTT 或系统内存)设置 TTM(Translation Table Maps)框架的placement策略。 -
内存资源分配
通过 TTM 框架调用底层分配函数,为 BO 分配实际的物理内存资源。对于 VRAM 或 GTT 类型,最终会调用到amdgpu_ttm_alloc或类似函数。 -
地址空间管理
对于 VRAM 或 GTT 类型的 BO,AMDGPU 驱动会使用drm_mm管理显存/GTT 地址空间。分配时会调用drm_mm_insert_node,为 BO 分配一段地址空间,并用drm_mm_node记录。 -
初始化和注册
完成 BO 的初始化,将其注册到全局或设备的 BO 管理链表中,便于后续查找和管理。
在上述流程中,第4步“地址空间管理” 是 drm_mm 和 drm_mm_node 发挥作用的核心环节。
3. drm_mm 和 drm_mm_node 在 amdgpu_bo_create 中的调用
3.1 地址空间的分配
当 amdgpu_bo_create 需要为 BO 分配 VRAM 或 GTT 区域时,必须确保所分配的内存区间在整个地址空间中是唯一且不重叠的。此时,AMDGPU 驱动会调用 drm_mm_insert_node,在对应的 drm_mm 管理器中分配一段合适的区间。
以 VRAM 为例,AMDGPU 驱动会维护一个 adev->vram_mgr.mm 的 drm_mm 实例,代表整个显存的地址空间。每次分配 BO 时,驱动会:
-
先分配一个
drm_mm_node结构体,用于记录本次分配的区间信息。 -
调用
drm_mm_insert_node,在drm_mm管理器中查找一段满足大小和对齐要求的空闲区间,并将其分配给该drm_mm_node。 -
将分配到的
drm_mm_node记录到amdgpu_bo结构体中,便于后续操作。
代码片段示意(伪代码):
struct drm_mm_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
ret = drm_mm_insert_node(&adev->vram_mgr.mm, node, size, alignment, ...);
bo->node = node;
3.2 地址空间的释放
当 BO 不再需要时(如被销毁或回收),驱动需要将其占用的地址空间归还给全局管理器。此时会调用:
-
drm_mm_remove_node(bo->node),将该区间从drm_mm管理器中移除,标记为可用。 -
释放
drm_mm_node结构体本身。
代码片段示意:
drm_mm_remove_node(bo->node);
kfree(bo->node);
3.3 地址空间的查询与映射
在后续的内存映射、DMA 操作、页表建立(参见博文:AMD KFD的BO设计分析系列3-3)等场景中,驱动可以通过 amdgpu_bo 结构体中的 drm_mm_node 成员,快速获取该 BO 在物理地址空间中的起始地址和长度。这对于 GPU 访问、用户空间映射、同步等操作都至关重要。
4. drm_mm 和 drm_mm_node 的作用与意义
4.1 避免区间重叠,保证分配唯一性
drm_mm 作为一个区间分配器,能够高效地管理一段连续的地址空间。每次分配时,drm_mm_insert_node 会遍历所有已分配的节点,确保新分配的区间不会与现有区间重叠。这种机制极大地简化了显存、GTT 等资源的分配逻辑,避免了手动管理区间带来的复杂性和错误风险。
4.2 支持多种分配策略
drm_mm 支持多种分配策略,如最先适应(first-fit)、最佳适应(best-fit)等。AMDGPU 驱动可以根据实际需求,选择不同的分配策略,以优化内存利用率和分配速度。例如,对于大块 VRAM 分配,可以优先选择最先适应策略,以减少碎片。
4.3 高效的释放与合并
当某个 BO 被释放时,drm_mm_remove_node 会自动将其对应的区间标记为可用,并尝试与相邻的空闲区间合并,减少碎片。这种自动合并机制有助于长期运行时保持地址空间的连续性,提高大块内存分配的成功率。
4.4 便于后续操作的区间查询
每个 drm_mm_node 结构体都记录了分配区间的起始地址、长度等信息。驱动可以通过这些信息,快速完成物理地址到虚拟地址的映射、DMA 传输、页表建立等操作。例如,在实现 mmap 回调时,可以直接使用 drm_mm_node 中的起始地址作为物理页帧号,调用 io_remap_pfn_range 完成用户空间映射。
4.5 支持多种地址空间的统一管理
AMDGPU 驱动不仅需要管理 VRAM,还需要管理 GTT、系统内存等多种地址空间。通过为每种地址空间维护一个独立的 drm_mm 实例,驱动可以实现统一的分配与回收接口,极大地提升了代码的可维护性和扩展性。
4.6 与 TTM 框架的协作
虽然 TTM 框架负责更高层次的内存管理(如内存迁移、页表管理等),但底层的物理地址空间分配仍然依赖于 drm_mm。TTM 在分配内存资源时,会调用驱动提供的分配回调(如 amdgpu_ttm_alloc),而这些回调最终会使用 drm_mm 进行实际的区间分配。
这种分层设计使得 TTM 可以专注于内存对象的生命周期管理和跨设备迁移,而具体的物理地址空间分配则交由 drm_mm 负责,实现了职责分离和高效协作。
5. 总结
drm_mm 和 drm_mm_node 是 AMDGPU 驱动实现高效、可靠内存管理的基石。在 amdgpu_bo_create 的实现过程中,它们承担了地址空间分配、区间唯一性保证、碎片管理、区间查询等多项关键任务。通过与 TTM 框架的协作,drm_mm 实现了多种内存类型的统一管理,极大地提升了驱动的健壮性和可维护性。
技术交流,欢迎加入社区:GPUers。
1451

被折叠的 条评论
为什么被折叠?



