AMD KFD驱动技术分析16:SVM Aperture
1. 概述
在 ROCm 的 libhsakmt 内存管理体系中,dGPU共享虚拟内存(SVM)管理是高性能异构计算的核心。为满足不同类型的内存一致性需求,hsakmt 针对 dGPU SVM 设计了两种 aperture(地址空间管理器):dgpu_aperture
和 dgpu_alt_aperture
。这两者分别对应非一致性(non-coherent)和一致性(coherent)的 SVM 内存分配,底层实现和使用场景各有侧重。关于SVM的原理请参见:AMD KFD驱动技术分析11:SVM原理与核心概念。
本文将结合源码,系统梳理这两种 aperture 的设计、初始化流程、分配选择、典型应用、API 影响和底层实现细节。
2. 数据结构与基本定义
在 fmm.c 中,svm_t
结构体定义如下:
typedef struct {manageable_aperture_t apertures[SVM_APERTURE_NUM];manageable_aperture_t *dgpu_aperture;manageable_aperture_t *dgpu_alt_aperture;// ... 其他成员 ...
} svm_t;
-
apertures[SVM_APERTURE_NUM]
:数组,分别存储主 aperture(SVM_DEFAULT)和一致性 aperture(SVM_COHERENT)。 -
dgpu_aperture
:指向主 SVM aperture,通常用于非一致性(non-coherent)内存。 -
dgpu_alt_aperture
:指向一致性 SVM aperture,通常用于 coherent 内存。
这两者本质上都是 manageable_aperture_t
类型的指针,管理着不同的虚拟地址区间和分配策略。
3. 初始化流程对比
3.1 初始化入口
初始化流程主要在 init_svm_apertures()
和 init_mmap_apertures()
两个函数中完成,具体调用时机见 hsakmt_fmm_init_process_apertures()
。
3.1.1 典型流程(GFX8/GFX9+)
-
首先尝试通过
init_mmap_apertures()
直接映射整个 SVM 区间(GFX9+,支持 48 位地址空间)。 -
如果失败或平台不支持,则通过
init_svm_apertures()
预留一段大块虚拟地址空间,并手动管理。
3.2 地址空间划分
3.2.1 非一致性 aperture(dgpu_aperture)
-
对应
svm.apertures[SVM_DEFAULT]
。 -
地址空间为预留 SVM 区间的后 3/4(或全部,取决于平台)。
-
用于大多数普通 GPU 访问的 SVM 分配。
3.2.2 一致性 aperture(dgpu_alt_aperture)
-
对应
svm.apertures[SVM_COHERENT]
。 -
地址空间为预留 SVM 区间的前 1/4,且 64KB 对齐。
-
用于需要 CPU/GPU 一致性的特殊分配,如 doorbell、MMIO、AQL queue 等。
3.2.3 代码片段
// init_svm_apertures
alt_base = (HSAuint64)svm.apertures[SVM_DEFAULT].base;
alt_size = (VOID_PTRS_SUB(svm.apertures[SVM_DEFAULT].limit,svm.apertures[SVM_DEFAULT].base) + 1) >> 2;
alt_base = (alt_base + 0xffff) & ~0xffffULL;
alt_size = (alt_size + 0xffff) & ~0xffffULL;
svm.apertures[SVM_COHERENT].base = (void *)alt_base;
svm.apertures[SVM_COHERENT].limit = (void *)(alt_base + alt_size - 1);
// ...
svm.dgpu_aperture = &svm.apertures[SVM_DEFAULT];
svm.dgpu_alt_aperture = &svm.apertures[SVM_COHERENT];
对于 GFXv9 及以后平台,SVM 地址空间覆盖整个 48 位虚拟地址空间,coherent 与 non-coherent 的 MType 不再依赖 aperture 区分,dgpu_aperture
和 dgpu_alt_aperture
可能指向同一个 aperture。
4. aperture的选择
4.1 普通 SVM 分配
选择 dgpu_aperture
。适用于大多数 GPU kernel 访问、普通 device memory 分配。代码示例:
if (hsakmt_topology_is_svm_needed(gpu_mem[gpu_mem_id].EngineId)) {aperture = svm.dgpu_aperture;// ...
}
4.2 需要一致性的特殊分配
选择 dgpu_alt_aperture。
典型场景包括:
-
Doorbell 分配(
hsakmt_fmm_allocate_doorbell
) -
MMIO 映射(
map_mmio
) -
AQL queue 分配
-
需要 CPU/GPU cache 一致性的 buffer
示例代码:
aperture = svm.dgpu_alt_aperture;
ioc_flags = KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL | ...;
mem = __fmm_allocate_device(gpu_id, NULL, MemorySizeInBytes, aperture, ...);
-
hsakmt_fmm_allocate_device
、hsakmt_fmm_allocate_host
等 API 内部会根据HsaMemFlags
和分配类型自动选择合适的 aperture。 -
CoarseGrain
/FineGrain
、AQLQueueMemory
、Doorbell
等 flag 影响 aperture 选择。
5. 底层实现与管理策略
5.1 aperture 的管理结构
每个 aperture 都是一个 manageable_aperture_t
,内部维护:
-
base
/limit
:虚拟地址区间 -
align
/guard_pages
:对齐和保护页 -
vm_ranges
:已分配区间左对齐链表 -
tree
/user_tree
:红黑树,追踪分配对象 -
fmm_mutex
:互斥锁,保证并发安全 -
is_cpu_accessible
:是否可被 CPU 访问 -
ops
:分配/释放函数指针(reserved 或 mmap)
5.2 分配与释放流程
-
分配时,先锁定 aperture,查找合适的空闲区间,分配后插入红黑树。
-
释放时,移除对象,回收区间,必要时调用底层驱动释放物理内存。
5.3 地址空间隔离
-
dgpu_aperture
和dgpu_alt_aperture
地址空间严格隔离,避免冲突。 -
dgpu_alt_aperture
采用 64KB 对齐,适合硬件一致性需求。
6. 典型应用场景对比
场景 | 选择 aperture | 说明 |
---|---|---|
普通 device memory/SVM分配 | dgpu_aperture | 非一致性,适合大多数 GPU kernel 访问 |
Doorbell/AQL queue/MMIO | dgpu_alt_aperture | 需要 CPU/GPU cache 一致性,硬件要求 64KB 对齐 |
FineGrain buffer | dgpu_alt_aperture | 需要一致性,适合 host/device 频繁交互 |
CoarseGrain buffer | dgpu_aperture | 仅 device 访问,性能优先 |
GFXv9+ 平台 | 两者可能合并 | MType 不再依赖 aperture,分配策略更灵活 |
7.总结
-
dgpu_aperture
和dgpu_alt_aperture
是 ROCm dGPU SVM 内存管理的核心机制,分别服务于非一致性和一致性内存需求。 -
初始化时严格划分地址空间,分配时根据 flag 和用途自动选择,保证了高效与灵活。
-
开发者在进行高性能 GPU 计算、驱动开发或系统调优时,应理解两者的区别和适用场景,合理利用一致性 aperture 提升数据交互效率。
-
推荐在调试和性能分析时,关注 aperture 的分配策略、对齐要求和底层日志输出。