mcpField
N
numa-programming

numa-programming

github.com/mohitmishra786開発269299 回インストール18 週間前に更新
リポジトリ

numa-programming について

マルチソケットサーバーや高性能ソフトウェアを扱う開発者向けの NUMA プログラミングスキルです。トポロジー検出、メモリとスレッドの配置、データ構造、リモートアクセス診断を解説します。

主な機能

  1. 01NUMA トポロジーとノード距離の確認
  2. 02プロセス、スレッド、メモリのバインド
  3. 03libnuma によるメモリ割り当てと移動
  4. 04ノード単位のデータ構造設計
  5. 05perf によるリモートアクセス診断
  6. 06lstopo によるハードウェア構成の可視化

活用シーン

  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 プログラミング

目的

NUMA を考慮したプログラミングについてエージェントをガイドします。numactl と sysfs によるトポロジー検出、libnuma API(numa_alloc_onnode、mbind、set_mempolicy)、numactl によるプロセスのバインド、NUMA を考慮したデータ構造、perf stat によるリモートアクセスの診断、lstopo による可視化を扱います。

使用する場面

  • マルチソケットサーバーで、CPU 使用率が低いにもかかわらずスケーリングが不十分な場合
  • 1 つの NUMA ノードでメモリ帯域幅が飽和している場合
  • データベースやキャッシュのプロセスをローカルメモリにバインドする場合
  • ノードごとのフリーリストやシャーディングされたアロケーターを設計する場合
  • リモートメモリアクセスとローカルメモリアクセスのレイテンシーを測定する場合
  • 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 はローカル、それより大きい値はリモート(ソケット間)です。

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 の NIC 配置には不可欠です。

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

よくある問題

症状原因対処法
他の場所に空き RAM があるのに、1 つのノードで OOM が発生するMPOL_BIND の制約が厳しすぎる--preferred を使うか、インターリーブする
スレッド数を増やした後に 2 倍遅くなるリモートメモリアクセスCPU ノードに合わせて numactl --membind を指定する
ベンチマーク結果にばらつきがあるOS がページを移行したmbind で MPOL_BIND を指定する。必要に応じて mlock を使う
DPDK NIC が誤ったソケットにあるPCI デバイスが CPU から遠いlstopo を使い、EAL をローカルソケットにバインドする
libnuma が見つからないパッケージがインストールされていないapt install libnuma-dev
First-touch ポリシーによる想定外の動作ノード 0 で割り当て、ノード 1 で実行しているバインドしたスレッドから割り当てる

関連スキル

  • skills/allocators/custom-allocators — ノードごとのプールアロケーター
  • skills/async-io/dpdk — rte_malloc_socket、NIC の NUMA 局所性
  • skills/hpc/mpi — NUMA ノードごとの MPI プロセスのバインド
  • skills/profilers/hardware-counters — キャッシュミスの測定
  • skills/profilers/linux-perf — perf の NUMA イベント
  • skills/low-level-programming/cpu-cache-opt — キャッシュ局所性の基礎

コメント