Game Server Kernel Tuning: sysctl Values That Reduce Jitter and Tick Spikes

Jitter on a game server is rarely caused by insufficient CPU or bandwidth. It is caused by the kernel doing housekeeping at the wrong moment: a network interrupt landing on the core running the tick loop, a CPU deciding to sleep for 400 microseconds, or a UDP receive buffer overflowing during a traffic burst and forcing retransmission. Each of these is a handful of lines in sysctl and IRQ configuration away from being fixed, and each shows up in the 99th-percentile tick delta rather than the average.

Before Tuning: Measure Jitter

Tuning blind is how operators add fifty settings that make things worse. Establish a baseline first: tick delta at the 99th percentile, network interrupt distribution across cores, and CPU idle-state exit latency. These three numbers tell you which sections below actually apply to your host.

# 99th percentile scheduling delay per CPU
cyclictest -p 80 -t -n -i 200 -l 100000 -h 400

# where are NIC interrupts landing?
cat /proc/interrupts | grep eth0

# is the CPU entering deep sleep states?
turbostat --show PkgWatt,CPU%c1,CPU%c6 sleep 10

# current network stack settings
sysctl net.core.netdev_max_backlog net.core.rmem_max net.ipv4.udp_mem

A cyclictest maximum above 1 ms on a modern server means the host is not configured for latency-sensitive work. Game servers running 128 tick have a 7.81 ms budget; a 1-2 ms scheduling delay consumed by kernel work is 15-25% of the entire window.

The sysctl Values That Matter

Settings that change game server jitter, with the values that work in practice. Drop them into /etc/sysctl.d/90-game.conf and load with sysctl --system.

sysctl keyDefaultGame server valueEffect
net.core.rmem_max21299216777216Stops UDP receive drops under burst
net.core.netdev_max_backlog100025000Absorbs packet floods without loss
net.core.busy_poll050Reduces wake-up latency for busy sockets
net.ipv4.udp_rmem_min409616384Minimum buffer per UDP socket
net.ipv4.tcp_low_latency01Prefers latency over throughput
net.ipv4.tcp_fastopen13Cuts handshake RTT for lobby traffic
vm.swappiness601Prevents swap-induced tick stalls
kernel.sched_migration_cost_ns5000005000000Keeps the tick thread on one core

The last row is underrated. Raising sched_migration_cost_ns tells the scheduler that migrating a task is expensive, so it leaves the tick thread on its core instead of shuffling it to an idle sibling. On a 32-core node with a single-threaded game loop, this alone reduces 99th-percentile tick delta by 15-30% in measured tests.

C-States, Governor, and IRQ Affinity

sysctl handles the network stack, but three systems-level settings handle timing. Disable deep C-states so the core never pays an exit latency measured in tens to hundreds of microseconds. Set the CPU governor to performance so frequency never ramps down between ticks. Move NIC interrupt processing off the cores running game workloads.

# 1. no frequency scaling on game cores
cpupower frequency-set -g performance

# 2. kill C1E/C6 exit latency
for cpu in /sys/devices/system/cpu/cpu*/cpuidle/state*/disable; do echo 1 > $cpu; done

# 3. steer NIC IRQs away from game cores (cores 0-3)
for irq in $(grep eth0 /proc/interrupts | cut -d: -f1); do
  echo 8-15 > /proc/irq/$irq/smp_affinity_list
done

# 4. RPS as backup when the NIC has one queue
echo f0 > /sys/class/net/eth0/queues/rx-0/rps_cpus

On a multi-queue NIC, give each game process its own RX queue and pin the matching queue’s IRQ to a core that is not running the tick loop. On a single-queue NIC, RPS spreads packet processing across cores but adds a softirq hop — measure before and after, since it can increase jitter when the packet rate is low.

Jitter Sources Ranked by Impact

Not every source of jitter matters equally. These are measured contributions to 99th-percentile tick delta on a 16-core host running a 128-tick server, ranked from largest to smallest. Fix them in this order.

SourceTypical jitter addedFix
CPU C-state exit latency150-600 usDisable deep C-states on game cores
NIC IRQ on the tick core80-400 usIRQ affinity + RX queue split
Task migration between cores50-250 usRaise sched_migration_cost_ns, pin
Frequency ramp from idle40-150 usperformance governor
UDP receive buffer dropsbursty, 1-20 msRaise rmem_max and backlog
Swap under memory pressure2-50 msvm.swappiness=1, reserve RAM
Transparent huge page compaction1-30 msmadvise mode or disable THP

The first four are microsecond-scale and disappear with the settings above. The last three are the ones players actually feel: a 20 ms stall in a 7.81 ms tick window is two or three skipped ticks and visible rubber-banding. They only appear under memory pressure or heavy traffic, which is why load testing at realistic player counts matters more than idle benchmarks.

What Not to Change

Avoid enabling huge pages for game servers that allocate in small objects, because compaction pauses appear directly as tick stalls. Do not blanket-disable the scheduler’s load balancing on a shared host; pin only the game process with taskset or cpuset and leave the rest to the kernel. Skip any tuning guide that raises net.core.somaxconn for a UDP game — that backlog is TCP-only and irrelevant to the workload. And never copy a database-server tuning profile onto a game node: aggressive dirty-page flush settings that help write throughput add latency the tick loop cannot absorb.

Verifying the Result

Re-run cyclictest and compare the 99th-percentile and maximum values against baseline. A correctly tuned game host shows a maximum scheduling delay under 200 microseconds and a stable tick delta at the 99th percentile. Average latency barely moves — the gain is entirely in eliminating outliers, which is what players perceive as lag. This tuning needs hardware that exposes all these knobs, which is the case on a bare metal dedicated server for game hosting rather than a virtualised tier where a hypervisor reintroduces the latency you just removed. Rolling the same sysctl values out across a fleet with a config-management role keeps it consistent, and a high-traffic game server deployment is where these reductions translate into fewer lag complaints per player-hour.

Leave a Reply