NUMA Memory Planner
Plan memory allocation across NUMA nodes to minimize remote memory access latency.
Inputs
Typical inter-socket penalty: ~50-100ns additional latency
Local Access Ratio
75.00%
Average Memory Access Latency (ns)
98.75
Latency Overhead vs. All-Local
23.44%
Remote Accesses
250,000
Recommendation
Reasonable locality — consider numactl --membind or --cpunodebind for latency-sensitive workloads to push this higher.
Step by step
Values used
Total Memory Accesses (sampled) = 1,000,000; Local Node Accesses = 750,000; Local Access Latency (ns) = 80; Remote Access Penalty (ns, additional) = 75
Average memory latency
avg_latency = local_ratio × local_latency + remote_ratio × (local_latency + remote_penalty)
Local Access Ratio
= 75.00
Average Memory Access Latency (ns)
= 98.75
Latency Overhead vs. All-Local
= 23.44
Remote Accesses
= 250,000
Recommendation
= Reasonable locality — consider numactl --membind or --cpunodebind for latency-sensitive workloads to push this higher.
How it works
On multi-socket (NUMA — Non-Uniform Memory Access) systems, each CPU socket has its own locally-attached memory; accessing memory attached to a different socket ('remote' access) crosses an inter-socket interconnect and costs additional latency, typically 50-100ns on top of local access latency. The local access ratio — measurable via `numastat` or perf's NUMA events — directly determines average effective memory latency; tools like numactl let you bind a process's memory allocations and CPU execution to the same node to maximize this ratio.
Formula
Average memory latency
avg_latency = local_ratio × local_latency + remote_ratio × (local_latency + remote_penalty)
- r_l
- local access ratio
- L_local
- local access latency
- P_remote
- remote access penalty
Frequently Asked Questions
How do I check NUMA locality on a running system?
`numastat -p <pid>` shows a process's memory allocation split across NUMA nodes, and `numastat` alone shows system-wide hit/miss statistics (numa_hit vs numa_miss/numa_foreign) that indicate how often memory ended up on a different node than where it was allocated from.
How do I force a process to use local memory?
`numactl --cpunodebind=0 --membind=0 <command>` pins both CPU execution and memory allocation to NUMA node 0, ensuring the process's memory accesses stay local. For already-running processes, `numactl` alone can't rebind, but taskset combined with careful memory migration tools can help.
Does NUMA matter on single-socket systems?
Largely no for cross-socket effects, but some modern single-socket CPUs still expose multiple NUMA nodes internally (e.g. AMD's chiplet designs can present each CCX or CCD as a separate NUMA node), so it's worth checking `numactl --hardware` even on nominally single-socket servers.