NUMA Architecture and Memory Affinity

Keywords: numa architecture memory access,numa node affinity,libnuma binding,first touch policy numa,remote numa penalty

NUMA Architecture and Memory Affinity enable explicit placement of data and threads on multi-socket systems to exploit local memory bandwidth and latency, critical for HPC and data-center applications scaling to 100s of cores.

Non-Uniform Memory Access Topology

- NUMA Organization: Multiple sockets (CPUs), each with local memory attached. Local socket memory ~100ns latency, remote socket memory ~200-400ns (2-4x penalty).
- Memory Bandwidth Asymmetry: Local DRAM bandwidth (say 100 GB/s) shared with other local cores. Remote DRAM bandwidth crossed via QPI/Infinity Fabric interconnect (less bandwidth than local).
- Example Topology: Dual-socket Xeon with 32 cores per socket. Each core can access both socket's memory, but local access preferred.
- UMA vs NUMA: Older systems uniform memory access (UMA) via shared front-side bus. Modern systems inherently NUMA due to scaling limitations of centralized memory controller.

NUMA Node Binding and Thread Affinity

- NUMA Node Definition: Logical grouping of cores + associated memory. Socket-based binding: threads pinned to cores in same socket as their data.
- numactl Command: numactl --membind=node0 --cpunodebind=node0 application. Forces threads/memory to specific NUMA node. Prevents OS migration.
- libnuma Library: Programmatic NUMA control. numa_alloc_onnode(), numa_bind(), numa_set_preferred(). Enables application-level NUMA awareness.
- cpuset Cgroups: Linux control groups restrict processes to CPU/memory subsets. System-wide NUMA orchestration via cgroups.

First-Touch Policy

- Memory Allocation Mechanism: Pages allocated to NUMA node of thread first accessing page (write). OS tracks page residency.
- Default Behavior: malloc() allocates from kernel's allocator, typically interleaved across nodes (round-robin). Application overrides via numa_alloc_onnode().
- First-Touch Implication: Thread A allocates array B but doesn't initialize; Thread B initializes B. B ends up on B's node (correct affinity).
- Guideline: Initialize data on thread that will access it, or explicitly allocate on target node before other threads touch.

Remote vs Local Memory Latency Impact

- Latency Difference: Local ~100ns, remote ~300ns (3x penalty). Impacts iterative workloads (large loop counts × remote access = significant slowdown).
- Bandwidth Scaling: Remote bandwidth congested by all-to-all access patterns. Single-socket bandwidth ~100 GB/s; multi-socket aggregate ~150-200 GB/s (sub-linear).
- Cache Effects: L3 cache (8-20 MB per socket) mitigates some remote access penalties. If working set fits in L3, remote penalty minimal.
- Example Impact: 1000-iteration loop accessing remote memory: 1000 × 200ns = 200µs (remote) vs 100µs (local). 2x slowdown possible.

NUMA-Aware Data Structures

- Replicated Data: Hot data replicated per socket (each socket has copy). Slight memory overhead but eliminates remote access.
- Data Partitioning: Divide large arrays by NUMA node. Thread i processes array[i×partition_size:(i+1)×partition_size]. Guarantees local access.
- Hash Table Striping: Hash table buckets assigned to NUMA nodes. Hash function distributes keys across nodes balancing load and access locality.
- Graph Partitioning: Graph algorithms (matrix computations, machine learning) partition vertices/edges by NUMA locality. Minimize cross-node edges.

Memory Interleaving vs Binding

- Interleaved Mode: OS spreads pages round-robin across NUMA nodes. Balances memory usage but serializes remote access across all nodes. Poor latency.
- Bound Mode: Pages allocated on specific node. Requires explicit NUMA awareness (application or numactl). Excellent latency but requires work distribution matching binding.
- Hybrid Approaches: Bind hot/critical data to local node, interleave cold data. Best of both worlds.

NUMA Scheduling and OS Coordination

- OS NUMA Scheduler: Linux kernel scheduler (CFS) considers NUMA locality. Migrates threads toward memory (if cheaper than migrating memory).
- Task Scheduler Trade-offs: Migrate thread (cache cold) vs keep thread (remote memory). Decision based on current load, task runtime, memory intensity.
- AutoNUMA: Linux feature periodically migrates pages toward threads that access them (and vice versa). Reduces manual tuning but adds overhead.

NUMA in Multi-Socket HPC Servers

- Dual/Quad Socket Systems: 2-4 sockets per server, 64-256 cores total. Typical HPC configuration in data centers.
- Binding Strategy: MPI ranks bound to NUMA nodes (one rank per node). Inter-rank communication via network (InfiniBand) not NUMA crossings.
- Memory Scaling: Dual-socket Xeon: 256 GB-1 TB memory (128GB-512GB per socket). Single-node jobs fit; larger jobs spill to other nodes (network-based, slower).
- Benchmark Sensitivity: STREAM benchmark 5-10x slower on remote nodes vs local. Gemm (compute-bound) largely unaffected by NUMA.

Want to learn more?

Search 13,225+ semiconductor and AI topics or chat with our AI assistant.

Search Topics Chat with CFSGPT