别让你的内存跑马拉松
1. 问题
多路服务器上,CPU 和内存不在同一个节点时,每次访问多走一条跨节点总线。
延迟翻倍,带宽打折。这就是你 128 核跑不过 64 核的原因。
| 随机分配 | 绑定本地节点 | |
|---|---|---|
| 延迟 | ~200ns | ~80ns |
| 带宽 | 跨节点总线(共享) | 本地内存(独享) |
2. Take Away
内存分配不是"给一块空间",而是"给一块空间 + 决定它在哪"。
malloc只做了前半件事。后半件事要用mbind(MPOL_BIND)把物理页钉到目标节点。
3. 怎么做
auto&rm=umpire::ResourceManager::getInstance();autonodes=umpire::numa::get_host_nodes();autonode0=rm.makeAllocator<umpire::strategy::NumaPolicy>("node0",rm.getAllocator("HOST"),nodes[0]);void*ptr=node0.allocate(size);// 数据自动在 Node 0位置不对?一行搬过去:
rm.move(ptr,node0);// 指针不变,物理页瞬移4. 三条规律
- 先 malloc 后 mbind— 预留地址空间,再绑定物理页。指针地址不变,业务代码不用改。
- move 是原地操作— VA 不变,PA 变。迁移完了指针还是那个指针。
- 同一个 move API,Host NUMA 和 GPU 都能用— 局部性问题在不同尺度上是同一件事。
5. 验证
numactl--hardware# 看拓扑umpire::numa::get_location# 看位置perfstat-enuma_miss# 看效果