In multi-core systems, Linux by default uses all available CPU cores for process scheduling. However, there are scenarios where you might want to restrict certain processes to specific cores:
- Preventing cache pollution in performance-critical applications
- Isolating workloads for better predictability
- Creating dedicated cores for real-time processes
- Testing multi-core application behavior
Linux provides several ways to control CPU affinity:
1. taskset Command
The most straightforward method is using the taskset
utility:
# Launch a process pinned to CPU 0
taskset -c 0 ./my_process &
# Set affinity for existing process (PID 1234) to CPUs 0 and 1
taskset -cp 0,1 1234
2. sched_setaffinity System Call
For programmatic control, use the sched_setaffinity
system call:
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
int main() {
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask); // Use only CPU 0
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
perror("sched_setaffinity");
return 1;
}
// Process now runs only on CPU 0
while(1) { /* work */ }
return 0;
}
For more sophisticated control:
Using cgroups
# Create a cgroup
mkdir /sys/fs/cgroup/cpuset/my_group
# Set allowed CPUs
echo 2-3 > /sys/fs/cgroup/cpuset/my_group/cpuset.cpus
# Add process to cgroup
echo <pid> > /sys/fs/cgroup/cpuset/my_group/tasks
Kernel Boot Parameter
For permanent core isolation, add to your kernel boot parameters:
isolcpus=2,3 # Reserve CPUs 2 and 3 for exclusive use
Check process CPU affinity with:
taskset -p <pid>
# Or
cat /proc/<pid>/status | grep Cpus_allowed
Monitor CPU usage with:
top -H -p <pid> # Show thread-level CPU usage
mpstat -P ALL 1 # Monitor per-CPU utilization
- NUMA architecture awareness is crucial for memory-bound processes
- Hyperthreading cores share resources - pinning to physical cores might be preferable
- Over-pinning can lead to underutilization
- Consider process priorities (
nice
values) alongside affinity
When dealing with multi-core systems, Linux provides robust mechanisms for controlling process scheduling through CPU affinity
. This feature allows administrators and developers to bind processes to specific CPU cores, which is particularly useful for:
- Optimizing cache utilization
- Reducing context switching overhead
- Isolating critical processes
- Benchmarking performance
The primary methods for managing CPU affinity include:
1. taskset Command
The simplest way to set CPU affinity is using the taskset
utility:
# Start a process bound to CPU 0
taskset -c 0 ./my_process &
# Change affinity of running process (PID 1234) to CPUs 0 and 2
taskset -pc 0,2 1234
2. sched_setaffinity System Call
For programmatic control, use the sched_setaffinity
system call:
#define _GNU_SOURCE
#include <sched.h>
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask); // Use only CPU 0
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
perror("sched_setaffinity");
}
Isolating CPU Cores at Boot
For maximum isolation, add to your kernel boot parameters:
isolcpus=1,3 # Isolate CPUs 1 and 3 from general scheduling
Using cgroups v2
For modern systems with cgroups v2:
# Create new cgroup
mkdir /sys/fs/cgroup/cpuset/my_group
# Set allowed CPUs
echo 2 > /sys/fs/cgroup/cpuset/my_group/cpuset.cpus
# Add process
echo $PID > /sys/fs/cgroup/cpuset/my_group/cgroup.procs
When pinning processes:
- Monitor cache hit rates with
perf stat -e cache-misses
- Check for load balancing issues using
mpstat -P ALL 1
- Consider NUMA architecture with
numactl --hardware
Here's a complete Python wrapper using ctypes:
import ctypes
import os
libc = ctypes.CDLL('libc.so.6')
mask = (ctypes.c_ulong * 1)(1 << 0) # CPU 0
if libc.sched_setaffinity(0, ctypes.sizeof(mask), mask) != 0:
raise RuntimeError("Failed to set CPU affinity")