Configure Linux process scheduling and CPU affinity for performance optimization

Intermediate 45 min Apr 27, 2026 176 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

Need help?

Don't want to manage this yourself?

We handle infrastructure performance optimization for businesses that depend on uptime. From initial setup to ongoing operations.