Configure Linux process scheduling and CPU affinity for performance optimization

Intermediate 45 min Apr 27, 2026 1,267 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Learn to optimize Linux process performance by configuring CPU scheduling priorities, CPU affinity, and systemd resource management for better workload distribution and reduced context switching.

Prerequisites

  • Root or sudo access
  • Basic understanding of Linux processes
  • Multi-core CPU system

What this solves

Linux process scheduling and CPU affinity control how processes are assigned to CPU cores and their execution priority. By default, the Linux scheduler distributes processes across all available CPU cores, but this can lead to cache misses and suboptimal performance for specific workloads. Configuring CPU affinity pins processes to specific cores, while scheduling priorities ensure critical applications get the resources they need.

Understanding Linux process scheduling and CPU affinity

Process scheduling basics

The Linux kernel uses the Completely Fair Scheduler (CFS) to manage process execution. Each process has a nice value (-20 to 19) that affects its priority, with lower values giving higher priority. The scheduler also considers CPU affinity, which determines which CPU cores a process can use.

Note: Modern systems have multiple CPU cores, and understanding NUMA (Non-Uniform Memory Access) topology is crucial for optimal performance. See our NUMA optimization guide for multi-socket servers.

CPU affinity concepts

CPU affinity binds processes to specific CPU cores, reducing cache misses and improving performance for CPU-intensive applications. This is particularly useful for real-time applications, database servers, and high-frequency trading systems where consistent performance matters more than load balancing.

Check current system topology

First, understand your system's CPU layout and current process distribution.

lscpu
nproc
cat /proc/cpuinfo | grep processor | wc -l

View current process scheduling information

Check current nice values and CPU affinity for running processes.

ps -eo pid,ppid,cmd,nice,psr --sort=-pcpu | head -20
top -p 1 -n 1 -b | grep "Cpu(s)"

Configure CPU scheduling with systemd and nice priorities

Install scheduling tools

Install the necessary tools for CPU affinity and process scheduling management.

sudo apt update
sudo apt install -y util-linux schedtool htop numactl
sudo dnf install -y util-linux schedutils htop numactl

Configure systemd service CPU scheduling

Create a systemd service configuration that demonstrates CPU affinity and nice value settings.

[Unit]
Description=High Priority Application
After=network.target

[Service]
Type=simple
User=appuser
Group=appgroup
ExecStart=/usr/local/bin/my-app

# CPU Scheduling Configuration
Nice=-10
CPUAffinity=0 1
CPUSchedulingPolicy=1
CPUSchedulingPriority=50

# Resource Limits
MemoryMax=2G
CPUQuota=150%

# Security
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/var/log/my-app

[Install]
WantedBy=multi-user.target

Create systemd drop-in configuration for existing services

Configure CPU affinity for existing services like nginx without modifying the main service file.

sudo mkdir -p /etc/systemd/system/nginx.service.d
[Service]
# Bind nginx to cores 2-7, leaving 0-1 for system tasks
CPUAffinity=2 3 4 5 6 7
Nice=-5

# Limit CPU usage to prevent resource starvation
CPUQuota=400%
MemoryMax=1G

Configure cgroup CPU scheduling

Create custom cgroups for different application classes with specific CPU scheduling parameters.

sudo mkdir -p /sys/fs/cgroup/cpu/high-priority
sudo mkdir -p /sys/fs/cgroup/cpu/low-priority
# Set high priority group to use more CPU time
sudo echo 2048 > /sys/fs/cgroup/cpu/high-priority/cpu.shares
sudo echo 512 > /sys/fs/cgroup/cpu/low-priority/cpu.shares

# Set CPU quota (100% = 1 core)
sudo echo 200000 > /sys/fs/cgroup/cpu/high-priority/cpu.cfs_quota_us
sudo echo 100000 > /sys/fs/cgroup/cpu/high-priority/cpu.cfs_period_us

Reload systemd and apply changes

Reload systemd configuration and restart services to apply the new CPU scheduling settings.

sudo systemctl daemon-reload
sudo systemctl restart nginx
sudo systemctl status nginx

Implement CPU affinity with taskset and cpuset

Use taskset for running processes

Apply CPU affinity to running processes using taskset command for immediate changes.

# Check current CPU affinity for a process (replace PID)
taskset -p 1234

# Set CPU affinity to cores 0,1 for process 1234
sudo taskset -cp 0,1 1234

# Start a new process with specific CPU affinity
taskset -c 2,3 /usr/bin/my-application

Configure persistent CPU affinity with cpuset

Create cpuset configurations for persistent CPU isolation across system reboots.

sudo mkdir -p /sys/fs/cgroup/cpuset/database
sudo mkdir -p /sys/fs/cgroup/cpuset/webserver
sudo mkdir -p /sys/fs/cgroup/cpuset/background

Configure cpuset parameters

Set up CPU and memory node assignments for each cpuset group.

# Configure database cpuset (cores 0-3)
sudo echo 0-3 > /sys/fs/cgroup/cpuset/database/cpuset.cpus
sudo echo 0 > /sys/fs/cgroup/cpuset/database/cpuset.mems
sudo echo 1 > /sys/fs/cgroup/cpuset/database/cpuset.cpu_exclusive

# Configure webserver cpuset (cores 4-7)
sudo echo 4-7 > /sys/fs/cgroup/cpuset/webserver/cpuset.cpus
sudo echo 0 > /sys/fs/cgroup/cpuset/webserver/cpuset.mems

# Configure background tasks (cores 6-7, shared)
sudo echo 6-7 > /sys/fs/cgroup/cpuset/background/cpuset.cpus
sudo echo 0 > /sys/fs/cgroup/cpuset/background/cpuset.mems

Create systemd slice configurations

Use systemd slices to manage cpuset assignments automatically.

[Unit]
Description=Database Services Slice
Before=slices.target

[Slice]
CPUAccounting=true
MemoryAccounting=true
AllowedCPUs=0-3
AllowedMemoryNodes=0

Create a script for dynamic CPU affinity management

Create a script to dynamically adjust CPU affinity based on system load.

#!/bin/bash

# Dynamic CPU Affinity Manager
# Adjusts process CPU affinity based on load

LOAD_THRESHOLD=2.0
HIGH_PRIORITY_PROCESSES=("mysql" "postgres" "nginx")
LOW_PRIORITY_CORES="6,7"
HIGH_PRIORITY_CORES="0-5"

# Get current load average
LOAD_AVG=$(uptime | awk '{print $(NF-2)}' | sed 's/,//')

# Function to set CPU affinity
set_affinity() {
    local process_name=$1
    local cores=$2
    
    for pid in $(pgrep "$process_name"); do
        if [ -n "$pid" ]; then
            taskset -cp "$cores" "$pid" 2>/dev/null
            echo "Set $process_name (PID: $pid) to cores $cores"
        fi
    done
}

# Adjust based on load
if (( $(echo "$LOAD_AVG > $LOAD_THRESHOLD" | bc -l) )); then
    echo "High load detected ($LOAD_AVG), isolating critical processes"
    for process in "${HIGH_PRIORITY_PROCESSES[@]}"; do
        set_affinity "$process" "$HIGH_PRIORITY_CORES"
    done
else
    echo "Normal load ($LOAD_AVG), allowing balanced scheduling"
    for process in "${HIGH_PRIORITY_PROCESSES[@]}"; do
        set_affinity "$process" "0-7"
    done
fi

Make the script executable and create systemd timer

Set up the CPU affinity manager to run periodically.

sudo chmod +x /usr/local/bin/cpu-affinity-manager.sh
[Unit]
Description=CPU Affinity Manager
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/cpu-affinity-manager.sh
User=root
[Unit]
Description=Run CPU Affinity Manager every 5 minutes
Requires=cpu-affinity-manager.service

[Timer]
OnBootSec=5min
OnUnitActiveSec=5min
Unit=cpu-affinity-manager.service

[Install]
WantedBy=timers.target

Enable and start the CPU affinity manager

Activate the automated CPU affinity management system.

sudo systemctl daemon-reload
sudo systemctl enable --now cpu-affinity-manager.timer
sudo systemctl status cpu-affinity-manager.timer

Monitor and optimize process performance

Install performance monitoring tools

Set up tools for monitoring CPU scheduling and affinity effectiveness.

sudo apt install -y sysstat iotop atop perf-tools-unstable
sudo dnf install -y sysstat iotop atop perf

Create performance monitoring script

Build a comprehensive monitoring script to track CPU scheduling effectiveness.

#!/bin/bash

# CPU Performance Monitor
# Tracks process scheduling and CPU affinity effectiveness

LOG_FILE="/var/log/cpu-performance.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

echo "=== CPU Performance Report - $DATE ===" >> $LOG_FILE

# CPU utilization per core
echo "CPU Utilization per Core:" >> $LOG_FILE
mpstat -P ALL 1 1 | tail -n +4 >> $LOG_FILE

# Process CPU affinity and usage
echo "\nTop CPU consumers with affinity:" >> $LOG_FILE
ps -eo pid,ppid,cmd,nice,psr,%cpu --sort=-%cpu | head -20 | while read line; do
    pid=$(echo $line | awk '{print $1}')
    if [[ $pid =~ ^[0-9]+$ ]]; then
        affinity=$(taskset -p $pid 2>/dev/null | awk '{print $NF}')
        echo "$line (Affinity: $affinity)" >> $LOG_FILE
    else
        echo "$line" >> $LOG_FILE
    fi
done

# Context switches and interrupts
echo "\nContext Switches and Interrupts:" >> $LOG_FILE
vmstat 1 5 | tail -1 >> $LOG_FILE

# Load average
echo "\nLoad Average:" >> $LOG_FILE
uptime >> $LOG_FILE

echo "\n" >> $LOG_FILE

Set up performance monitoring with systemd

Configure automated performance monitoring and logging.

sudo chmod +x /usr/local/bin/cpu-performance-monitor.sh
sudo touch /var/log/cpu-performance.log
sudo chown root:adm /var/log/cpu-performance.log
sudo chmod 644 /var/log/cpu-performance.log
[Unit]
Description=CPU Performance Monitor
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/cpu-performance-monitor.sh
User=root
[Unit]
Description=Run CPU Performance Monitor every 10 minutes
Requires=cpu-performance-monitor.service

[Timer]
OnBootSec=10min
OnUnitActiveSec=10min
Unit=cpu-performance-monitor.service

[Install]
WantedBy=timers.target

Enable performance monitoring

Start the automated performance monitoring system.

sudo systemctl enable --now cpu-performance-monitor.timer
sudo systemctl status cpu-performance-monitor.timer

Configure log rotation for performance logs

Set up log rotation to prevent performance logs from consuming too much disk space.

/var/log/cpu-performance.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    create 644 root adm
    postrotate
        systemctl reload-or-restart rsyslog > /dev/null 2>&1 || true
    endscript
}

Verify your setup

Check that CPU scheduling and affinity configurations are working correctly.

# Verify systemd service CPU affinity
systemctl show nginx | grep CPUAffinity

# Check current process affinity
ps -eo pid,cmd,psr | grep nginx
taskset -p $(pgrep nginx | head -1)

# Monitor CPU usage per core
watch -n 2 'mpstat -P ALL 1 1 | tail -n +4'

# Check cgroup assignments
cat /proc/$(pgrep nginx | head -1)/cgroup

# View performance monitoring results
sudo tail -f /var/log/cpu-performance.log

# Test the CPU affinity manager
sudo /usr/local/bin/cpu-affinity-manager.sh

Common issues

SymptomCauseFix
Taskset command fails with "Invalid argument"CPU core doesn't exist or wrong syntaxCheck lscpu output and use correct core numbers
Systemd service ignores CPUAffinitysystemd version doesn't support CPU affinityUse ExecStart with taskset wrapper or update systemd
High context switching despite CPU affinityProcesses competing for same resourcesReview memory locality and adjust affinity groups
Performance degradation after setting affinityToo restrictive CPU bindingAllow more cores or use CPU sets instead of strict binding
Nice values not taking effectProcess started before systemd configurationRestart services after changing nice values
Cgroup cpuset not workingcpuset controller not enabledEnable cpuset in kernel command line: cgroup_enable=cpuset
Warning: Overly restrictive CPU affinity can hurt performance on systems with varying workloads. Monitor system performance after making changes and adjust accordingly.

Next steps

Running this in production?

Want this handled for you? Setting up CPU scheduling once is straightforward. Keeping it monitored, tuned for different workloads, and optimized as your infrastructure scales is the harder part. See how we run infrastructure like this for European SaaS and e-commerce teams.

Automated install script

Run this to automate the entire setup

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. Fully managed, with one fixed contact who knows your setup.

You get one fixed contact who knows your setup

Rotterdam 01:25 · reachable in a message, no ticket form