Read NUMA Memory Placement with numastat
numastat turns the kernel's per-node NUMA counters into a report you can actually read. It never touches CPU affinity, memory policy or process state while doing it. By the end you will read the kernel counters, inspect one process's resident memory, and produce a compact report that is useful on a wide machine.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need the numastat command from the numactl package. This guide was checked with numactl 2.0.18 on a Linux host. Allow about 10 minutes for a first pass. You do not need root, though reading another user's process data can depend on the host's /proc permissions.
1. Confirm the command and its default report
Check the installed version first:
$ numastat -V
2.0.18
Worth recording alongside any performance report, since output details and available options belong to the installed numactl build. If the command is missing, install the distribution package named numactl through your normal package-management process; that is an administrative change and sits outside the read-only workflow here.
Now run the report with no options:
$ numastat
node0
numa_hit 20524362786
numa_miss 0
numa_foreign 0
interleave_hit 30
local_node 20525666111
other_node 0
- Units are pages, not megabytes. Columns are NUMA nodes.
numa_hitcounts allocations made on the intended node;numa_misscounts allocations made elsewhere, paired with anuma_foreigncount on the node that was meant to get them.local_nodeandother_nodedescribe allocation while a process ran on the allocating node versus another one.- These counters are cumulative. They describe activity since the counters were initialised, not a fresh sample window.
Do not read a zero as proof the host has no NUMA issue: a single-node machine has no remote node to expose, and a quiet workload may simply not have triggered the event yet.
2. Inspect system memory by node
Ask for the meminfo-like system view:
$ numastat -m
This prints rows similar to /proc/meminfo, with a column per node plus a total. It is the useful starting point when the question is "where is the resident system memory actually sitting". Expect rows such as MemTotal, MemFree, Active, Inactive, AnonPages, FilePages and Slab. Node count and values are host-specific, so save the output rather than relying on a fixed column layout.
Combine megabyte units with a narrower display when the terminal is tight:
$ numastat -m -c -z
-c shrinks columns based on their contents and rounds displayed memory to the nearest megabyte. -z drops rows and columns that are all zero. On a host with many nodes that is the difference between a readable report and a screen full of empty columns, but a value can still round to a zero-looking display even when the underlying figure is non-zero.
3. Find a process's allocation
Start with the shell that is launching the command:
$ numastat -p "$$"
Per-node process memory usage (in MBs) for PID 2836398 (numastat)
Node 0 Total
--------------- ---------------
Heap 0.01 0.01
Stack 0.02 0.02
Private 1.69 1.69
---------------- --------------- ---------------
Total 1.71 1.71
$$ expands to the shell's own PID. Depending on how your shell launches the final command, the displayed process name can end up being the shell or numastat itself. To inspect a different process, use a numeric PID instead:
$ numastat -p 1234
Replace 1234 with a PID that actually exists on your host. The report reads resident pages through /proc/<PID>/numa_maps, so it is not a full accounting of virtual address space, and a process that exits mid-read can leave you with incomplete or unavailable data. Retry against a live PID before treating that as a real result.
When you do not know the PID, search command lines by text instead:
$ numastat -p qemu
$ numastat libvirt kvm qemu
Non-numeric arguments are treated as fragments to search for in process command lines; the second form searches several fragments at once, and -p is optional there. A broad fragment can catch helper processes along with the service you actually meant, so check the names and PIDs it returns. Add -v for detail on each matching process instead of only aggregate lines:
$ numastat -p qemu -v
4. Sort and capture repeatable output
Sort the largest consumers to the top:
$ numastat -m -s
$ numastat -p qemu -s2
With no node number, -s sorts by the total column; -s2 sorts by node 2. The node number must touch the option with no space, and because -s takes an optional argument, put it last in a combined string: -mcs works, -msc does not do what you want.
Set an explicit output width when redirecting or logging:
$ NUMASTAT_WIDTH=120 numastat -m > /tmp/numastat-memory.txt
$ sed -n '1,20p' /tmp/numastat-memory.txt
Interactive output normally targets an 80-column terminal and may use the resize command where available, but redirected output can run long. NUMASTAT_WIDTH gives a stable width for logs and comparisons. The file above is a temporary, non-destructive capture; clean it up with rm -- /tmp/numastat-memory.txt once you are done with it.
Common traps
- Mixing units: the no-option report is in pages.
-npresents the original statistics in megabytes, while-mpresents system memory in megabytes. Never compare a raw default number directly against a process total. - Assuming a snapshot: the default counters accumulate. For a live view, use
watch -n1 numastat, but each screen is still a cumulative reading. Stop it withCtrl-C. - Over-interpreting rounding: compact mode rounds values, so a zero-looking row can still hide a small non-zero value. Drop
-cwhen the distinction actually matters. - Using a name that matches too much: process patterns search command lines, not service-manager unit names. Prefer a verified PID for an incident report.
- Expecting a tuning tool: numastat reports resident memory and allocation counters, it does not move memory or change policy. Reach for a separate, reviewed NUMA policy tool when you actually need to change placement.
Done means
- Recorded the installed numastat version.
- Can tell page-based default counters apart from the megabyte reports.
- Inspected system memory with
-mand a process with-p. - Can reduce wide output with
-c, hide empty data with-z, and sort with-s. - Know the examples read state only, and that a process disappearing mid-inspection needs a retry, not a conclusion.