In this lesson, you will learn how to optimize your application's performance by pinning processes to specific CPU cores and their local memory banks.
Understanding the Cache Hierarchy
In modern multi-socket servers, we use an architecture called NUMA (Non-Uniform Memory Access). Each CPU "node" has its own local bank of memory. Accessing memory attached to your own CPU socket is lightning-fast, but accessing memory attached to a different socket requires crossing a slower interconnect, which adds latency and degrades performance.
When a process bounces between different CPU cores, it loses the benefit of its L1 and L2 caches, which are private to each core. To keep your application running at peak efficiency, we want to ensure the process stays "local"—both to the CPU cache and the local memory bank.
Pinning with taskset
To force a process to remain on a specific CPU core (maintaining cache affinity), we use the taskset utility. This prevents the Linux scheduler from migrating your process to a distant core.
For example, to pin a process to CPU 0, you would run:
taskset -c 0 ./my-high-performance-app
NUMA-Awareness
If your server is NUMA-capable, simply pinning to a CPU core isn't enough; you also want to ensure the memory the process allocates resides on the local NUMA node. You can combine CPU affinity with memory policy using numactl.
The following command runs your application on CPU cores 0-3 and restricts its memory allocation to the memory bank associated with node 0:
numactl --physcpubind=0-3 --localalloc ./my-high-performance-app
By using --localalloc, you instruct the kernel to prefer memory pages that are physically closest to the assigned CPU cores. This minimizes the "NUMA penalty"—the latency incurred when a CPU has to fetch data from a remote memory controller. When used together, these techniques reduce cache misses and interconnect traffic, ensuring your process executes with consistent, low-latency performance.
Key Takeaway: By pinning processes to specific cores with taskset and forcing memory allocation to local NUMA nodes with numactl, you prevent performance degradation caused by cache misses and cross-socket memory latency.