NUMA-04 显存迁回内存:AMD/Intel 的 SVM 与Eviction的实现是否考虑了NUMA

发布时间:2026/9/22 0:37:41

NUMA-04 显存迁回内存:AMD/Intel 的 SVM 与Eviction的实现是否考虑了NUMA 前三篇的迁移都在“普通内存 ↔ 普通内存”。但 GPU 显存 CPU 根本访问不到它是怎么被纳入进程地址空间、又怎么在缺页时自动迁回内存以及回迁时怎么选择numa node。这将是本文的主题。0. 本章要回答的问题GPU 显存这种 CPU 不能直接读的内存怎么变成进程页表里的一个页ZONE_DEVICE/ device private pageCPU 去访问一个“其实在显存里”的地址时会发生什么migrate_to_ram缺页回调device→host 迁移时那个“目标 CPU 页”是在哪分配、落在哪个 node 的第 3 问是重点。本文更多的是分析当前的实现是否考虑了NUMA至于怎么优化放在后文分析。1. HMM 与 ZONE_DEVICE把设备内存塞进内存地图1.1 为什么需要它统一内存SVM / HMM的目标是CPU 和 GPU 共享同一套虚拟地址一个指针两边都能用。难点在于——同一个虚拟地址其物理页可能此刻在系统内存、下一刻被迁到了显存。内核需要一种办法把“显存里的页”也表示成一个struct page挂进进程页表这样缺页、迁移、反向映射这些既有机制才能复用。ZONE_DEVICE就是这个办法它为设备内存创建struct page但标记成特殊类型。其中 GPU 显存用的是MEMORY_DEVICE_PRIVATEinclude/linux/memremap.h// include/linux/memremap.henummemory_type{/* 0 is reserved to catch uninitialized type fields */MEMORY_DEVICE_PRIVATE1,// 设备私有内存CPU 不能直接访问// ...};MEMORY_DEVICE_PRIVATE的含义这些页有struct page、能进页表但 CPU 不能直接解引用——CPU 一旦访问就触发缺页由驱动把它迁回真正的系统内存。1.2 显存怎么注册进来devm_memremap_pages驱动在初始化时把一段显存通过devm_memremap_pages()或memremap_pages()注册为ZONE_DEVICE内核为这段显存建立struct page数组并绑定一个struct dev_pagemapinclude/linux/memremap.h// include/linux/memremap.hstructdev_pagemap{// ...conststructdev_pagemap_ops*ops;// 关键设备页的行为回调// ...};structdev_pagemap_ops{void(*page_free)(structpage*page);vm_fault_t(*migrate_to_ram)(structvm_fault*vmf);// CPU 访问设备页时的缺页回调};GPU VRAM 一段物理区间devm_memremap_pages()注册为 ZONE_DEVICE生成 struct page 数组type MEMORY_DEVICE_PRIVATE绑定 dev_pagemap.ops.migrate_to_ram 驱动回调这些 page 可以挂进进程页表2. CPU 访问设备页migrate_to_ram缺页回调当一段 SVM 内存当前在显存页表项指向 device private page而 CPU 代码去读写它时MMU 发现这是特殊页触发缺页异常内核回到dev_pagemap_ops.migrate_to_ram这个回调——把页迁回系统内存再让 CPU 访问继续。KFD 路径的注册drivers/gpu/drm/amd/amdkfd/kfd_migrate.c// drivers/gpu/drm/amd/amdkfd/kfd_migrate.cstaticconststructdev_pagemap_opssvm_migrate_pgmap_ops{.page_freesvm_migrate_page_free,.migrate_to_ramsvm_migrate_to_ram,// CPU 缺页 → 迁回系统内存};svm_migrate_to_ram()最终调用svm_migrate_vram_to_ram()走的正是第 03 章的migrate_vma三段式方向标志选设备页kfd_migrate.c// kfd_migrate.c svm_migrate_vma_to_ram()if(adev-gmc.xgmi.connected_to_cpu)migrate.flagsMIGRATE_VMA_SELECT_DEVICE_COHERENT;elsemigrate.flagsMIGRATE_VMA_SELECT_DEVICE_PRIVATE;// 挑出设备私有页// ...rmigrate_vma_setup(migrate);// 收集源(显存)页// ... 驱动为每个源页分配一个“系统内存页”填进 migrate.dst[]migrate_vma_pages(migrate);migrate_vma_finalize(migrate);整条缺页迁回链路是否就在内存CPU 读写一个 SVM 地址页表项指向device private page?MMU 触发缺页dev_pagemap_ops.migrate_to_ram() svm_migrate_to_rammigrate_vma 三段式flags DEVICE_PRIVATE为每个显存页分配一个系统内存页 → dst[]拷贝、重映射、收尾CPU 访问继续这部分的详细原理可以从参考Linux 内存管理子系统的进化——从 MM 到 HMM。3. 目标 CPU 页在哪分配、落哪个 nodemigrate_vma三段式里“填dst[]”这一步在驱动手里填的时候用哪个 node 分配就决定了页迁回后落在哪个 node。3.1 AMD KFD 路径alloc_page_vma跟随 VMA 策略KFD 用svm_migrate_get_sys_page()分配目标系统页kfd_migrate.c// kfd_migrate.cstaticstructpage*svm_migrate_get_sys_page(structvm_area_struct*vma,unsignedlongaddr){structpage*page;pagealloc_page_vma(GFP_HIGHUSER,vma,addr);// ← 落点由 VMA 的 mempolicy 决定if(page)lock_page(page);returnpage;}alloc_page_vma()按这段 VMA 的 NUMA 内存策略分配没有特殊策略时就是 first-touch/当前 node。这里的“VMA 策略”就是第 02 章mbind设定的“地址段级策略”内核里挂在 VMA 上没设时退化成第 01 章讲的 first-touch。也就是说——KFD 迁回的落点取决于 VMA 策略或触发缺页的那个 CPU 所在 node而不是“GPU 物理上最近的 node”。3.2 DRMdrm_pagemap路径vma_alloc_folio/folio_allocIntel 的 DRM SVM 后端走drm_pagemap。它填目标页的函数是drm_pagemap_migrate_populate_ram_pfn()drivers/gpu/drm/drm_pagemap.c// drivers/gpu/drm/drm_pagemap.c drm_pagemap_migrate_populate_ram_pfn()/* TODO: Support fallback to single pages if THP allocation fails */if(vas)foliovma_alloc_folio(GFP_HIGHUSER,order,vas,addr);// 有 VMA跟随 VMA 策略elsefoliofolio_alloc(GFP_HIGHUSER,order);// 无 VMA直接落当前 node有vasVMA时vma_alloc_folio跟随 VMA 的 mempolicy等价于 first-touch落点是“碰它的 CPU”所在 node。无vas时如后台驱逐 evictfolio_alloc完全不带 node 偏好落在当前执行线程所在的 node。两种情况都没有把“发起迁移的 GPU 最近的那个 CPU node”作为参数。在 NPS4 / 多 socket 机器上这意味着页很可能迁到一个离目标 GPU 较远的 node后续 CPU 访问就吃了远程延迟——这正是发现的问题。3.3 两条路径对照路径分配目标页的函数落点依据是否考虑 GPU 邻近 nodeKFDalloc_page_vma(GFP_HIGHUSER, vma, addr)VMA mempolicy / 当前 node否DRMdrm_pagemap有 VMAvma_alloc_folio(...)VMA mempolicy否DRMdrm_pagemapevict无 VMAfolio_alloc(GFP_HIGHUSER, order)当前 node无偏好否结论现有 device→host 迁移的落点从来不是“GPU 最近的 node”而是“恰好碰它的 CPU”或“当前 node”。4. evict 路径除了 CPU 缺页触发的迁回还有一类是显存吃紧时的驱逐evict把 SVM 显存页赶回系统内存腾空间。evict 往往发生在没有用户 VMA 上下文的后台流程里正对应folio_allocvas NULL分支——连 VMA 策略都没有纯落当前 node离“最近 node”更远。所以 evict 路径是这个问题最明显的受害场景。触发迁回的两种来源有无CPU 缺页migrate_to_rampopulate_ram_pfn 分配目标页显存驱逐evict_to_ram有 VMA 上下文?vma_alloc_folio跟随 VMA 策略folio_alloc落当前 node落点都可能远离发起 GPU 的最近 node5. 本章小结把“目标 node”的旅程接到本章层现状应该怎样用户态/上层只说“迁回 SYSMEM”传入/推导出“GPU 最近的 node id”drm_pagemap 分配vma_alloc_folio/folio_alloc无 node 偏好用alloc_pages_node(nid, ...)之类带上目标 node落点碰它的 CPU / 当前 nodeGPU 邻近 node也就是说第 01 章“怎么反推 GPU 最近 node”、第 02 章“move_pages/分配 API 怎么指定 node”、第 03 章“node 参数怎么决定落点”到这里合流成一个具体的问题**在drm_pagemap的 populate_ram 分配处把正确的 node 传进去。总结下本文的技术要点ZONE_DEVICE/MEMORY_DEVICE_PRIVATE让显存拥有struct page、能进页表但 CPU 不能直接访问include/linux/memremap.h。驱动用devm_memremap_pages()注册显存绑定dev_pagemap.ops.migrate_to_ram回调。CPU 访问设备页触发缺页 →migrate_to_ram→migrate_vma三段式迁回系统内存。下面是本文的两个焦点问题焦点1目标 CPU 页由alloc_page_vmaKFD/vma_alloc_folio·folio_allocDRM分配落点是 VMA 策略或当前 node都不考虑 GPU 邻近 node。焦点2evict 路径无 VMA用folio_alloc纯落当前 node是问题最突出的场景。接下来讨论下可能的优化以及helios和GB200这种机架式系统中的numa。关联阅读01 你的内存不是一整块看懂 NUMA 与机器拓扑02 一段内存到底在哪个 node用户态 NUMA 编程接口03 页是怎么在 node 间搬家的内核 NUMA 与页迁移机制ZONE_DEVICE为设备内存创建 struct page
延伸阅读

更多相关文章

2026/9/22 3:30:59

NUMA-03 页是怎么在 node 间搬家的:内核 NUMA 与页迁移机制

NUMA:一段内存到底在哪个 node:用户态 NUMA 编程接口在用户态调 move_pages 把页迁到某个 node,一行就返回了。但内核里到底发生了什么?“目标 node” 这个参数又是怎么一路传下去、最终决定新页落在哪的?这一章把这条…

2026/9/21 8:36:01

Java集合框架深度解析:从底层原理到高并发实战优化

1. 集合,Java开发的基石与“瑞士军刀”如果你写过Java代码,那么你几乎不可能没碰过集合。无论是从数据库查出来的一堆用户对象,还是临时存放几个配置项,集合都是我们最顺手、最常用的工具。但正因为太常用了,很多人对它…

2026/9/21 12:44:18

主动配电网故障恢复:网络重构与孤岛划分协同优化

1. 主动配电网故障恢复的核心挑战与解决思路电力系统运行中最令人头疼的场景莫过于故障发生后的恢复过程。作为一名长期从事配电网研究的工程师,我深刻理解故障恢复过程中面临的三大核心矛盾:恢复速度与供电可靠性的平衡、故障隔离范围与负荷损失量的权衡…

2026/9/22 16:06:03

抄股票基础知识l完整示例

股票API升级踩坑?这份保姆级教程帮你搞懂底层逻辑 版本升级后 API 全变了,接口文档看着眼晕,旧代码直接报错?别慌,这篇保姆级教程带你从底层原理拆解股票数据获取的核心机制,彻底解决“改代码就崩溃”的顽疾。很多开发者在对接行情数据时,总被…

2026/9/22 16:06:03

招聘简历表格踩坑实录:源码解析避坑指南

招聘简历表格踩坑实录:源码解析避坑指南 官方文档那一套,谁看谁头疼。几百页的PDF,搜半天找不到关键配置项,直接劝退。 别再对着文档死磕了,直接上 源码解析 。…

2026/9/22 16:06:03

一文搞懂意大利沙发品牌前十名:源码级拆解选型逻辑

一文搞懂意大利沙发品牌前十名:源码级拆解选型逻辑 报错一堆看不懂 StackTrace,心里慌不慌? 很多初学者刚接触“意大利沙发品牌前十名”这个看似玄学的概念,脑子里全是乱码。 其实,选沙发就像读源码,底层逻辑是一样的。…

2026/9/22 16:06:03

杭州美景盖世无双:转行运维开发3个实战项目避坑全记录

杭州美景盖世无双:转行运维开发3个实战项目避坑全记录 看了一堆教程还是不会写项目?这是大多数转行者在杭州求职时最扎心的现实。你背熟了Linux命令,Python脚本也能跑通几个小例子,但一面对真实的 实战项目…

2026/9/22 16:01:03

哨兵日记源码解析:解决版本升级API失效的实战项目

哨兵日记源码解析:解决版本升级API失效的实战项目 版本升级后 API 全变了?别急着骂街,先看看【哨兵日记】的源码解析。 我见过太多团队,在升级 Sentinel 1.8 到 1.9 时,因为熔断降级规则字段变更,导致线上服务雪崩。…

2026/9/22 10:02:42

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/22 9:07:39

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/22 0:04:49

输电线路在线监测高频面试题拆解 3秒抓住官方文档重点

输电线路在线监测高频面试题拆解 3秒抓住官方文档重点 官方文档几百页翻到头还是懵?面试问到 输电线路在线监测 的数据链路时,脑子一片空白?别慌,这种 高频面试题 我整理了10年,专门治各种“文档太长抓不住重点”的毛病。…

2026/9/22 0:04:49

中介房源管理系统重构避坑:3个关键步骤搞定API变更

中介房源管理系统重构避坑:3个关键步骤搞定API变更 版本升级后 API 全变了,这种痛只有真做过的人懂。 很多团队在接手老旧房产项目时,最崩溃的不是代码烂,而是底层框架升级后,原本熟悉的接口调用方式彻底失效。 这份 保姆级教程…

2026/9/22 0:04:49

3个坑点带你一文搞懂55gg小游戏源码

3个坑点带你一文搞懂55gg小游戏源码 盯着控制台满屏的红色报错,看着那一长串 StackTrace ,是不是脑子瞬间宕机?别急,这种时候最忌讳的就是盲目改代码。很多刚入行的前端同学,面对 55gg 小游戏这类轻量级 H5…

2026/9/20 4:54:47

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/21 18:32:12

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码