funwithlinux guide

The Ins and Outs of Linux Kernel Tuning for Performance

The Linux kernel is the core of every Linux-based operating system, responsible for managing hardware resources, scheduling processes, and facilitating communication between software and hardware. While Linux kernels are designed with "sane defaults" to work across diverse workloads (desktops, servers, embedded systems, etc.), these defaults are rarely optimal for specific use cases. **Kernel tuning** involves adjusting low-level parameters and configurations to optimize performance for your workload—whether that’s a high-traffic web server, a database, a real-time embedded system, or a HPC cluster. In this blog, we’ll demystify Linux kernel tuning, breaking down key subsystems (CPU, memory, disk I/O, network), essential tools, and best practices to help you squeeze maximum performance from your Linux environment.

Table of Contents

  1. Understanding the Linux Kernel and Performance Metrics
  2. Key Subsystems to Tune
  3. Tools for Monitoring and Tuning
  4. Advanced Kernel Tuning
  5. Best Practices and Considerations
  6. Conclusion
  7. References

1. Understanding the Linux Kernel and Performance Metrics

Before diving into tuning, it’s critical to understand what the kernel does and how to measure performance. The kernel acts as a “middleman,” managing:

  • CPU scheduling: Allocating CPU time to processes.
  • Memory management: Handling RAM, swap, and caching.
  • Disk I/O: Controlling reads/writes to storage.
  • Networking: Routing packets and managing sockets.

Key Performance Metrics to Monitor

To identify bottlenecks, track these metrics:

SubsystemMetrics
CPUUtilization (user/system/idle), load average, context switches, interrupts.
MemoryFree/used RAM, swap usage, page cache size, page faults (major/minor).
Disk I/OThroughput (MB/s), latency (ms), IOPS (I/O operations per second), queue depth.
NetworkBandwidth (Mbps), latency (RTT), packet loss, TCP retransmissions.

2. Key Subsystems to Tune

2.1 CPU Tuning

The CPU is often the first bottleneck in compute-heavy workloads. Tuning focuses on optimizing scheduler behavior, core allocation, and interrupt handling.

a. Scheduler Tuning

Linux uses the Completely Fair Scheduler (CFS) as the default for general-purpose workloads, but alternatives exist:

  • Deadline Scheduler: Prioritizes tasks with strict deadlines (e.g., real-time systems).
  • Realtime Scheduler (RT): For time-critical tasks (e.g., industrial control systems).

To switch schedulers for a process, use chrt (realtime) or schedtool (CFS). For example, to run a process with real-time priority:

chrt -f 99 ./realtime_app  # -f = FIFO scheduler, priority 99 (max)  

b. CPU Affinity

Bind processes to specific CPU cores to reduce cache misses (e.g., databases, HPC). Use taskset:

taskset -c 0,1 ./database  # Bind process to cores 0 and 1  

For system-wide control, use cgroups (via systemd slices or cgconfig).

c. Frequency Scaling

CPU governors control clock speed. For performance, switch from powersave to performance:

echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor  

d. Hyper-Threading (HT)

Enable HT for workloads with high instruction-level parallelism (e.g., web servers). Disable it for latency-sensitive tasks (e.g., databases) where physical cores perform better:

# Disable HT (persistent across reboots: edit BIOS/UEFI)  
echo off | sudo tee /sys/devices/system/cpu/smt/control  

e. Interrupt Handling

IRQs (hardware interrupts) can starve processes. Use irqbalance to distribute IRQs across cores:

sudo systemctl enable --now irqbalance  # Auto-balance IRQs  

For critical devices (e.g., network cards), isolate IRQs to dedicated cores:

echo 2 > /proc/irq/42/smp_affinity_list  # Bind IRQ 42 to core 2  

2.2 Memory Tuning

Memory tuning focuses on reducing swap usage, optimizing caching, and avoiding out-of-memory (OOM) crashes.

a. Page Cache Tuning

The kernel caches disk data in RAM (page cache) to speed up reads. Adjust how aggressively data is written back to disk:

  • vm.dirty_ratio: Percentage of RAM that can be dirty (unwritten) before the kernel forces writes.
  • vm.dirty_background_ratio: Percentage that triggers background writes (lower than dirty_ratio).

For write-heavy workloads (e.g., logging servers), reduce these values to avoid write bursts:

sysctl -w vm.dirty_ratio=10          # Default: 20  
sysctl -w vm.dirty_background_ratio=5  # Default: 10  

b. Swap Behavior

vm.swappiness controls how aggressively the kernel swaps. Lower values reduce swapping (good for servers):

sysctl -w vm.swappiness=10  # Default: 60 (0 = swap only when OOM)  

c. OOM Killer

The OOM killer terminates processes when RAM is exhausted. Tune its behavior:

  • vm.overcommit_memory: Controls memory overcommitment (0 = heuristic, 1 = always overcommit, 2 = never overcommit).
  • oom_score_adj: Lower values make a process less likely to be killed (e.g., -1000 = immune).

Example: Protect sshd from OOM:

echo -1000 > /proc/$(pidof sshd)/oom_score_adj  

d. Huge Pages

Reduce memory overhead for large workloads (databases like PostgreSQL, virtualization). Use Transparent Huge Pages (THP) (auto-enabled) or static huge pages:

# Enable THP (default on most distros)  
echo always > /sys/kernel/mm/transparent_hugepage/enabled  

2.3 Disk I/O Tuning

Disk I/O is often the slowest subsystem. Tune schedulers, read-ahead, and filesystem settings.

a. I/O Schedulers

Choose based on workload:

  • NOOP: Best for SSDs/NVMe (no mechanical seek time).
  • Deadline: Low latency for databases (prioritizes reads over writes).
  • BFQ (Budget Fair Queueing): Fairness for multi-user systems (e.g., shared hosting).

To set a scheduler for a disk (e.g., /dev/sda):

echo deadline > /sys/block/sda/queue/scheduler  

b. Read-Ahead

Increase read-ahead for sequential workloads (e.g., video streaming, backups). Use blockdev:

blockdev --setra 4096 /dev/sda  # 4096 sectors (2MB, default: 256 sectors/128KB)  

c. Filesystem Optimizations

  • Mount Options: Use noatime (disable access time logging) and nodiratime (disable directory access time) to reduce writes:
    # In /etc/fstab  
    /dev/sda1 / ext4 defaults,noatime,nodiratime 0 1  
  • XFS/ext4 Tuning: For XFS, use allocsize=1G (large files) or inode64 (64-bit inodes). For ext4, enable delalloc (delayed allocation).

2.4 Network Tuning

Optimize TCP/IP parameters, buffer sizes, and congestion control for low latency or high throughput.

a. TCP/IP Buffers

Increase socket buffers to handle high bandwidth/latency (e.g., long-distance links):

sysctl -w net.core.rmem_max=16777216  # Max receive buffer (16MB)  
sysctl -w net.core.wmem_max=16777216  # Max send buffer (16MB)  
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"  # Min/default/max receive  
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"  # Min/default/max send  

b. Congestion Control

Switch to BBR (Bottleneck Bandwidth and RTT) for high-latency, high-bandwidth links (e.g., cloud servers):

sysctl -w net.ipv4.tcp_congestion_control=bbr  

Other options: cubic (default), vegas (low latency).

c. TCP Timestamps and Connection Reuse

Reduce TIME_WAIT sockets (common in high-concurrency servers like Nginx):

sysctl -w net.ipv4.tcp_tw_reuse=1  # Reuse TIME_WAIT sockets for new connections  
sysctl -w net.ipv4.tcp_tw_recycle=0  # Disable (breaks NAT networks)  

3. Tools for Monitoring and Tuning

Monitoring Tools

  • top/htop: Real-time CPU/memory usage.
  • vmstat: System-wide memory, CPU, and I/O stats (e.g., vmstat 5 for 5-second intervals).
  • iostat: Disk I/O metrics (e.g., iostat -x 5 for extended stats).
  • sar: Historical performance data (install sysstat first).
  • perf: Low-level CPU profiling (e.g., perf top to see hot functions).

Tuning Tools

  • sysctl: Modify kernel parameters at runtime (persist in /etc/sysctl.conf).
  • procfs: Directly edit files in /proc/sys/ (e.g., /proc/sys/vm/swappiness).
  • tuned-adm: Profile-based tuning (e.g., tuned-adm profile throughput-performance for servers).

4. Advanced Kernel Tuning

a. Custom Kernel Compilation

For specialized workloads (e.g., embedded systems, real-time), compile a custom kernel to:

  • Remove unused drivers (reduce memory overhead).
  • Enable experimental features (e.g., BBRv2, new schedulers).

Steps:

  1. Download kernel source: git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
  2. Configure: make menuconfig (enable/disable features).
  3. Compile: make -j$(nproc)
  4. Install: make modules_install install

b. NUMA Tuning

On multi-socket systems with Non-Uniform Memory Access (NUMA), align processes with local memory to reduce latency. Use numactl:

numactl --cpunodebind=0 --membind=0 ./app  # Bind to node 0 (CPU and memory)  

5. Best Practices and Considerations

  1. Monitor First, Tune Later: Use tools like perf or sar to identify bottlenecks before adjusting parameters.
  2. Test Incrementally: Change one parameter at a time and benchmark (e.g., sysbench, fio, iperf).
  3. Workload-Specificity: A web server needs different tuning than a database (e.g., more network buffers vs. huge pages).
  4. Persistence: Save changes to /etc/sysctl.conf (kernel params), /etc/fstab (mount options), or systemd units (cgroups).
  5. Security: Avoid risky settings (e.g., vm.overcommit_memory=1 can cause OOM; tcp_tw_recycle breaks NAT).

6. Conclusion

Linux kernel tuning is a powerful way to optimize performance, but it’s not a one-size-fits-all solution. By understanding your workload, monitoring key metrics, and iteratively adjusting subsystems (CPU, memory, disk I/O, network), you can unlock significant gains. Always test changes in staging first, and document your configurations for future reference.

7. References