Home / Alt manpages / numactl(8)

  • numactl(8)
  • Admin command
  • linux

Pin a Linux Process to NUMA CPUs and Memory with numactl

You will inspect this host's NUMA layout, run a process on a chosen NUMA node, constrain its memory allocations, and verify the policy from the process itself. The examples use numactl 2.0.18 from Ubuntu package 2.0.18-1ubuntu0.24.04.1, as installed on this machine.

Allow about fifteen minutes. You need a shell and a NUMA-aware Linux kernel. The examples use /bin/true and numactl --show, so they do not change a service or persistent system configuration. Use elevated privileges only if the command you are testing already requires them.

1. Check the installed command and topology

Start with read-only checks. These do not need sudo:

$ command -v numactl
/usr/bin/numactl
$ numactl --version
numactl version 2.0.18
$ numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3 4 5 6 7

Your output will differ. --hardware lists the available NUMA nodes, the CPUs associated with each node, memory sizes and node distances. Record the node numbers before writing a policy. A single-node machine can still accept numactl policies, but there is no placement choice to measure.

Checkpoint: choose a node shown by --hardware. The examples below use node 0 because it exists on this host. Replace it with a real node number on another system.

2. See the current policy

Run --show in the shell you are using:

$ numactl --show
policy: default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7
cpubind: 0
nodebind: 0
membind: 0
preferred:

The exact CPU and node lists depend on the host and its cpuset. This output describes the current process policy, not a promise that every child has unrestricted access. Containers, service managers and parent processes can already restrict the allowed CPUs or nodes.

3. Bind a harmless process to CPUs and memory

Use --cpunodebind to select CPUs associated with a node and --membind to restrict allocation to nodes. The policy is inherited by the command's children:

$ numactl --cpunodebind=0 --membind=0 -- /bin/true
$ printf '%s\n' "$?"
0

An exit status of zero says that /bin/true ran and returned zero. It does not prove that a large application's working set fitted on the selected node. With --membind, allocation is restricted to the listed nodes and can fail when they do not have enough available memory. That is a deliberate failure mode, not an automatic fallback.

To inspect the policy while a child is alive, launch a shell that prints its own view:

$ numactl --cpunodebind=0 --membind=0 -- /bin/sh -c 'numactl --show'
policy: bind
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7
cpubind: 0
nodebind: 0
membind: 0

The CPU list may be wider than the node list because the command reports physical CPU availability as well as the node binding. The useful checks are nodebind: 0 and membind: 0 for this example.

4. Prefer memory without making it exclusive

--preferred selects one preferred node but allows allocation to fall back to other nodes if the preferred node cannot satisfy it. This is less strict than --membind:

$ numactl --preferred=0 -- /bin/sh -c 'numactl --show'
policy: preferred
preferred node: 0
preferred: 0

Use --localalloc when the policy should try the process's current node first and then fall back elsewhere. Use --interleave=0,1 when you have at least two real nodes and want allocations distributed round robin between them. Do not copy a multi-node example onto a single-node host and assume it provides balancing.

5. Keep command options in the right place

numactl parses options before the command. Put -- before a child command when its options could be mistaken for numactl options:

$ numactl --cpunodebind=0 --membind=0 -- /bin/sh -c 'printf "child ok: %s\n" yes'
child ok: yes

numactl does not run the child through a shell. Shell operators such as pipes and redirections only work when you explicitly use a shell wrapper, as above. Keep the wrapper and its arguments quoted carefully when values come from outside the script.

6. Choose a policy that matches the failure boundary

For a database or worker with a measured memory locality problem, start with --preferred or --localalloc. They preserve fallback behaviour while making the intended locality visible. Move to --membind only when you have tested the application's memory demand and want an allocation failure rather than remote-node fallback.

--balancing enables Linux kernel NUMA balancing when supported, but the manpage says it should be used with --membind only. It is not a general performance switch. Test it with the real workload and watch its latency and CPU cost before putting it in a service unit.

Do not add sudo merely because a policy failed. First check that the node exists, that the process's cpuset permits it, and that the selected node has enough memory. If you are launching a service, use the same account and service environment during testing. A root test can hide an access or cpuset problem affecting the real service.

7. Undo and verify the operational change

These command-line policies apply to the launched process and its children. They disappear when those processes exit; there is no persistent setting to undo in the examples above. To return a long-running service to its previous behaviour, stop it using its normal supervisor, remove the numactl wrapper or policy arguments from the service configuration, then start it through the supervisor again. Configuration changes may require elevated privileges and a maintenance window.

After starting the real command, verify from inside its process tree with numactl --show, or inspect the process's allowed CPUs and memory nodes through the usual host monitoring tools. Compare the result with the policy you intended, then measure the workload rather than treating a successful launch as a performance result.

Done means

  • You recorded valid node numbers from numactl --hardware.
  • You can distinguish strict --membind from fallback-friendly --preferred and --localalloc.
  • You verified the child policy with numactl --show.
  • You used -- when child arguments could be confused with numactl options.
  • You have a measured rollback path before applying the wrapper to a service.