计算机体系结构 27:NUMA 与数据放置
计算机体系结构 27:NUMA 与数据放置
核心问题
虚拟地址分配成功时,物理页是否已经落在某个 NUMA 节点?通常不能这样判断。Linux 的 NUMA policy 约束页面分配选择,但匿名页常在首次触发实际分配时才获得物理页。线程在哪个 CPU 上触页、策略允许哪些节点、页面后来是否迁移,都会改变数据位置。
本篇用双节点手算说明本地页和远端页怎样改变访问成本。当前环境没有 NUMA 拓扑、CPU 绑定、驻留页或迁移的真机证据。
附件:27-numa.json。
范围与证据等级
题设只有两个节点。本地页访问成本定为 100 ns,远端页定为 170 ns;这两个数是模型输入,不是从当前主机测得。模型按访问次数加权求和,不模拟队列、互联拥塞、缓存命中、预取、页大小差异或内存带宽。
证据等级是手算。Python 只负责复算和保存结果,不能把它升级为教学时序模型或真机测量。
policy、绑定与驻留是三件事
Linux NUMA policy 可以作用于 system、task、VMA 或 shared mapping。task policy 通常影响之后发生的页分配;修改策略不会自动证明已有页已经迁移。cpuset 还会缩小策略可用的节点集合。
因此,一份可解释的真机报告至少需要四类信息:机器拓扑、线程 CPU 绑定、触页顺序、实际页面驻留。只保留 numactl 命令没有回读 numa_maps,仍不能确认数据在哪个节点。
核心案例:同样十六次访问
题设 A 有 12 次本地访问和 4 次远端访问:
1 | |
题设 B 把分布倒过来,4 次本地、12 次远端:
1 | |
两者只差页面放置,B 的题设总成本高 560 ns。这个结果说明放置能影响成本,却不能预测真实程序的运行时间。实际访问可能被 cache 命中,多个请求可以重叠,互联还会排队。
模式:策略声明必须配状态回读
这个模式不只适用于 NUMA。设置 CPU affinity、I/O scheduler 或 huge page 策略时,命令成功只表示请求被接受;实际状态需要从对应内核接口回读。NUMA 的最小证据链是:拓扑 → 绑定 → 触页 → 驻留 → 测量。
验收结果
python3 examples/computer-architecture/run_batch.py 26-28 生成两个手算案例,并在输出中保留 not_a_host_numa_measurement=true。两组加权和分别为 1880 ns 与 2440 ns。
验收只证明题设算式一致。当前没有 numactl --hardware、taskset、numa_maps、move_pages 或迁移前后计时;旧 NUMA 文章中的示例数字也没有被挪作本篇实测。
练习
某页被线程 A 首次触碰后,线程 A 迁移到另一节点。只知道 first-touch 能否判断后续访问一定本地?列出仍需观察的状态。
在 8 次本地、8 次远端的相同题设下计算平均成本,并说明为何平均延迟不能代替带宽测量。
模式速查
| 关键词 | 检查链路 | 证据不足时的表述 |
|---|---|---|
| first-touch | 触页线程与实际驻留 | 页面预计按策略分配 |
| bind | CPU 集合与 cpuset | 已请求绑定,不等于页已迁移 |
| remote cost | 拓扑、驻留、计数或基准 | 仅为模型题设 |




