AMD KFD的BO设计分析系列6-3: res_cursor--BO物理内存资源的迭代器

res_cursor:BO物理内存迭代器解析

这篇文章讲一下AMD中设计的amdgpu_res_cursoramdgpu_res_cursor 是 AMDGPU 驱动资源管理中的重要抽象,专为分块资源的遍历和操作而设计。

1. 背景与设计目的

在现代 GPU 驱动架构中,显存和系统内存的分配、管理、映射是高性能图形渲染和异构计算的基础。AMDGPU 驱动基于 TTM框架,采用多层次的资源管理器(如 VRAM 管理器、GTT 管理器)来管理物理内存资源。由于显存分配往往是分块(block)或分段(node)进行的,实际的物理资源可能由多个不连续的区间组成。

在进行页表填充、DMA 映射、数据清零等操作时,驱动需要遍历这些分块资源,并将其与虚拟地址空间进行映射。amdgpu_res_cursor 就是为此设计的一个通用游标(cursor)结构体和操作接口,方便在 VRAM/GTT/DOORBELL 等不同类型的资源分配器中遍历和操作分块资源。也可以看作物理内存资源集合的迭代器。

2. 结构体定义与成员功能

struct amdgpu_res_cursor {
    uint64_t		start;      // 当前块的物理起始地址
    uint64_t		size;       // 当前块的大小(字节)
    uint64_t		remaining;  // 剩余待遍历的总大小
    void			*node;      // 指向当前块(block/node)的指针
    uint32_t		mem_type;   // 当前资源类型(VRAM/GTT/DOORBELL)
};
  • start:当前遍历到的物理块的起始地址(以字节为单位),用于后续页表填充或数据操作。

  • size:当前块的大小,决定本次操作能覆盖的字节数。

  • remaining:本次遍历还剩下多少字节未处理,便于循环和终止条件判断。

  • node:指向当前物理块的结构体指针(如 drm_buddy_block 或 drm_mm_node),用于获取块的详细信息。

  • mem_type:资源类型,决定遍历和块处理的方式。常见值有 TTM_PL_VRAM、TTM_PL_TT、AMDGPU_PL_DOORBELL。

3. 核心操作接口与实现

3.1 初始化游标:amdgpu_res_first

static inline void amdgpu_res_first(struct ttm_resource *res,
                    uint64_t start, uint64_t size,
                    struct amdgpu_res_cursor *cur);
  • 功能:初始化游标,准备遍历指定资源对象(如 VRAM/GTT)的分块区间。

  • 实现思路:

    • 判断资源类型(mem_type),选择合适的分块链表或节点数组。

    • 跳过前面的块,定位到起始地址对应的块。

    • 设置游标的 start、size、remaining、node 等成员,准备后续遍历。

VRAM场景
  • 遍历 amdgpu_vram_mgr_resource 的 blocks 链表,定位到起始块。

  • 计算块内偏移,设置游标。

GTT/DOORBELL场景
  • 遍历 ttm_range_mgr_node 的 mm_nodes 数组,定位到起始节点。

  • 计算节点内偏移,设置游标。

Fallback场景
  • 如果资源类型不支持或资源为空,游标直接指向整个区间,node 设为 NULL。

3.2 游标前进:amdgpu_res_next

static inline void amdgpu_res_next(
        struct amdgpu_res_cursor *cur, uint64_t size);
  • 功能:将游标向前移动指定字节数,自动跳转到下一个块或节点。

  • 实现思路:

    • 更新 remaining 和当前块的 size。

    • 如果当前块还有剩余空间,则只移动 start 和 size。

    • 如果当前块用完,则跳转到下一个块或节点,重新设置 start、size、node。

    • 支持 VRAM、GTT、DOORBELL等多种资源类型。

3.3 块清零检测:amdgpu_res_cleared

static inline bool amdgpu_res_cleared(
          struct amdgpu_res_cursor *cur);
  • 功能:检测当前块是否已经被清零(如分配时已初始化为0)。

  • 实现思路:

    • 仅支持 VRAM 类型,通过 amdgpu_vram_mgr_is_cleared 检查块状态。

    • 其他类型默认返回 false。

4. 应用场景与示例

4.1 页表填充(PTE设置)

在 BO 映射到 GPU 虚拟地址空间时,驱动需要将物理块的地址填充到页表项(PTE),实现虚拟地址到物理地址的映射。由于 BO 可能由多个物理块组成,驱动可用 amdgpu_res_cursor 遍历所有块,逐块填充页表。

示例流程:

struct amdgpu_res_cursor cur;
amdgpu_res_first(res, start_offset, total_size, &cur);

while (cur.remaining) {
    // 填充页表项,将 cur.start 映射到虚拟地址
    set_pte(vm, vaddr, cur.start, cur.size, flags);

    // 前进到下一个块
    amdgpu_res_next(&cur, cur.size);
}

4.2 DMA 映射与数据传输

在进行 DMA 操作(如显存清零、数据拷贝)时,驱动需要遍历所有物理块,将每个块的物理地址传递给 DMA 引擎。amdgpu_res_cursor 可用于高效遍历和分块操作。

示例流程:

struct amdgpu_res_cursor cur;
amdgpu_res_first(res, 0, bo_size, &cur);

while (cur.remaining) {
    dma_map(cur.start, cur.size);
    amdgpu_res_next(&cur, cur.size);
}

4.3 块清零检测与优化

在分配显存时,部分块可能已被硬件清零,无需再次初始化。驱动可用 amdgpu_res_cleared 检查块状态,跳过已清零块,提升性能。

示例流程:

struct amdgpu_res_cursor cur;
amdgpu_res_first(res, 0, bo_size, &cur);

while (cur.remaining) {
    if (!amdgpu_res_cleared(&cur))
        memset_io(cur.start, 0, cur.size);
    amdgpu_res_next(&cur, cur.size);
}

5. 总结

amdgpu_res_cursor 是对 TTM/AMDGPU 资源分块管理的进一步抽象,专注于遍历和操作分块资源。在涉及分块资源遍历的场景(如页表填充、DMA映射)优先使用 amdgpu_res_cursor,避免手动循环和边界判断。优点总结如下:

  1. 统一抽象:用一个游标结构体和接口,统一遍历多种资源类型,简化驱动代码。

  2. 高效分块遍历:支持分块、分段资源的高效遍历,适应显存分配的实际需求。

  3. 灵活偏移与区间支持:支持任意起始偏移和区间大小,便于处理部分映射、分段操作等复杂场景。

  4. 自动跳转与终止:自动处理块跳转和终止条件,减少手动循环和边界判断。

  5. 扩展性强:可扩展支持更多资源类型和块属性(如清零、压缩等)。

看似该结构体没有特别之处,但结合前面文章AMD KFD的BO设计分析系列6-1: VRAM BO的显存分配分析中分配物理显存的blocks,会对该结构体的重要性有一个直观的认识,在AMD VM中实现VA到PA映射时,就使用了这个cursor。


技术交流,欢迎加入社区:GPUers

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeeplyMind

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值