1. 背景与原理
在AMD ROCm平台的内存管理中,SVM(Shared Virtual Memory)允许CPU和GPU共享统一的虚拟地址空间。init_svm_apertures函数负责初始化SVM地址空间(aperture),以便后续的内存分配和映射操作。该函数支持两种模式:
-
mmap模式:直接利用操作系统的虚拟地址分配能力,适用于GFXv9及以上架构,虚拟地址空间充足。
-
reserve模式 :在指定区间内预留一块连续的虚拟地址空间,适用于旧架构或特殊需求(如环境变量
HSA_RESERVE_SVM启用)。
本文重点分析reserve模式的实现原理和具体流程。
2. 实现原理与应用场景
2.1 实现原理
Reserve模式的核心目标是:在指定的base和limit区间内,预留一块足够大的、连续的虚拟地址空间,供SVM使用。
-
预留空间的大小优先为整个区间,若无法分配则逐步减半,直到满足最小要求(4GB)。
-
预留空间必须对齐到GPU的Huge Page Size,保证性能和兼容性。
-
预留空间的至少一半必须在GPU可寻址范围内,确保GPU能够访问大部分分配的SVM空间。
预留空间的实现很简单,就是mmap。当计算出起始地址和大小后,就可以申请了,关键实现函数如下:
cpp
static void *reserve_address(void *addr, unsigned long long int len)
{
void *ret_addr;
if (len <= 0)
return NULL;
//匿名映射,请关注映射参数
ret_addr = mmap(addr, len, PROT_NONE,
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
if (ret_addr == MAP_FAILED)
return NULL;
return ret_addr;
}
2.2 适用场景
-
兼容性强:适用于虚拟地址空间有限或驱动/硬件不支持mmap模式的场景。
-
可控性高:通过环境变量可强制启用reserve模式,便于调试和特殊需求。
-
性能保障:Huge Page对齐和空间预留减少碎片,提高访问效率。
3. bo的svm地址分配与释放
reserve SVM 区域作为统一的虚拟地址池,所有分配和映射都在该区域内完成。在reserve SVM地址区间内申请memory,配套的申请和释放函数是reserved_aperture_allocate_aligned和reserved_aperture_release。原理与drm_mm的管理地址空间类似。使用list维护分配区间的元数据。
3.1 申请函数实现流程
1. 对齐处理
-
如果请求的对齐小于 aperture 的默认对齐,则提升到默认对齐。
-
对于大块分配,自动提升对齐到更高的2的幂(最多到 GPU_HUGE_PAGE_SIZE),以优化TLB性能。
-
如果没有指定对齐(或对齐小于等于PAGE_SIZE),则采用"尾部对齐"策略:通过 offset 变量将分配区间尾部对齐到目标对齐边界,解决部分旧GPU的TLB问题。
2 分配区间扩展
- 分配区间大小会加上 guard pages(保护页),防止越界访问。
3. 查找空闲区间
-
遍历 aperture 的 vm_ranges 链表,查找足够大的"洞"。
-
如果指定了 address,则从该地址开始查找,否则从 aperture base 开始按对齐递增查找。
-
如果找到的空闲区间足够大,则分配;否则继续查找下一个区间。
4. 分配区间插入
-
如果分配区间正好与前一个已分配区间相邻,则扩展该区间。
-
否则,创建新的 vm_area_t 节点插入到链表中,维护分配区间元数据。
5 返回分配结果
3.2 释放函数的实现流程
-
区间对齐处理
首先将释放的大小加上 guard pages(保护页),确保释放区间与分配时一致。
-
查找对应区间
通过
vm_find在 aperture 的vm_ranges链表中查找包含该地址的区间(vm_area_t)。 -
区间释放与调整
-
如果释放区间正好等于整个已分配区间,则直接移除该区间节点(
vm_remove_area)。 -
如果释放区间是已分配区间的一部分,则根据释放位置(区间头、区间尾或中间)调整区间边界或拆分区间(
vm_split_area)。
-
-
物理内存和 NUMA 策略处理
-
如果 aperture 支持 CPU 访问(
is_cpu_accessible),则重置 NUMA 策略(mbind),并用mmap(PROT_NONE)重新映射释放区间,保持地址空间预留但不可访问。 -
如果
mmap失败且errno == ENOMEM,则先munmap再尝试mmap,确保释放成功。
-
3.3 关键点
-
所有分配和释放都在 aperture 的 fmm_mutex 保护下,保证线程安全。
-
分配区间通过 vm_area_t 链表管理,支持动态分配和释放。
-
对齐和保护页策略保证了分配区间的性能和安全性。
-
释放时要保留区间。