AMDGPU 基于DRM SVM框架的新SVM功能实现 :属性子系统结构体关系解析

AMD 正在使用 drm svm框架重构SVM的实现,看来drm svm框架要进入大范围应用了。下面是在kernel社区上由AMD的开发人员提交的POC 验证版本的patches的技术方案实现。这里快速总结了实现,以飨读者。

因是POC版本,设计可能会变动,读者们慎重使用。本文仅用来跟踪前沿驱动技术的迭代发展现状。


1. 整体架构

复制代码
用户空间 (UAPI)                          内核空间 (attr 管理)                      内核空间 (SVM 核心)
┌───────────────────┐                   ┌──────────────────────┐                ┌──────────────────┐
│drm_amdgpu_gem_svm │  ioctl            │ amdgpu_svm_attr_tree │                │   amdgpu_svm     │
│  start_addr       │──SET/GET─────────▶│   lock (mutex)       │◄────────────── │   attr_tree      │
│  size             │                   │   tree (rb_root)     │                │   gpusvm         │
│  nattr            │                   │   range_list         │                │   adev, vm ...   │
│  attrs_ptr ───────┤                   └─────┬────────────────┘                └──────────────────┘
│                   │                         │ 包含 N 个                               │
│  ┌────────────────┤                         ▼                                        │ 包含 N 个
│  │drm_amdgpu_svm_ │                   ┌──────────────────────┐                ┌──────┴───────────┐
│  │  attribute     │   转换为           │amdgpu_svm_attr_range │                │amdgpu_svm_range  │
│  │  type (u32)    │────────────────▶  │  it_node (区间树)     │   查询 attrs    │  base (gpusvm)   │
│  │  value (u32)   │                   │  list (链表)          │◄────────────── │  pte_flags       │
│  └────────────────┘                   │  attrs ──────────────┤                │  attr_flags      │
│                                       │    preferred_loc     │                │  gpu_mapped ...  │
│                                       │    prefetch_loc      │                └──────────────────┘
│                                       │    flags             │
│                                       │    granularity       │
│                                       │    access (enum)     │
│                                       └──────────────────────┘

2. 各结构体解析

2.1 amdgpu_svm_attrs --- 属性值集合(Value Object)

c 复制代码
struct amdgpu_svm_attrs {
    int32_t preferred_loc;              // 首选内存位置: GPU ID / SYSMEM(0) / UNDEFINED(0xffffffff)
    int32_t prefetch_loc;               // 预取位置
    uint32_t flags;                     // 位标志组合 (COHERENT, GPU_RO, GPU_EXEC 等)
    uint32_t granularity;               // 映射粒度
    enum amdgpu_svm_attr_access access; // NONE / ENABLE / IN_PLACE
};

纯数据容器,没有指针 ,可以直接拷贝。它把用户空间的多个离散
drm_amdgpu_svm_attribute(type/value 对)聚合成一个完整的属性快照。

2.2 amdgpu_svm_attr_range --- 区间-属性映射节点

c 复制代码
struct amdgpu_svm_attr_range {
    struct interval_tree_node it_node;  // ← 嵌入区间树,key=[start, last] 页号
    struct list_head list;              // ← 链入 attr_tree->range_list 有序链表
    struct amdgpu_svm_attrs attrs;      // ← 嵌入属性值
};

双索引结构:同一个节点同时存在于两个数据结构中:

索引方式 数据结构 用途
it_node 区间红黑树 (rb_root_cached) O(log n) 按地址范围查询
list 有序链表 (range_list) O(n) 顺序遍历、合并相邻同属性区间

这是内核中常见的"同一对象多索引"模式(类似 VMA 同时在 mm->mm_rb
mm->mmap 中)。

2.3 amdgpu_svm_attr_tree --- 属性管理器(容器)

c 复制代码
struct amdgpu_svm_attr_tree {
    struct mutex lock;                  // 保护下面两个数据结构
    struct rb_root_cached tree;         // ← attr_range 的区间红黑树根
    struct list_head range_list;        // ← attr_range 的有序链表头
    struct amdgpu_svm *svm;             // ← 回指所属 SVM 实例
};

每个 SVM 实例一个 attr_tree,管理该进程(fd)所有地址范围的属性。

2.4 amdgpu_svm_attr_change_trigger --- 变更分类枚举

c 复制代码
enum amdgpu_svm_attr_change_trigger {
    ACCESS_CHANGE       = (1U << 0),   // access 级别变了 → 可能需要 unmap/remap
    PTE_FLAG_CHANGE     = (1U << 1),   // GPU PTE flags 变了 → 需要重建 PTE
    MAPPING_FLAG_CHANGE = (1U << 2),   // 映射策略变了 → 可能影响缓存一致性
    LOCATION_CHANGE     = (1U << 3),   // 首选位置变了 → 可能触发迁移
    GRANULARITY_CHANGE  = (1U << 4),   // 粒度变了 → 需要拆分/合并 range
    ATTR_ONLY           = (1U << 5),   // 只更新属性,不影响 GPU 映射
};

位掩码设计,允许一次 set_attr 操作同时触发多种变更。


3. 属性标志分类

amdgpu_svm_attrs.flags 中的标志位按作用范围分为两组:

PTE 级标志(影响 GPU 页表条目)

c 复制代码
#define AMDGPU_SVM_PTE_FLAG_MASK \
    (AMDGPU_SVM_FLAG_COHERENT | AMDGPU_SVM_FLAG_EXT_COHERENT | \
     AMDGPU_SVM_FLAG_GPU_RO | AMDGPU_SVM_FLAG_GPU_EXEC)
标志 含义
COHERENT 0x02 GPU-CPU 缓存一致性
EXT_COHERENT 0x80 跨节点扩展一致性
GPU_RO 0x08 GPU 只读访问
GPU_EXEC 0x10 GPU 可执行

映射级标志(影响映射策略)

c 复制代码
#define AMDGPU_SVM_MAPPING_FLAG_MASK \
    (AMDGPU_SVM_FLAG_HOST_ACCESS | AMDGPU_SVM_FLAG_HIVE_LOCAL | \
     AMDGPU_SVM_FLAG_GPU_READ_MOSTLY | AMDGPU_SVM_FLAG_GPU_ALWAYS_MAPPED)
标志 含义
HOST_ACCESS 0x01 允许 CPU 访问设备内存
HIVE_LOCAL 0x04 限制在 XGMI hive 内
GPU_READ_MOSTLY 0x20 读多写少优化
GPU_ALWAYS_MAPPED 0x40 始终保持 GPU 映射

4. 数据流

复制代码
用户调用 ioctl(AMDGPU_SVM_OP_SET_ATTR)
  │
  ▼
drm_amdgpu_svm_attribute[] (type/value 对数组)
  │
  ▼  amdgpu_svm_attr_set()
  │
  ├─▶ 解析为 amdgpu_svm_attrs (聚合所有 type/value)
  │
  ├─▶ 在 attr_tree 中插入/拆分/合并 amdgpu_svm_attr_range
  │   (区间树 + 链表同步维护)
  │
  ├─▶ 计算 trigger 位掩码 (哪些属性变了)
  │
  └─▶ 通知 svm_range 层:amdgpu_svm_range_apply_attr_change()
        │
        ▼
      根据 trigger 决定:重建 PTE / 迁移 VRAM / 销毁重建 range

5. 关键设计:属性层与映射层解耦

attr_rangesvm_range独立的区间覆盖,粒度不同:

复制代码
地址空间:    0          4K         8K         12K        16K
attr_range:  |←── preferred=GPU, flags=COHERENT ──────────→|  (一个大区间)

svm_range:   |← range1 →|← range2 →|         |← range3 →|   (按 fault 按需创建)
             (已映射)     (已映射)    (无fault) (已映射)
  • attr_range :由用户 set_attr 显式创建,覆盖用户声明的整个地址范围
  • svm_range:由 GPU page fault 按需创建,只覆盖实际被 GPU 访问的页
  • svm_range 需要知道某个页的属性时,调用
    amdgpu_svm_attr_lookup_page_locked() 查询 attr_tree

这种解耦的好处:

场景 优势
用户声明 1GB 范围的属性 attr_tree 只存一个节点(O(1) 空间)
只有 4KB 被 GPU 访问 svm_range 只创建一个 4KB 范围
用户修改属性 只更新 attr_range,通知 svm_range 按需调整
GPU fault 新地址 svm_range 查询 attr_tree 获取属性

6. 内存中的对象层次

复制代码
amdgpu_device (GPU 设备)
  └── amdgpu_vm (每个进程一个)
        └── amdgpu_svm (每个 fd/vm 一个)
              ├── drm_gpusvm gpusvm
              │     └── drm_gpusvm_notifier[]
              │           └── drm_gpusvm_range[] ← amdgpu_svm_range.base
              │
              └── amdgpu_svm_attr_tree *attr_tree
                    ├── rb_root_cached tree ─────────┐
                    └── list_head range_list ─────────┤
                                                      ▼
                                               amdgpu_svm_attr_range
                                                 ├── it_node (in tree)
                                                 ├── list (in range_list)
                                                 └── attrs (属性值)

7. UAPI 到内核属性的转换

用户空间通过 drm_amdgpu_svm_attribute 数组传递离散的 type/value 对:

c 复制代码
// 用户空间
struct drm_amdgpu_svm_attribute attrs[] = {
    { .type = AMDGPU_SVM_ATTR_PREFERRED_LOC, .value = gpu_id },
    { .type = AMDGPU_SVM_ATTR_SET_FLAGS,     .value = AMDGPU_SVM_FLAG_COHERENT },
    { .type = AMDGPU_SVM_ATTR_ACCESS,        .value = gpu_id },
};

内核在 amdgpu_svm_attr_set() 中将其聚合为一个 amdgpu_svm_attrs

UAPI type attrs 字段
ATTR_PREFERRED_LOC preferred_loc = value
ATTR_PREFETCH_LOC prefetch_loc = value
ATTR_ACCESS access = ENABLE
ATTR_ACCESS_IN_PLACE access = IN_PLACE
ATTR_NO_ACCESS access = NONE
ATTR_SET_FLAGS `flags
ATTR_CLR_FLAGS flags &= ~value
ATTR_GRANULARITY granularity = value
相关推荐
DeeplyMind5 天前
drm_gpusvm_pages — svm range物理页面映射状态管理者的实现详细分析
drm_gpusvm·gpusvm_pages
DeeplyMind2 个月前
附录A:AMDGPU SVM 属性类型
kfd·amdgpu svm
DeeplyMind2 个月前
02 - SVM相关的Linux内核基础
hmm·rocm·kfd·共享虚拟内存·amdgpu svm