AMD KFD的BO设计分析系列6-1: VRAM BO的显存分配分析

前文:AMD KFD的BO设计分析系列6: BO的物理地址部分-PM概述了BO物理空间的核心结构体间的关系,根据分配位置的不同,使用不同的管理器来实现物理空间的分配。本文介绍的AMD 的 VRAM 管理器(amdgpu_vram_mgr)负责为BO分配具体的设备内存(VRAM),重点分析TTM 框架下 ttm_resource 物理地址分配的代码实现,重点关注 VRAM 分配流程和物理地址的确定。

1. TTM资源分配的入口

在 TTM 框架中,ttm_resource 代表 BO实际分配到的物理内存资源。对于 VRAM 类型的 BO,分配流程由 VRAM 管理器实现,核心入口是:

cpp 复制代码
static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
                               struct ttm_buffer_object *tbo,
                               const struct ttm_place *place,
                               struct ttm_resource **res);

该函数负责为 BO 分配 VRAM,并初始化 ttm_resource 结构体。AMD扩展的相关结构体如下,一个manager,一个resource。

cpp 复制代码
struct amdgpu_vram_mgr {
    struct ttm_resource_manager manager;   // TTM资源管理器,用于统一管理显存资源
    struct drm_buddy mm;                   // buddy分配器,负责VRAM物理地址空间的分配
    struct mutex lock;                     // 互斥锁,保护缓冲区对象的并发访问
    struct list_head reservations_pending; // 等待处理的预留请求链表
    struct list_head reserved_pages;       // 已预留页的链表
    atomic64_t vis_usage;                  // 记录CPU可见VRAM的使用量
    u64 default_page_size;                 // 默认分配页大小
};

struct amdgpu_vram_mgr_resource {
    struct ttm_resource base;              // TTM资源结构体,描述分配到的物理资源
    struct list_head blocks;               // 分配到的buddy块链表,每块代表一段物理地址区间
    unsigned long flags;                   // 资源属性标志(如已清零、分配策略等)
};

2. 分配流程详解

2.1 参数准备与资源结构体分配

  • 获取 VRAM 管理器和设备指针。

  • 分配 amdgpu_vram_mgr_resource(继承自 ttm_resource),用于描述分配到的物理资源。

  • 初始化资源结构体,设置分配大小、flags等。

2.2 分配物理地址区间

  • 通过 drm_buddy_alloc_blocks 在 VRAM 地址空间分配物理块(block),每个 block 代表一段物理地址区间。

  • 支持多种分配策略(如连续分配、TOPDOWN、DCC对齐等),根据 BO 的 flags 和 place 参数决定分配方式。

  • 分配结果以 block 链表形式存储在 vres->blocks

2.3 物理地址的确定

  • 每个 block 的起始物理地址通过 amdgpu_vram_mgr_block_start(block) 获取,大小通过 amdgpu_vram_mgr_block_size(block) 获取。

  • 分配完成后,遍历所有 block,确定资源的物理地址区间。

  • ttm_resourcestart 字段通常记录分配的首个页帧号(PFN),而实际物理地址由 block 的 start 字段决定。

2.4 资源结构体与物理地址绑定

  • ttm_resource 结构体通过 amdgpu_vram_mgr_resource 关联到分配的 block 链表。

  • BO 通过 bo->tbo.resource 指向该资源结构体,从而间接获得物理地址信息。

可以看出,vram的分配最终是使用了drm框架的分配函数drm_buddy_alloc_blocks,这是一个在前面文章中没有涉及的概念。下面重点讲解。

3. drm_buddy物理显存分配器

drm_buddy是drm框架提供的物理显存分配器。drm_buddy_alloc_blocks 是drm 框架下用于分配显存等大块物理内存的核心分配器接口,采用 buddy 算法实现高效的内存管理。它广泛应用于 amdgpu_vram_mgr 等显存管理器,为 BO(Buffer Object)分配物理地址区间。下面详细分析其实现原理和流程:

cpp 复制代码
int drm_buddy_alloc_blocks(struct drm_buddy *mm,
                           u64 start, u64 end, u64 size,
                           u64 min_block_size,
                           struct list_head *blocks,
                           unsigned long flags)
  • mm:buddy 管理器实例,管理整个物理地址空间。

  • start/end:允许分配的物理地址范围(通常由 fpfn/lpfn 约束)。

  • size:需要分配的总字节数。

  • min_block_size:分配块的最小对齐(通常为页或更大)。

  • blocks:输出链表,存储分配到的 block。

  • flags:分配策略(如连续分配、TOPDOWN、RANGE等)。

3.1 参数校验

函数首先对参数进行严格校验,确保分配范围、对齐、大小等合法:

  • sizemin_block_size 必须大于等于 chunk_size(最小分配单位)。

  • min_block_size 必须是 2 的幂。

  • startendsize 必须按 chunk_size 对齐。

  • end 不能超过管理器的总空间。

  • 检查分配区间不会溢出。

3.2 分配策略选择

根据参数和 flags,选择不同的分配策略:

  1. 严格区间分配(RANGE)

    如果 start + size == end,表示分配必须完全落在指定区间,调用 __drm_buddy_alloc_range,遍历树结构分配。

  2. 连续分配(CONTIGUOUS)

    如果要求分配连续物理块,则将 size 向上取整为 2 的幂,并将 min_block_size 设为 size。

  3. 普通分配

    如果没有特殊要求,则按最小块对齐分配。

3.3 分配主流程

  1. **计算分配 order:**计算分配块的 order(即块大小的 log2),用于 buddy 算法分配合适大小的块。

  2. 循环分配: 按需分配多个 block,直到满足 size。每次分配调用 __drm_buddy_alloc_blocks,根据策略选择区间分配或从 freelist 分配。如果实际分配的块大于请求 size(如连续分配时),会调用 drm_buddy_block_trim 修剪多余部分,释放未使用的空间。

  3. **分配失败处理:**如果分配失败,尝试合并空闲块(force merge),或采用"try harder"策略分配更大的块。如果仍然失败,则释放已分配的块并返回错误。

  4. 分配成功处理: 标记分配的 block 为已分配状态并更新管理器的可用空间。所有分配到的 block 以链表形式输出到 blocks,每个 block 记录物理地址(offset)、大小(block_size)等信息。上层管理器(amdgpu_vram_mgr)会遍历这些 block,填充到 BO 的物理地址映射中。

3.4 算法核心特点

  • Buddy 算法:通过二叉树分割和合并空闲块,实现高效的内存分配和回收,减少碎片。

  • 区间约束:支持严格的物理地址范围限制,满足显存分区、可见性等需求。

  • 多策略支持:支持连续分配、TOPDOWN分配、普通分配等多种策略,灵活适应不同场景。

  • 高效修剪:分配后可修剪多余空间,提升空间利用率。

4. 总结

  • TTM 的物理地址分配由资源管理器(如 amdgpu_vram_mgr)实现,核心是通过 buddy allocator 在 VRAM 地址空间分配物理块。

  • 每个 ttm_resource 结构体通过 block 链表记录分配到的物理地址区间,BO 通过 resource 指针间接访问物理地址。


如有帮助,请三连:点赞、收藏、加关注。

相关推荐
我言秋日胜春朝★3 小时前
【Linux网络编程】多路转接reactor——ET模式的epoll
linux·服务器·网络
Hell_Yrz4 小时前
Golang信号处理实战
linux
四桑.4 小时前
uniapp运行微信小程序uni为什么是undefined
linux
用户31187945592185 小时前
perl-Test-Simple-1.302195-5.fc39.noarch.rpm 怎么安装?Fedora 39 安装步骤讲解
linux
焦思懿--19期--工职大5 小时前
VMWare和物理机之间文件传输
linux·服务器·网络·电脑
四桑.5 小时前
echarts6.0.0版本,平行坐标图形,series为多组时,横线溢出绘图区域,如何解决
linux
qq_323429715 小时前
银河麒麟V10高级服务器版Bash快捷键经常失效
linux
Mr. Cao code7 小时前
Dockerfile 指令详解与实战指南
linux·运维·ubuntu·docker·容器
foundbug9997 小时前
查看nginx日志文件
linux·nginx·github