Skip to content
Calcrivo

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

  1. 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

  2. Average memory latency

    avg_latency = local_ratio × local_latency + remote_ratio × (local_latency + remote_penalty)

  3. Local Access Ratio

    = 75.00

  4. Average Memory Access Latency (ns)

    = 98.75

  5. Latency Overhead vs. All-Local

    = 23.44

  6. Remote Accesses

    = 250,000

  7. 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.

You might also need