原理篇见【https://blog.csdn.net/shenjunpeng/article/details/150931847?spm=1011.2415.3001.5331】
1. HMM 的优势与挑战
1.1 优势
-
统一虚拟地址空间:简化异构计算平台的数据共享和访问。
-
高效页表同步:支持设备端的 page fault 和页表同步,提升性能。
-
内存一致性保障:通过 notifier 机制保证 CPU/设备访问一致性。
-
简化驱动开发:为设备驱动提供标准化 API,降低开发难度。
-
支持多种内存类型:兼容系统内存、设备私有内存、P2P 内存等。
2.2 挑战
-
性能开销:频繁的页表同步和失效处理可能带来性能损耗。
-
一致性复杂性:多处理器、多设备间的数据一致性管理复杂。
-
内核集成难度:与 mm、page table、notifier 等子系统深度耦合,开发和维护门槛高。
-
异常场景处理:如 page fault 风暴、死锁、资源泄漏等需精心设计和测试。
2. 典型代码示例
2.1 注册 mmu_interval_notifier
struct mmu_interval_notifier notifier;
mmu_interval_notifier_insert(¬ifier, mm, start, length, ops);
2.2 查询并同步页表
struct hmm_range range = {.notifier = ¬ifier,.start = start,.end = end,.hmm_pfns = pfns,.default_flags = HMM_PFN_REQ_FAULT | HMM_PFN_REQ_WRITE,.pfn_flags_mask = HMM_PFN_REQ_FAULT | HMM_PFN_REQ_WRITE,
};
int ret = hmm_range_fault(&range);
if (ret)// 处理错误
for (i = 0; i < npages; i++) {if (range.hmm_pfns[i] & HMM_PFN_VALID) {phys_addr_t pa = hmm_pfn_to_phys(range.hmm_pfns[i]);// 填充设备页表}
}
2.3 失效处理
static bool my_notifier_invalidate(struct mmu_interval_notifier *notifier,const struct mmu_notifier_range *range,unsigned long cur_seq)
{// 暂停设备访问,unmap 页表,等待恢复return true;
}
3. SVM 中 HMM 的使用场景
KFD SVM 通过 HMM 实现以下关键功能:
-
GPU 访问用户空间内存前,获取并锁定物理页(即页表同步、page fault 支持)。
-
支持 GPU 侧 page fault,在 GPU 访问尚未分配物理页的虚拟地址时,驱动可通过 HMM 触发 CPU 侧分配物理页。
-
支持内存迁移,如将数据从系统内存迁移到 GPU 显存(VRAM),或反向迁移。
-
感知虚拟地址区间失效,如 unmap、migrate、swap out 等,及时更新 GPU 页表。
3.1 SVM 中 HMM 的典型调用流程
3.1.1 注册 mmu_interval_notifier
每个 SVM 区间(struct svm_range
)在创建时,都会注册一个 mmu_interval_notifier
,用于感知该区间的虚拟地址空间变化。这样一旦该区间被 unmap、迁移、失效,KFD 驱动就能收到通知,做相应处理。
static void
svm_range_add_notifier_locked(struct mm_struct *mm, struct svm_range *prange)
{mmu_interval_notifier_insert_locked(&prange->notifier, mm,prange->start << PAGE_SHIFT,prange->npages << PAGE_SHIFT,&svm_range_mn_ops);
}
3.1.2 获取并锁定物理页(hmm_range_fault)
该函数会遍历指定虚拟地址区间的页表,确保每一页都被分配物理页(如有必要会触发 CPU 侧 page fault),并将每一页的 PFN(页帧号)和状态标志写入 hmm_pfns
数组。这一步通常在 svm_range_validate_and_map
→ amdgpu_hmm_range_get_pages
中完成。
int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,uint64_t start, uint64_t npages, bool readonly,void *owner, struct page **pages,struct hmm_range **phmm_range)
{struct hmm_range *hmm_range;unsigned long end;unsigned long timeout;unsigned long i;unsigned long *pfns;int r = 0;hmm_range = kzalloc(sizeof(*hmm_range), GFP_KERNEL);if (unlikely(!hmm_range))return -ENOMEM;pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);if (unlikely(!pfns)) {r = -ENOMEM;goto out_free_range;}hmm_range->notifier = notifier;hmm_range->default_flags = HMM_PFN_REQ_FAULT;if (!readonly)hmm_range->default_flags |= HMM_PFN_REQ_WRITE;hmm_range->hmm_pfns = pfns;hmm_range->start = start;end = start + npages * PAGE_SIZE;hmm_range->dev_private_owner = owner;do {hmm_range->end = min(hmm_range->start + MAX_WALK_BYTE, end);pr_debug("hmm range: start = 0x%lx, end = 0x%lx",hmm_range->start, hmm_range->end);timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);retry:hmm_range->notifier_seq = mmu_interval_read_begin(notifier);r = hmm_range_fault(hmm_range);if (unlikely(r)) {if (r == -EBUSY && !time_after(jiffies, timeout))goto retry;goto out_free_pfns;}if (hmm_range->end == end)break;hmm_range->hmm_pfns += MAX_WALK_BYTE >> PAGE_SHIFT;hmm_range->start = hmm_range->end;} while (hmm_range->end < end);hmm_range->start = start;hmm_range->hmm_pfns = pfns;for (i = 0; pages && i < npages; i++)pages[i] = hmm_pfn_to_page(pfns[i]);*phmm_range = hmm_range;return 0;out_free_pfns:kvfree(pfns);
out_free_range:kfree(hmm_range);if (r == -EBUSY)r = -EAGAIN;return r;
}
3.1.3 填充 GPU 页表
获取到物理页后,KFD 驱动会将这些页的物理地址通过 DMA 映射,填充到 GPU 页表,实现 GPU 对用户空间内存的直接访问。这里 hmm_range->hmm_pfns
就是 HMM 返回的每一页的 PFN 和状态。
r = svm_range_dma_map(prange, ctx->bitmap, offset, npages, hmm_range->hmm_pfns);
3.1.4 失效与恢复
当用户空间对 SVM 区间做 unmap、迁移等操作时,HMM 通过 mmu_interval_notifier 回调(如 svm_range_cpu_invalidate_pagetables
)通知 KFD 驱动,KFD 会暂停 GPU 访问、unmap 页表、等待恢复。
4. 总结
HMM 是 Linux 内核为异构计算平台量身定制的高效内存管理机制,极大简化了 CPU 与设备间的数据共享、页表同步和一致性管理。它为 GPU、FPGA、AI 加速器等设备驱动提供了统一、标准化的 API,支持 SVM、page fault、内存迁移等高级功能,是现代高性能计算平台不可或缺的基础设施。
对于内核和驱动开发者,深入理解 HMM 的原理、实现和最佳实践,有助于开发更高效、可靠的异构计算应用,并为未来的系统优化和创新打下坚实基础。