mcpField
N
numa-programming

numa-programming

github.com/mohitmishra786开发269299 次安装18 周前更新
代码仓库

关于 numa-programming

面向多路服务器和高性能程序开发者的 NUMA 编程指南,介绍拓扑检测、内存与线程绑定、数据结构设计及远程访问诊断。

主要功能

  1. 01检测 NUMA 拓扑与节点距离
  2. 02绑定进程、线程和内存
  3. 03使用 libnuma 分配与迁移内存
  4. 04设计按节点划分的数据结构
  5. 05借助 perf 诊断远程访问
  6. 06通过 lstopo 查看硬件布局

适用场景

  1. 01排查多路系统扩展性不佳
  2. 02让数据库或缓存使用本地内存
  3. 03为分片分配器设计节点内存池
  4. 04比较本地与远程内存访问

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill numa-programming

安装后在 Claude Code 中输入/numa-programming确认已加载。

详细介绍

NUMA 编程

用途

引导 Agent 进行 NUMA 感知编程:使用 numactl 和 sysfs 检测拓扑、使用 libnuma API(numa_alloc_onnode、mbind、set_mempolicy)、使用 numactl 绑定进程、设计 NUMA 感知数据结构、使用 perf stat 诊断远程访问,以及使用 lstopo 可视化。

适用场景

  • 多路服务器的 CPU 利用率较低,但扩展性不佳
  • 某个 NUMA 节点的内存带宽饱和
  • 将数据库或缓存进程绑定到本地内存
  • 设计按节点划分的空闲链表或分片分配器
  • 测量远程与本地内存访问延迟
  • 为 socket 局部性调优 HPC、DPDK 或自定义分配器

工作流

1. 检测拓扑
# Hardware topology summary
numactl --hardware

# Detailed topology with distances
lstopo --of console

# sysfs nodes
ls /sys/devices/system/node/
cat /sys/devices/system/node/node0/meminfo
cat /sys/devices/system/node/node0/cpulist

典型输出:

available: 2 nodes (0-1)
node 0 cpus: 0-15
node 0 size: 65536 MB
node 1 cpus: 16-31
node 1 size: 65536 MB
node distances:
node   0   1
  0:  10  21
  1:  21  10

距离 10 表示本地,更高的值表示远程(跨 socket)。

2. 使用 numactl 绑定进程
# Bind to node 0 CPUs and memory
numactl --cpunodebind=0 --membind=0 ./myapp

# Interleave memory across all nodes
numactl --interleave=all ./myapp

# Preferred node (fallback if full)
numactl --preferred=0 ./myapp

# Show process NUMA policy
numactl --show
cat /proc/self/numa_maps
3. libnuma API
#include <numa.h>
#include <numaif.h>
#include <stdio.h>

int main(void) {
    if (numa_available() < 0) {
        fprintf(stderr, "NUMA not available\n");
        return 1;
    }
    int node = numa_node_of_cpu(0);
    printf("CPU 0 on node %d\n", node);

    // Allocate on specific node
    size_t size = 1024 * 1024 * 1024;
    void *mem = numa_alloc_onnode(size, 0);
    if (!mem) return 1;

    // Bind existing memory
    unsigned long nodemask = 1UL << 0;
    mbind(mem, size, MPOL_BIND, &nodemask, sizeof(nodemask) * 8, 0);

    numa_free(mem, size);
    return 0;
}
gcc -o numa_test numa_test.c -lnuma
API用途
numa_alloc_onnode在指定节点上分配
numa_alloc_local在当前 CPU 所属节点上分配
mbind为现有映射设置策略
set_mempolicy设置后续分配的默认策略
move_pages将页面迁移到目标节点
4. NUMA 感知数据结构
// Per-node freelist — avoids cross-node synchronization
#define MAX_NODES 8
struct per_node_pool {
    void *free_list[MAX_NODES];
    int   node_count;
};

void *pool_alloc_numa(struct per_node_pool *p) {
    int node = numa_node_of_cpu(sched_getcpu());
    void *blk = p->free_list[node];
    if (blk) {
        p->free_list[node] = *(void **)blk;
        return blk;
    }
    return numa_alloc_onnode(BLOCK_SIZE, node);
}

将线程固定到与其内存池位于同一节点上的核心。

5. 对齐线程亲和性
# Pin thread 0 to CPU 0 (node 0), allocate on node 0
numactl --cpunodebind=0 --membind=0 ./worker --id 0
numactl --cpunodebind=1 --membind=1 ./worker --id 1
#include <pthread.h>
#include <sched.h>

cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(target_cpu, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
6. 诊断远程访问
# Cache misses often spike with remote memory
perf stat -e cache-misses,cache-references,node-load-misses \
    numactl --cpunodebind=0 --membind=1 ./myapp

# Compare local vs remote binding
perf stat numactl --cpunodebind=0 --membind=0 ./myapp
perf stat numactl --cpunodebind=0 --membind=1 ./myapp
# NUMA hit/miss stats (if available)
perf stat -e node-loads,node-load-misses,node-stores ./myapp
7. 测量远程访问开销
// Microbenchmark: touch 1GB on local vs remote node
clock_t start = clock();
for (size_t i = 0; i < size; i += 4096)
    sum += ((char *)mem)[i];

根据互连(QPI/UPI/Infinity Fabric)的不同,远程访问预计会慢 1.5–3 倍。

8. 使用 lstopo 可视化
# Graphical (if X11)
lstopo

# Text with memory/PCI
lstopo --of ascii

# Export for documentation
lstopo file.png

显示:NUMA 节点、核心、缓存、PCI 设备——对于 DPDK 网卡部署至关重要。

9. 决策树
Poor scaling on multi-socket?
├── Check numactl --hardware
├── Verify thread and memory on same node
├── perf stat node-load-misses
├── Remote misses high?
│   ├── numactl --membind=local
│   └── Per-node data partitioning
└── Still slow → memory bandwidth bound; reduce sharing

常见问题

症状原因解决方法
某个节点内存耗尽,但其他节点仍有空闲内存MPOL_BIND 过于严格使用 --preferred 或交错分配
线程数增加后速度慢了 2 倍远程内存访问使用 numactl --membind,与 CPU 节点匹配
基准测试结果不一致操作系统迁移了页面使用 mbind 设置 MPOL_BIND;必要时使用 mlock
DPDK 网卡位于错误的 socketPCI 设备离 CPU 较远使用 lstopo;将 EAL 绑定到本地 socket
找不到 libnuma未安装软件包apt install libnuma-dev
首次触碰策略令人意外在节点 0 上分配,却在节点 1 上运行从已绑定的线程进行分配

相关技能

  • skills/allocators/custom-allocators — 按节点划分的内存池分配器
  • skills/async-io/dpdk — rte_malloc_socket、网卡 NUMA 局部性
  • skills/hpc/mpi — 按 NUMA 节点绑定 MPI 进程
  • skills/profilers/hardware-counters — 测量缓存未命中
  • skills/profilers/linux-perf — perf NUMA 事件
  • skills/low-level-programming/cpu-cache-opt — 缓存局部性基础

评论

支持 Markdown