irqbalance - Interrupt Distribution Tuning Cheatsheet
irqbalance is a daemon that distributes hardware interrupts (IRQs) across CPU cores. By default Linux may route most interrupts from a busy NIC or storage controller to CPU 0, making that core a bottleneck while others idle. irqbalance monitors interrupt load and rebalances IRQ affinity to spread the work. Conversely, for latency-critical workloads with hand-pinned CPUs, it is often deliberately disabled so it cannot move interrupts onto isolated cores.
Installation
| Platform | Command |
|---|
| Debian/Ubuntu | sudo apt install irqbalance |
| Fedora/RHEL | sudo dnf install irqbalance |
| Arch Linux | sudo pacman -S irqbalance |
| Service | sudo systemctl enable --now irqbalance |
| Verify | irqbalance --version |
Inspecting Interrupts First
| Command | Shows |
|---|
cat /proc/interrupts | Per-CPU interrupt counts by device |
watch -n1 'cat /proc/interrupts' | Live growth (spot the hot core) |
mpstat -I SUM -P ALL 1 | Interrupts per CPU per second |
cat /proc/irq/<N>/smp_affinity | Affinity mask for one IRQ |
cat /proc/irq/<N>/smp_affinity_list | Same, as a CPU list |
# Is one CPU absorbing all NIC interrupts?
watch -n1 "grep -E 'eth0|mlx|ens' /proc/interrupts"
Running the Daemon
| Command | Description |
|---|
sudo systemctl status irqbalance | Check it is running |
sudo irqbalance --foreground | Run in foreground (debugging) |
sudo irqbalance --oneshot | Balance once, then exit |
sudo irqbalance --debug | Verbose decisions |
Key Options / Environment
| Setting | Effect |
|---|
IRQBALANCE_BANNED_CPUS=<mask> | Never assign IRQs to these CPUs |
--banirq=N | Exclude a specific IRQ from balancing |
--policyscript=PATH | Script that decides per-IRQ policy |
--interval=SECONDS | Rebalance interval |
| `—hintpolicy=exact | subset |
--powerthresh=N | Power-save consolidation threshold |
Configuration usually lives in /etc/default/irqbalance or /etc/sysconfig/irqbalance.
# Keep IRQs off isolated cores 8-15 (mask for CPUs 8..15)
echo 'IRQBALANCE_BANNED_CPUS=0000ff00' | sudo tee -a /etc/default/irqbalance
sudo systemctl restart irqbalance
Manual IRQ Affinity (when you disable the daemon)
# Pin IRQ 42 to CPU 2 (bitmask 0x4)
echo 4 | sudo tee /proc/irq/42/smp_affinity
# Or by CPU list
echo 2 | sudo tee /proc/irq/42/smp_affinity_list
| Approach | Use |
|---|
| irqbalance running | General servers, variable load |
| irqbalance disabled + manual pinning | Low-latency, NUMA-pinned, RT workloads |
| Banned CPUs | Hybrid: balance, but protect isolated cores |
Latency-Critical Pattern
# Typical low-latency setup: stop the balancer, pin NIC IRQs near the app's NUMA node
sudo systemctl stop irqbalance
sudo systemctl disable irqbalance
# then set smp_affinity for the NIC's IRQs to cores on the same NUMA node
Pair with numactl so the application’s memory and the interrupt handling live on the same NUMA node — cross-node interrupt handling is a classic hidden latency source.
Verifying the Change
| Check | Command |
|---|
| Interrupt spread | mpstat -I SUM -P ALL 1 |
| Softirq load | top → %si per CPU |
| Network throughput | sar -n DEV 1 |
| Per-IRQ counts | watch 'cat /proc/interrupts' |
Success looks like interrupt counts growing evenly across intended cores (or concentrated on exactly the cores you chose).
| Tool | Role |
|---|
| irqbalance | Distribute IRQs across CPUs |
| numactl | Bind process CPU/memory to NUMA nodes |
| cpupower | Frequency/idle-state control |
| tuned | Whole-system profiles (may manage irqbalance) |
| RPS/RFS | Software-side packet steering |
Resources