set_mempolicy(2)
โจ set_mempolicy โ system calls manual โจ
okay bestie so this one is set_mempolicy(2) from the System Calls Manual and it's genuinely one of the most iconic NUMA girlies in the whole kernel. sit down, get a lil drink, we're doing memory policy ๐
๐ซถ NAME
set_mempolicy โ set the default NUMA memory policy for a thread and its children
no cap, that's the whole vibe. it sets your thread's whole memory-brain for what happens after.
๐ธ LIBRARY
NUMA (Non-Uniform Memory Access) policy library โ that's libnuma, and you link it with -lnuma.
โญ SYNOPSIS
#include <numaif.h>
long set_mempolicy(int mode, const unsigned long *nodemask,
unsigned long maxnode);
๐ DESCRIPTION
so set_mempolicy() sets the NUMA memory policy of the calling thread โ and that policy is two things: a mode, plus zero or more nodes. you hand it mode, nodemask, and maxnode, and it justโฆ does that. slay.
a NUMA machine has different memory controllers with different distances to specific CPUs. the memory policy is literally the answer to "which node does this thread's memory come from". that's it, that's the assignment.
This system call defines the default policy for the thread. and here's the hierarchy tea โ: the thread policy governs allocation of pages in the process's address space outside of memory ranges controlled by a more specific policy set by mbind(2). (specific policy beats default policy, always. main character energy for mbind.)
the thread default policy also controls allocation of:
- any pages for memory-mapped files mapped using the
mmap(2)call with theMAP_PRIVATEflag, that are only read (loaded) from by the thread, and - memory-mapped files mapped using
mmap(2)with theMAP_SHAREDflag, regardless of the access type.
the policy is applied only when a new page is allocated for the thread. for anonymous memory, that's when the page is first touched by the thread. so likeโฆ policy is a vibe check at allocation time, and after that the page is on its own fr.
the mode argument must specify one of MPOL_DEFAULT, MPOL_BIND, MPOL_INTERLEAVE, MPOL_WEIGHTED_INTERLEAVE, MPOL_PREFERRED, MPOL_PREFERRED_MANY, or MPOL_LOCAL โ all of them are described in detail below, don't worry, I got you. every mode except MPOL_DEFAULT requires the caller to specify the node or nodes the mode applies to, via the nodemask argument. no nodes, no policy, no service ๐.
๐ mode flags (optional, but make it fashion)
mode may also include an optional mode flag. the supported ones are:
MPOL_F_NUMA_BALANCING(since Linux 5.12) โ whenmodeisMPOL_BIND, enable the kernel NUMA balancing for the task if it's supported by the kernel. if the flag isn't supported by the kernel, or is used with amodeother thanMPOL_BIND,-1is returned anderrnois set toEINVAL. so if you mix it wrong it's giving error, not giving results ๐MPOL_F_RELATIVE_NODES(since Linux 2.6.26) โ a nonemptynodemaskspecifies node IDs that are relative to the set of node IDs allowed by the process's current cpuset.MPOL_F_STATIC_NODES(since Linux 2.6.26) โ a nonemptynodemaskspecifies physical node IDs. Linux will not remap the nodemask when the process moves to a different cpuset context, nor when the set of nodes allowed by the process's current cpuset context changes. it's the "I said what I said" flag.
๐ฆ the nodemask + maxnode situation
nodemask points to a bit mask of node IDs that contains up to maxnode bits. the bit mask size is rounded to the next multiple of sizeof(unsigned long), but the kernel will use bits only up to maxnode. (rounding up โ using the extra bits, bestie, don't get it twisted.)
a NULL value of nodemask or a maxnode value of zero specifies the empty set of nodes. and if maxnode is zero, the nodemask argument is justโฆ ignored. iconic, unbothered, not reading it.
where a nodemask is required, it must contain at least one node that is:
- on-line,
- allowed by the process's current cpuset context (unless the
MPOL_F_STATIC_NODESmode flag is specified), - and contains memory.
if MPOL_F_STATIC_NODES is set in mode and a required nodemask contains no nodes allowed by the process's current cpuset context, the memory policy reverts to local allocation. this effectively overrides the specified policy until the process's cpuset context includes one or more of the nodes specified by nodemask. so yeah, your policy is on pause until the cpuset catches up ๐ญ
๐ the modes, one by one
The mode argument must include one of the following values:
MPOL_DEFAULTโ removes any nondefault thread memory policy, so the memory policy "falls back" to the system default policy. the system default policy is "local allocation" โ allocate memory on the node of the CPU that triggered the allocation.nodemaskmust be specified asNULL. if the "local node" contains no free memory, the system will attempt to allocate memory from a "near by" node. (yes, near by, that's the phrase, keeping it.)MPOL_BINDโ a strict policy that restricts memory allocation to the nodes specified innodemask. ifnodemaskspecifies more than one node, page allocations come from the node with the lowest numeric node ID first, until that node contains no free memory. allocations then come from the node with the next highest node ID specified innodemask, and so forth, until none of the specified nodes contain free memory. pages will not be allocated from any node not specified in thenodemask. it's strict because it MEANS it.MPOL_INTERLEAVEโ interleaves page allocations across the nodes specified innodemaskin numeric node ID order. this optimizes for bandwidth instead of latency by spreading out pages and memory accesses to those pages across multiple nodes. however, accesses to a single page will still be limited to the memory bandwidth of a single node. spread the pages bestie, but a single page is still a single-page girl.MPOL_WEIGHTED_INTERLEAVE(since Linux 6.9) โ interleaves page allocations across the nodes specified innodemaskaccording to the weights in/sys/kernel/mm/mempolicy/weighted_interleave. for example: if bits0,2, and5are set innodemask, and the contents of/sys/kernel/mm/mempolicy/weighted_interleave/node0,/sys/.../node2, and/sys/.../node5are4,7, and9, respectively, then pages in this region will be allocated on nodes0,2, and5in a4:7:9ratio. ratios!! math!! she ate ๐ฅMPOL_PREFERREDโ sets the preferred node for allocation. the kernel will try to allocate pages from this node first and fall back to "near by" nodes if the preferred node is low on free memory. ifnodemaskspecifies more than one node ID, the first node in the mask will be selected as the preferred node. if thenodemaskandmaxnodearguments specify the empty set, then the policy specifies "local allocation" (like the system default policy discussed above).MPOL_PREFERRED_MANY(since Linux 5.15) โ specifies a preference for nodes from which the kernel will try to allocate from. this differs fromMPOL_PREFERREDin that it accepts a set of nodes versus a single node. this policy is intended to benefit page allocations where specific memory types (i.e., non-volatile, high-bandwidth, or accelerator memory) are of greater importance than node location. location? don't know her. memory type is the moment.MPOL_LOCAL(since Linux 3.8) โ specifies "local allocation": the memory is allocated on the node of the CPU that triggered the allocation (the "local node"). thenodemaskandmaxnodearguments must specify the empty set. if the "local node" is low on free memory, the kernel will try to allocate memory from other nodes. the kernel will allocate memory from the "local node" whenever memory for this node is available. if the "local node" is not allowed by the process's current cpuset context, the kernel will try to allocate memory from other nodes. the kernel will allocate memory from the "local node" whenever it becomes allowed by the process's current cpuset context. it's loyal, it keeps coming back ๐ซถ
the thread memory policy is preserved across an execve(2), and is inherited by child threads created using fork(2) or clone(2). generational wealth, but for memory policy ๐
๐ RETURN VALUE
glow-up moment: on success, set_mempolicy() returns 0. on error, -1 is returned and errno is set to indicate the error. that's it. that's the whole personality.
๐ ERRORS
EFAULTโ part of all of the memory range specified bynodemaskandmaxnodepoints outside your accessible address space.EINVALโmodeis invalid. or,modeisMPOL_DEFAULTandnodemaskis nonempty, ormodeisMPOL_BINDorMPOL_INTERLEAVEandnodemaskis empty. or,maxnodespecifies more than a page worth of bits. or,nodemaskspecifies one or more node IDs that are greater than the maximum supported node ID. or, none of the node IDs specified bynodemaskare on-line and allowed by the process's current cpuset context, or none of the specified nodes contain memory. or, themodeargument specified bothMPOL_F_STATIC_NODESandMPOL_F_RELATIVE_NODES. or, theMPOL_F_NUMA_BALANCINGisn't supported by the kernel, or is used withmodeother thanMPOL_BIND. that's a lot of ways to be wrong, and honestly? valid ofEINVAL.ENOMEMโ insufficient kernel memory was available.
๐ง STANDARDS
Linux. (just Linux. periodt.)
โญ HISTORY
Linux 2.6.7. old money.
๐ NOTES
memory policy is not remembered if the page is swapped out. when such a page is paged back in, it will use the policy of the thread or memory range that is in effect at the time the page is allocated. so the policy that matters is the one on duty at allocation o'clock, not the one from before the swap. the past is the past ๐
for information on library support, see numa(7).
๐ SEE ALSO
get_mempolicy(2), getcpu(2), mbind(2), mmap(2), numa(3), cpuset(7), numa(7), numactl(8)
okay that's the whole page, you're officially NUMA-literate ๐
cute lil sign-off: this rewrite is serving Linux man-pages 6.20, dated 2026-02-08, and the original page is set_mempolicy(2). mwah ๐ธ
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: Linux-man-pages-copyleft-var
- Copyright 2003-2004, Andi Kleen <andi@firstfloor.org>
- Copyright 2003-2004, SuSE GmbH
- Copyright 2007, Lee Schermerhorn <Lee.Schermerhorn@hp.com>
- Copyright 2007, Hewlett-Packard Development Company, L.P
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms