Multicore, Coherence & Thread-Level Parallelism

non-uniform memory access (NUMA)

/ NOO-mah /

Imagine a large open-plan office split into wings, where each wing has its own filing cabinet right beside it. Reaching the cabinet in your own wing is quick; fetching a folder from a cabinet three wings away means a long walk. Everyone can still reach every cabinet — it is one shared filing system — but how long it takes depends on where the folder lives relative to where you sit. Non-uniform memory access is a shared-memory machine built like this: memory is split into banks attached to different cores, and a core reaches its nearby (local) memory fast and far (remote) memory slowly.

Here is the structure. A large multiprocessor is divided into nodes; each node bundles some cores with a slice of the main memory and its own memory controller. The memory is still one shared address space — any core can read any address — but an access to memory in your own node is local and fast, while an access to memory homed on another node must travel across the interconnect and is remote and slower, often by a factor of two or more. This is why it is called non-uniform: latency depends on which node owns the data. It is the opposite of UMA, the uniform-access model of small SMP machines.

NUMA exists because strict uniform access does not scale: past a couple of dozen cores, you cannot give everyone equally-fast access to one central memory, so you distribute the memory and accept that distance now matters. The practical consequence is that data placement and thread placement become performance-critical — keep a thread's hot data in its own node's memory, and pin the thread there. The honest catch is that NUMA is largely invisible until it bites: a program is correct either way, but scatter a thread's data across remote nodes and it can run dramatically slower than the identical code with good placement. NUMA-aware allocation and scheduling are how large servers reclaim that lost speed.

A 2-socket server, each socket a NUMA node with its own RAM. A thread on socket 0 reading data stored in socket 0's RAM might take 100 ns; reading the same kind of data homed on socket 1's RAM might take 150 ns because the request crosses the inter-socket link. Same program, same correctness — but place the data on the wrong node and throughput sags.

Local memory is fast, remote memory is slower; correctness is unchanged but placement decides the speed — the essence of NUMA.

NUMA never changes a program's result, only its speed, so its cost is invisible in the source. Large multicore and multi-socket systems are NUMA, not the uniform SMP of textbooks — good data and thread placement can matter as much as the algorithm.

Also called
NUMAnon-uniform memory architecture非統一記憶體存取