概述
kfd_ioctl_svm_attr_type 枚举定义了 SVM(Shared Virtual Memory)的所有属性类型,用于控制 GPU 对共享虚拟内存的访问行为、数据位置偏好、以及一致性模式。
c
enum kfd_ioctl_svm_attr_type {
KFD_IOCTL_SVM_ATTR_PREFERRED_LOC, // 首选位置
KFD_IOCTL_SVM_ATTR_PREFETCH_LOC, // 预取位置(触发迁移)
KFD_IOCTL_SVM_ATTR_ACCESS, // GPU 访问权限(可迁移)
KFD_IOCTL_SVM_ATTR_ACCESS_IN_PLACE, // GPU 访问权限(不迁移)
KFD_IOCTL_SVM_ATTR_NO_ACCESS, // 移除 GPU 访问权限
KFD_IOCTL_SVM_ATTR_SET_FLAGS, // 设置标志位
KFD_IOCTL_SVM_ATTR_CLR_FLAGS, // 清除标志位
KFD_IOCTL_SVM_ATTR_GRANULARITY // 迁移粒度
};
1. KFD_IOCTL_SVM_ATTR_PREFERRED_LOC
1.1 功能
设置内存的首选位置(preferred location),决定数据在空闲时应该驻留的位置。
1.2 Value 取值
| 值 | 含义 |
|---|---|
0 (KFD_IOCTL_SVM_LOCATION_SYSMEM) |
系统内存(CPU) |
GPU_ID |
特定 GPU 的显存 |
0xffffffff (UNDEFINED) |
未定义,由系统决定 |
1.3 内核处理
c
case KFD_IOCTL_SVM_ATTR_PREFERRED_LOC:
prange->preferred_loc = attrs[i].value;
break;
1.4 作用
- 当 GPU 发生 page fault 时,
svm_range_best_restore_location()会优先考虑preferred_loc - 如果
preferred_loc是一个 GPU,且该 GPU 可以访问,数据会迁移到该 GPU - 影响 page fault 恢复时的数据放置策略
1.5 使用示例
c
// 设置首选位置为 GPU 0
attrs[0].type = KFD_IOCTL_SVM_ATTR_PREFERRED_LOC;
attrs[0].value = gpu_id_0;
2. KFD_IOCTL_SVM_ATTR_PREFETCH_LOC
2.1 功能
设置预取位置 并立即触发数据迁移。
2.2 Value 取值
与 PREFERRED_LOC 相同。
2.3 内核处理
c
case KFD_IOCTL_SVM_ATTR_PREFETCH_LOC:
prange->prefetch_loc = attrs[i].value;
break;
在 svm_range_set_attr() 中,设置 prefetch_loc 后会触发:
c
r = svm_range_trigger_migration(mm, prange, &migrated);
2.4 与 PREFERRED_LOC 的区别
| 属性 | 行为 |
|---|---|
PREFERRED_LOC |
设置偏好,不立即迁移,等 page fault 时生效 |
PREFETCH_LOC |
设置位置并立即迁移数据 |
2.5 使用场景
- 在 GPU 计算前,预先将数据迁移到目标 GPU 显存
- 避免运行时 page fault 导致的性能抖动
2.6 使用示例
c
// 立即将数据迁移到 GPU 0
attrs[0].type = KFD_IOCTL_SVM_ATTR_PREFETCH_LOC;
attrs[0].value = gpu_id_0;
3. KFD_IOCTL_SVM_ATTR_ACCESS
3.1 功能
授予指定 GPU 对内存的访问权限 ,数据可以被迁移到该 GPU。
3.2 Value 取值
GPU ID(指定哪个 GPU 获得访问权限)。
3.3 内核处理
c
case KFD_IOCTL_SVM_ATTR_ACCESS:
gpuidx = kfd_process_gpuidx_from_gpuid(p, attrs[i].value);
bitmap_set(prange->bitmap_access, gpuidx, 1); // 设置访问位
bitmap_clear(prange->bitmap_aip, gpuidx, 1); // 清除 in-place 位
break;
3.4 作用
- 设置
bitmap_access位图中对应 GPU 的位 - 当 GPU 访问该内存时,数据可能被迁移到该 GPU 的显存
- page fault 恢复时,
svm_range_best_restore_location()检查此位图
3.5 迁移行为
GPU 访问 → Page Fault → 检查 bitmap_access
↓
如果 GPU 在 bitmap_access 中
↓
数据可迁移到该 GPU 显存
4. KFD_IOCTL_SVM_ATTR_ACCESS_IN_PLACE
4.1 功能
授予指定 GPU 对内存的访问权限 ,但数据保持原地不迁移。
4.2 Value 取值
GPU ID。
4.3 内核处理
c
case KFD_IOCTL_SVM_ATTR_ACCESS_IN_PLACE:
gpuidx = kfd_process_gpuidx_from_gpuid(p, attrs[i].value);
bitmap_clear(prange->bitmap_access, gpuidx, 1); // 清除访问位
bitmap_set(prange->bitmap_aip, gpuidx, 1); // 设置 in-place 位
break;
4.4 与 ACCESS 的区别
| 属性 | bitmap_access | bitmap_aip | 数据迁移 |
|---|---|---|---|
ACCESS |
✅ 设置 | ❌ 清除 | 可迁移到 GPU |
ACCESS_IN_PLACE |
❌ 清除 | ✅ 设置 | 不迁移,远程访问 |
4.5 适用场景
- 多 GPU 共享访问同一内存
- 避免数据在 GPU 间来回迁移(ping-pong)
- CPU 内存被多个 GPU 远程访问
4.6 性能考虑
ACCESS: 数据迁移到 GPU 显存,带宽高,延迟低
ACCESS_IN_PLACE: 远程访问(PCIe/XGMI),带宽受限,但避免迁移开销
5. KFD_IOCTL_SVM_ATTR_NO_ACCESS
5.1 功能
移除指定 GPU 对内存的访问权限。
5.2 Value 取值
GPU ID。
5.3 内核处理
c
case KFD_IOCTL_SVM_ATTR_NO_ACCESS:
gpuidx = kfd_process_gpuidx_from_gpuid(p, attrs[i].value);
bitmap_clear(prange->bitmap_access, gpuidx, 1); // 清除访问位
bitmap_clear(prange->bitmap_aip, gpuidx, 1); // 清除 in-place 位
break;
5.4 作用
- 同时清除
bitmap_access和bitmap_aip - GPU 尝试访问时会触发 page fault,且无法恢复(返回 -EACCES)
5.5 使用场景
- 安全性:限制特定 GPU 访问敏感数据
- 资源管理:在 GPU 不再需要访问时释放权限
6. KFD_IOCTL_SVM_ATTR_SET_FLAGS
6.1 功能
设置(OR)指定的标志位。
6.2 Value 取值
标志位掩码,可以是以下值的组合:
| 标志 | 值 | 说明 |
|---|---|---|
KFD_IOCTL_SVM_FLAG_HOST_ACCESS |
0x01 | 保证 CPU 可访问 |
KFD_IOCTL_SVM_FLAG_COHERENT |
0x02 | 细粒度一致性 |
KFD_IOCTL_SVM_FLAG_HIVE_LOCAL |
0x04 | 使用同 hive 的任意 GPU |
KFD_IOCTL_SVM_FLAG_GPU_RO |
0x08 | GPU 只读,允许复制 |
KFD_IOCTL_SVM_FLAG_GPU_EXEC |
0x10 | 允许 GPU 执行 |
KFD_IOCTL_SVM_FLAG_GPU_READ_MOSTLY |
0x20 | GPU 主要读取 |
KFD_IOCTL_SVM_FLAG_GPU_ALWAYS_MAPPED |
0x40 | 保持 GPU 映射始终有效 |
KFD_IOCTL_SVM_FLAG_EXT_COHERENT |
0x80 | 扩展一致性(device-scope atomics) |
6.3 内核处理
c
case KFD_IOCTL_SVM_ATTR_SET_FLAGS:
*update_mapping = true;
prange->flags |= attrs[i].value; // OR 操作
break;
6.4 标志详解
FLAG_COHERENT (0x02)
- 启用细粒度一致性
- CPU 和 GPU 看到一致的内存视图
- 性能开销较高
FLAG_EXT_COHERENT (0x80)
- 扩展一致性,使用 device-scope atomics
- 比 COHERENT 更强的一致性保证
- 用于跨设备原子操作
FLAG_GPU_ALWAYS_MAPPED (0x40)
- 即使 XNACK 开启,也保持 GPU 页表映射有效
- 避免 page fault 开销
- 类似于 XNACK 关闭的行为
FLAG_GPU_RO (0x08)
- GPU 只读访问
- 允许数据复制到多个 GPU(replication)
- 优化多 GPU 读取同一数据的场景
7. KFD_IOCTL_SVM_ATTR_CLR_FLAGS
7.1 功能
清除(AND NOT)指定的标志位。
7.2 Value 取值
与 SET_FLAGS 相同的标志位掩码。
7.3 内核处理
c
case KFD_IOCTL_SVM_ATTR_CLR_FLAGS:
*update_mapping = true;
prange->flags &= ~attrs[i].value; // AND NOT 操作
break;
7.4 使用示例
c
// 设置细粒度一致性
attrs[0].type = KFD_IOCTL_SVM_ATTR_SET_FLAGS;
attrs[0].value = KFD_IOCTL_SVM_FLAG_COHERENT;
// 清除细粒度一致性(改为粗粒度)
attrs[0].type = KFD_IOCTL_SVM_ATTR_CLR_FLAGS;
attrs[0].value = KFD_IOCTL_SVM_FLAG_COHERENT;
8. KFD_IOCTL_SVM_ATTR_GRANULARITY
8.1 功能
设置迁移粒度,控制 page fault 时迁移的内存块大小。
8.2 Value 取值
log2(页数),范围 0-63(实际限制为 0x3F)。
| Value | 迁移大小 |
|---|---|
| 0 | 1 页 = 4KB |
| 1 | 2 页 = 8KB |
| 4 | 16 页 = 64KB |
| 9 | 512 页 = 2MB |
8.3 内核处理
c
case KFD_IOCTL_SVM_ATTR_GRANULARITY:
prange->granularity = min_t(uint32_t, attrs[i].value, 0x3F);
break;
8.4 作用
在 page fault 处理中:
c
size = 1UL << prange->granularity;
start = ALIGN_DOWN(addr, size);
last = ALIGN(addr + 1, size) - 1;
8.5 权衡
| 粒度 | 优点 | 缺点 |
|---|---|---|
| 小 | 精确,避免不必要迁移 | 频繁 fault,开销大 |
| 大 | 减少 fault 次数,预取效果好 | 可能迁移不需要的数据 |
9. 属性总结表
| 属性类型 | 存储位置 | 作用 | 触发迁移 |
|---|---|---|---|
PREFERRED_LOC |
prange->preferred_loc |
设置首选位置 | ❌ 延迟 |
PREFETCH_LOC |
prange->prefetch_loc |
设置位置并迁移 | ✅ 立即 |
ACCESS |
prange->bitmap_access |
授权 GPU 访问,可迁移 | 按需 |
ACCESS_IN_PLACE |
prange->bitmap_aip |
授权 GPU 访问,不迁移 | ❌ |
NO_ACCESS |
清除两个 bitmap | 移除 GPU 访问权限 | N/A |
SET_FLAGS |
prange->flags |
设置标志 | N/A |
CLR_FLAGS |
prange->flags |
清除标志 | N/A |
GRANULARITY |
prange->granularity |
迁移粒度 | N/A |
10. 典型使用场景
10.1 单 GPU 计算
c
// 1. 设置首选位置为 GPU
attrs[0].type = KFD_IOCTL_SVM_ATTR_PREFERRED_LOC;
attrs[0].value = gpu_id;
// 2. 授权 GPU 访问
attrs[1].type = KFD_IOCTL_SVM_ATTR_ACCESS;
attrs[1].value = gpu_id;
// 3. 预取数据到 GPU
attrs[2].type = KFD_IOCTL_SVM_ATTR_PREFETCH_LOC;
attrs[2].value = gpu_id;
10.2 多 GPU 共享读取
c
// 所有 GPU 就地访问,数据保持在 CPU
for (int i = 0; i < num_gpus; i++) {
attrs[i].type = KFD_IOCTL_SVM_ATTR_ACCESS_IN_PLACE;
attrs[i].value = gpu_ids[i];
}
10.3 细粒度一致性
c
// 设置细粒度一致性
attrs[0].type = KFD_IOCTL_SVM_ATTR_SET_FLAGS;
attrs[0].value = KFD_IOCTL_SVM_FLAG_COHERENT;