Skip to content

numactl - NUMA CPU & Memory Binding Cheatsheet

numactl - NUMA CPU & Memory Binding Cheatsheet

numactl controls NUMA (Non-Uniform Memory Access) policy for processes. On multi-socket servers, memory attached to one CPU socket (node) is faster for that socket to access than memory on another node; a process bouncing between nodes pays a latency penalty. numactl lets you bind a process to specific NUMA nodes — pinning its CPUs and its memory to the same node — which can significantly improve performance for memory-bound workloads like databases and HPC jobs.

Installation

PlatformCommand
Debian/Ubuntusudo apt install numactl
Fedora/RHELsudo dnf install numactl
Arch Linuxsudo pacman -S numactl
Verifynumactl --version

Inspecting Topology

CommandShows
numactl --hardware (-H)NUMA nodes, CPUs per node, memory per node, distances
numactl --show (-s)Current process’s NUMA policy
numastatPer-node memory allocation hit/miss stats
lscpuCPU-to-node mapping (NUMA node CPUs)
# See how many NUMA nodes and which CPUs/memory belong to each
numactl --hardware

Binding a Process

CommandEffect
numactl --cpunodebind=0 --membind=0 ./appRun on node 0’s CPUs and memory
numactl -N 1 -m 1 ./appShort form: node 1 CPUs + memory
numactl --physcpubind=0-7 ./appBind to specific CPU cores
numactl --membind=0,1 ./appAllow memory from nodes 0 and 1
numactl --interleave=all ./appSpread memory across all nodes (round-robin)

Memory Policies

PolicyFlagMeaning
Bind--membind=NODESOnly allocate from these nodes (fail if full)
Preferred--preferred=NODEPrefer a node, fall back if needed
Interleave--interleave=NODESRound-robin across nodes (bandwidth)
Local--localallocAllocate on the node the thread runs on

When to Use Which

GoalPolicy
Latency-sensitive, fits in one node--cpunodebind=N --membind=N (co-locate)
Bandwidth-bound, large footprint--interleave=all
Mostly one node, occasional spill--preferred=N
Let the kernel decide locally--localalloc

Common Workflows

# Pin a database to node 0 to avoid cross-node memory latency
numactl --cpunodebind=0 --membind=0 postgres -D /data

# Bandwidth-heavy analytics: interleave memory across all nodes
numactl --interleave=all ./analytics-job

# Reserve specific cores for a real-time process
numactl --physcpubind=8-15 --membind=1 ./rt-app

# Check what policy a running setup uses
numactl --show
ToolRole
numactlSet NUMA CPU/memory policy per process
numastatMonitor per-node allocation efficiency
tasksetCPU affinity (without NUMA memory policy)
cpupowerCPU frequency/governor tuning
kernel numa_balancingAutomatic NUMA balancing (/proc/sys/kernel)

Pair numactl with cpupower for frequency control; use numastat to confirm your binding actually reduced cross-node misses.

Verifying the Win

# Before/after: watch numa_miss / numa_foreign drop after binding
numastat -p $(pgrep -n app)

High numa_miss / numa_foreign means memory is being served from a remote node — exactly what binding fixes.

Resources