华为UVM技术分析:把GPU显存塞进Linux核心MM---GMEM实现简析

华为UVM技术分析:把GPU显存塞进Linux核心MM---GMEM实现简析

本文基于内核mm/gmem*.cinclude/linux/gmem.hinclude/linux/vm_object.h源码,从统一虚拟地址UVA/SVM视角拆解华为GMEM子系统,同步对比HMM、AMD KFD、Intel Xe现有异构方案,面向内核与GPU驱动研发人员。

一、GMEM核心定位:走出HMM的异构内存新路线

CPU与GPU/NPU异构开发长期存在三大痛点:地址空间割裂、数据频繁拷贝、显存容量不足无法超额使用。
Linux主线成熟方案为HMM:设备镜像CPU页表,设备内存依托ZONE_DEVICEstruct page承载,页面迁移依赖migrate_vma,CPU核心MM永久持有页面所有权。

GMEM提出完全不同的架构思路:将异构设备提升为地址空间一级核心载体

  1. 进程新增独立GMEM地址空间gm_as,通过gm_as_attach挂载GPU/NPU设备;
  2. 跨设备共享VMA绑定专属逻辑页表vm_object,维护VA到gm_mapping映射,作为页面存储位置的唯一权威;
  3. GPU显存抽象为虚拟NUMA节点h-NUMA,复用内核原生NUMA内存管理、页面迁移、内存统计整套基础设施。

二者底层核心分歧:HMM让设备跟随CPU页表,不改动内核页所有权模型;GMEM新增中间层逻辑页表,CPU与GPU统一受其调度,页面所有权交由中间层管控。

二、核心数据结构:逻辑页表是整个体系中枢

整套代码分为控制面、数据面两条逻辑链路:

  • 控制面:mm->gm_as → gm_context → gm_dev,管理进程挂载设备、显存内存池基础信息;
  • 数据面:vma->vm_object → xarray → gm_mapping,记录虚拟地址页面存放位置(主机/显存/无分配)。

1. 逻辑页表 vm_object

仅对带有VM_PEER_SHARED标识的跨设备共享VMA生效,普通进程无额外性能开销,内部以xarray存储虚拟地址与页面映射关系。

structvm_object{spinlock_tlock;structvm_area_struct*vma;structxarray*logical_page_table;// VA -> gm_mappingatomic_tnr_pages;atomic_tref_count;};

2. 页状态管理 gm_mapping

定义页面三态:GM_MAPPING_CPU(主机内存)、GM_MAPPING_DEVICE(显存)、GM_MAPPING_NOMAP(未分配),内部互斥锁统一管控缺页、迁移、换出全流程,同一页面同一时间仅存在于一端。

structgm_mapping{unsignedintflag;union{structpage*page;// 主机页structgm_page*gm_page;// 显存页};structgm_dev*dev;structmutexlock;// 迁移状态机串行锁};

3. 显存物理页 gm_page(与HMM最大差异)

GMEM不复用内核标准struct page,自研gm_page管理显存物理内存,内置简易反向映射rmap,但仅支持单进程单虚拟地址绑定
短板显著:无法支撑多进程共享、fork写时复制COW场景。

structgm_page{structlist_headgm_page_list;unsignedlongdev_pfn;unsignedlongdev_dma_addr;unsignedinthnid;// 单槽反向映射,仅记录一组(mm, va)unsignedlongva;structmm_struct*mm;spinlock_trmap_lock;unsignedintflag;atomic_trefcount;};

4. GMEM对内核MM的侵入改动(中度改造)

仅针对异构共享内存做最小侵入:

  1. mm_struct新增gm_as成员存储进程GMEM地址空间;
  2. vm_area_struct新增vm_obj绑定逻辑页表;
  3. 新增VM_PEER_SHARED标志位作为GMEM总开关;
  4. 拦截内存缺页、内存卸载钩子,分流至GMEM专属处理函数。

三、驱动接入:gm_mmu统一回调接口

GMEM完成上层策略封装,硬件操作下沉至驱动,驱动只需实现一套gm_mmu回调表即可完成适配,核心接口分为内存分配、映射、DMA拷贝、显存导入四类。
peer_mappeer_unmap通过copy标志位统一管理映射创建/销毁与数据DMA迁移,大幅简化驱动开发成本。

structgm_mmu{enumgm_ret(*peer_va_alloc_fixed)(structgm_fault_t*gmf);enumgm_ret(*peer_va_free)(structgm_fault_t*gmf);// 创建设备映射,copy=true同步H2D数据enumgm_ret(*peer_map)(structgm_fault_t*gmf);// 销毁设备映射,copy=true同步D2H数据enumgm_ret(*peer_unmap)(structgm_fault_t*gmf);enumgm_ret(*import_phys_mem)(structmm_struct*mm,inthnid,unsignedlongpage_cnt);enumgm_ret(*peer_hmemcpy)(structgm_memcpy_t*gmc);};

四、h-NUMA:显存伪装虚拟NUMA节点

GMEM标志性设计,未占用真实CPU NUMA节点编号的id作为虚拟h-node,每个GPU绑定独立hnode,配套专属内存空闲链表、活跃链表与独立回收线程gm_swapd

  1. 显存惰性导入:空闲链表耗尽时才回调驱动批量申请显存,避免一次性占用全部显存;
  2. 容量管控:max_memsize限制进程可占用显存上限,原生支持显存超额订阅;
  3. 节点并入进程mems_allowed,内核内存分配器可识别显存内存池。

对比HMM:HMM依托ZONE_DEVICE复用内核整套页管理;GMEM复用NUMA节点体系,但需要自研页面、反向映射、回收逻辑。

五、核心数据流转:三路径统一互斥锁管控

1. GPU设备缺页(主机→显存迁移)

GPU访问未映射显存内存触发缺页,流程:
锁定gm_mapping→ 判断页面状态 → 主机页则断开CPU页表、DMA搬运数据 → 驱动创建设备映射 → 页面移入显存活跃链表,纳入后台换出候选。
显存页分配三级兜底:空闲链表取用 → 向驱动申请新显存 → 后台换出闲置页面。

2. CPU主机缺页(显存→主机迁移)

CPU访问共享VMA触发缺页,仅支持2MB大页THP:
锁定映射锁,若页面被GPU锁定则直接报错;页面位于显存时,执行peer_unmap将数据DMA回传主机,创建CPU侧PMD大页映射,切换页面状态为主机内存。

3. 显存后台换出swapd

每个虚拟NUMA节点创建独立内核线程,批量驱逐未锁定显存页面回主机内存:
通过gm_page内置单槽rmap反查进程虚拟地址,抢占全局映射锁,执行D2H拷贝,回收显存至空闲链表。
严格锁序保障并发安全:mmap读锁 → rmap锁 → gm_mapping互斥锁 → 节点链表自旋锁。

六、用户态操作接口

  1. mmap(MAP_PEER_SHARED):创建支持CPU/GPU共享的统一虚拟地址内存;
  2. hmadvise:GMEM专属内存策略,支持预取至显存、释放显存、页面锁定;
  3. hmemcpy:主机与显存间显式DMA拷贝,当前仅实现H2D、D2H,设备间D2D拷贝未落地。

七、GMEM与HMM架构核心对比

对比维度HMM(KFD/Xe)GMEM
页表权威CPU原生页表新增中间逻辑页表vm_object
同步模型MMU通知异步失效,弱一致互斥锁强互斥,页面仅存一端
显存载体ZONE_DEVICE+struct page虚拟h-NUMA+自研gm_page
页面回收依附内核kswapd,无专属显存回收器单节点独立swapd线程
反向映射原生内核rmap,支持多进程共享单槽rmap,不支持共享COW
页面粒度4KB细粒度兼容仅2MB THP大页
内核改动改动极小,主线原生支持中度侵入mm核心结构体

Inteldrm_gpusvm与GMEM设计目标高度重合,均希望统一SVM异构逻辑;区别在于drm_gpusvm基于DRM子系统实现,不修改核心内存管理,也是Linux主线更偏好的方案。

八、GMEM现存原生硬伤

  1. 单槽反向映射:gm_page仅绑定一组进程地址,多进程共享、fork COW完全失效;
  2. fork语义残缺:子进程复制VMA时新建空白逻辑页表,不继承显存映射关系;
  3. 仅支持2MB大页,4KB细粒度分配无法使用,小内存场景资源浪费;
  4. 单地址空间仅支持挂载一台设备,无法多GPU并行共享内存;
  5. 后台swapd唤醒条件恒假,回收仅在显存耗尽时同步触发,无法主动水位管控;
  6. 换出仅落主机RAM,不支持磁盘swap,主机内存会成为新瓶颈;
  7. D2D显存拷贝、硬件上下文切换接口仅预留占位,无完整实现。

九、总结

GMEM是一次激进的内核内存重构尝试,核心两大设计亮点具备参考价值:

  1. 中心化逻辑页表,统一仲裁CPU/GPU多MMU页面位置;
  2. 为显存提供内核原生独立回收机制,补齐HMM显存超额订阅短板。

但整套实现当前仅为基础骨架,多处核心能力未落地,且对内核MM存在中度侵入,与上游“优先在DRM层实现异构内存”的路线冲突。短期难以完整合入主线,但其分层管理、显存独立回收的设计思路,大概率会被drm_gpusvm等现有主线方案吸收借鉴。


感兴趣的技术读友,可以去看下源码:https://atomgit.com/openeuler/kernel。