| name | linux-performance-tuner |
| description | Use when user wants to tune Linux performance — kernel parameters, CPU governor, I/O scheduler, memory and swap settings, network stack tuning, database tuning (PostgreSQL, MySQL, Redis), high-throughput or low-latency optimization, profiling slow systems, or asks why their server is slow, has high load, or underperforms. |
| version | 1.4.0 |
| author | Lehnert |
Linux Performance Tuner
Overview
Generates a tuned sysctl configuration, I/O scheduler settings, CPU governor settings, and workload-specific optimizations based on the user's hardware and use case. Always measures before tuning — includes profiling commands to find the actual bottleneck before applying any change.
Rule: Profile first, tune second. Never apply tuning blind. Always identify the bottleneck first.
Language: Respond in the user's language. Config files and scripts in English.
When to Use
- User reports high load, slow response times, or poor throughput
- User wants to optimize for a specific workload (web, database, HPC, containers)
- User wants to tune kernel parameters for their server
- User asks about CPU governor, I/O scheduler, huge pages, NUMA
- User wants to profile where their system is spending time
- User asks "why is my server slow?"
When NOT to Use
- User wants to harden the server →
linux-security-hardener
- User wants to monitor ongoing performance →
linux-monitoring-setup
- User wants to tune Docker/container resource limits →
docker-compose-writer
Step 1 — Find the Bottleneck First
Before generating any tuning, output these diagnostic commands and ask the user to share results if they haven't already:
uptime
vmstat 1 10
mpstat -P ALL 1 5
top -b -n1 | head -20
free -h
cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapUsed"
iostat -xz 1 5
iotop -bo -n5 2>/dev/null
sar -n DEV 1 5 2>/dev/null
ss -s
netstat -s | grep -E "failed|error|overflow|retran" 2>/dev/null
ps aux --sort=-%cpu | head -10
dmesg -T | tail -30 | grep -iE "error|warn|oom|throttl"
Step 2 — Identify Workload Type
If the bottleneck or workload type isn't clear, present options:
What is this server's primary workload?
1. Web / Application server (nginx, Apache, Node.js, Python, Ruby)
2. Database server (PostgreSQL, MySQL, Redis, MongoDB)
3. High-throughput networking (load balancer, proxy, high-connection count)
4. General purpose / mixed (VPS, dev server, multiple services)
5. Compute / HPC (CPU-intensive batch jobs, scientific computing)
6. Storage / I/O heavy (file server, NFS, large file processing)
Tuning Profiles
Profile 1 — Web / Application Server
CPU:
cpupower frequency-set -g performance
for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo performance > "$cpu"
done
cat > /etc/systemd/system/cpu-performance.service << 'EOF'
[Unit]
Description=Set CPU governor to performance
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'for f in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do [ -w "$f" ] && echo performance > "$f"; done; true'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now cpu-performance.service
Kernel (/etc/sysctl.d/99-webserver.conf):
fs.file-max = 2097152
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 6
net.ipv4.tcp_slow_start_after_idle = 0
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
vm.swappiness = 10
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
ulimits (/etc/security/limits.d/99-webserver.conf):
* soft nofile 65536
* hard nofile 262144
* soft nproc 65536
* hard nproc 65536
Profile 2 — Database Server
Kernel (/etc/sysctl.d/99-database.conf):
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
vm.nr_hugepages = 512
vm.swappiness = 1
vm.dirty_ratio = 10
vm.dirty_background_ratio = 3
vm.overcommit_memory = 2
vm.overcommit_ratio = 80
net.core.somaxconn = 4096
net.ipv4.tcp_keepalive_time = 300
I/O scheduler (critical for database performance):
for disk in /sys/block/sd* /sys/block/nvme*; do
if [[ -f "${disk}/queue/scheduler" ]]; then
echo mq-deadline > "${disk}/queue/scheduler"
echo 0 > "${disk}/queue/rotational" 2>/dev/null || true
echo 256 > "${disk}/queue/nr_requests" 2>/dev/null || true
fi
done
PostgreSQL-specific tuning (postgresql.conf guidance):
| Parameter | Formula / Value | Notes |
|---|
shared_buffers | 15–25% of RAM | Lower (15%) for mixed workloads, higher (25%) for dedicated DB |
effective_cache_size | 75% of RAM | Planner hint only |
work_mem | RAM / (max_connections × 2) | Per-sort memory |
maintenance_work_mem | 512MB–2GB | VACUUM, CREATE INDEX |
wal_buffers | 64MB | WAL write buffer |
checkpoint_completion_target | 0.9 | Spread checkpoint I/O |
random_page_cost | 1.1 (SSD) / 4.0 (HDD) | Query planner cost |
effective_io_concurrency | 200 (SSD) / 2 (HDD) | Parallel I/O |
max_worker_processes | CPU cores | Background workers |
max_parallel_workers_per_gather | CPU cores / 2 | Query parallelism |
Profile 3 — High-Throughput Networking
Kernel (/etc/sysctl.d/99-network.conf):
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.ipv4.tcp_rmem = 4096 262144 134217728
net.ipv4.tcp_wmem = 4096 262144 134217728
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 300000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 5
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
NIC offloading:
ethtool -K eth0 gso on gro on tso on tx on rx on
cat /proc/interrupts | grep eth0
Profile 4 — General Purpose VPS
Kernel (/etc/sysctl.d/99-general.conf):
vm.swappiness = 10
vm.dirty_ratio = 20
vm.dirty_background_ratio = 5
net.core.somaxconn = 8192
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.core.rmem_max = 8388608
net.core.wmem_max = 8388608
kernel.randomize_va_space = 2
fs.file-max = 1048576
Profile 5 — Compute / HPC
echo 0 > /proc/sys/kernel/numa_balancing
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
taskset -cp 2-5 <pid>
chrt -f 50 /path/to/realtime-process
Profile 6 — Storage / I/O Heavy
For file servers, NFS, object storage, and large file processing workloads.
I/O scheduler (critical — use BFQ for HDDs, mq-deadline for SSDs):
echo bfq > /sys/block/sda/queue/scheduler
echo 256 > /sys/block/sda/queue/nr_requests
echo mq-deadline > /sys/block/nvme0n1/queue/scheduler
echo 64 > /sys/block/nvme0n1/queue/nr_requests
cat /sys/block/sda/queue/scheduler
Kernel (/etc/sysctl.d/99-storage.conf):
vm.swappiness = 1
vm.dirty_ratio = 40
vm.dirty_background_ratio = 10
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500
fs.file-max = 4194304
fs.inotify.max_user_watches = 524288
NFS-specific tuning:
echo 32 > /proc/fs/nfsd/threads
ulimits (/etc/security/limits.d/99-storage.conf):
* soft nofile 262144
* hard nofile 1048576
Profile 7 — Redis Cache / Message Broker
Kernel (/etc/sysctl.d/99-redis.conf):
vm.overcommit_memory = 1
vm.swappiness = 0
net.core.somaxconn = 65535
Disable Transparent Huge Pages (causes Redis latency spikes):
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
Key redis.conf settings:
| Parameter | Value | Notes |
|---|
maxmemory | 70–80% of available RAM | Leave headroom for OS and fork() |
maxmemory-policy | allkeys-lru (cache) / noeviction (queue) | allkeys-lru for pure cache |
appendonly | yes (durability) / no (pure cache) | AOF adds ~10-30% write overhead |
save "" | Disable RDB | For pure cache — saves only waste I/O |
hz | 10 (default) | Increase to 100 only for sub-ms latency needs |
bind | 127.0.0.1 | Never bind to 0.0.0.0 without auth |
Check Redis health:
redis-cli info stats | grep -E "evicted|rejected|keyspace"
redis-cli info memory | grep -E "used_memory_human|maxmemory_human"
redis-cli --latency -h localhost -p 6379
Profiling Tools Reference
Use these to identify the bottleneck before tuning:
| Tool | What it shows | Install |
|---|
perf top | Live CPU hotspot — which functions consume CPU | perf package |
perf stat -p <pid> | CPU counters for a process | perf package |
flamegraph | Visual CPU call stack — find hot paths | FlameGraph + perf |
iostat -xz 1 | Per-disk I/O utilization and latency | sysstat |
iotop | Per-process I/O rates | iotop |
vmstat 1 | CPU/memory/swap/IO overview | Built-in |
sar -n DEV 1 | Per-NIC throughput and errors | sysstat |
ss -s | Socket state summary | Built-in |
atop | Full resource history with process detail | atop |
dstat | Combined CPU/disk/net/mem in one view | dstat |
strace -p <pid> | System calls a process is making | Built-in |
lsof -p <pid> | Open files and connections | lsof |
numactl --hardware | NUMA topology | numactl |
turbostat | CPU frequency and power states | linux-tools |
Quick flamegraph:
perf record -F 99 -a -g -- sleep 30
perf script | /path/to/FlameGraph/stackcollapse-perf.pl | \
/path/to/FlameGraph/flamegraph.pl > flame.svg
Output Format
Write tuning files to ./performance/ in the current working directory:
performance/
sysctl.conf ← drop into /etc/sysctl.d/99-tuning.conf
limits.conf ← drop into /etc/security/limits.d/99-tuning.conf
io-scheduler.sh ← set I/O scheduler + persist via udev rule
cpu-governor.sh ← set CPU governor + systemd service
apply-all.sh ← apply everything at once
Then print ONLY:
✅ Performance tuning written to ./performance/
▶ Review before applying — understand each change:
cat performance/sysctl.conf
▶ Apply all at once:
chmod +x performance/apply-all.sh
sudo ./performance/apply-all.sh
▶ Or apply individually:
sudo cp performance/sysctl.conf /etc/sysctl.d/99-tuning.conf
sudo sysctl -p /etc/sysctl.d/99-tuning.conf
sudo cp performance/limits.conf /etc/security/limits.d/99-tuning.conf
▶ Measure after applying (compare to before):
vmstat 1 10
iostat -xz 1 5
💡 Always benchmark before and after — tuning without measurement is guessing.
💡 Next: /linux-monitoring-setup to track metrics continuously after tuning.