--- title: "CPU Governor: Why 'performance' Matters for Game Servers" excerpt: "How Linux CPU frequency governors work, why ondemand costs a game server latency, and how to set the performance governor so the core runs at full clock continuously." category: "optimization" tags: "cpu, linux" image: "" read_time: "8 min read" ---
A CS 1.6 server sends and services packets in bursts, hundreds of times a second, with long-ish idle gaps between them. That pattern is exactly what fools the default Linux CPU governor: it sees the idle gaps, clocks the core down to save power, and then has to ramp back up when the next packet arrives — adding latency at the worst moment. On a 1000 FPS server those micro-stutters show up as jitter. Switching to the performance governor pins the core at full clock and removes the ramp entirely.
The CPU frequency governor is the kernel policy that decides, moment to moment, what clock speed each core runs at. The common ones:
performance — hold the maximum frequency at all times. No ramp, no latency, higher idle power.powersave — hold the minimum frequency. Worst case for a game server.ondemand / schedutil — scale frequency up and down with load. Great for laptops, bad for bursty low-average-load servers because the burst is over before the clock has ramped.A game server's average CPU can look low even when its latency needs are high — that mismatch is precisely why load-scaling governors underserve it.
Read what each core is set to:
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
Or, if cpupower is installed:
cpupower frequency-info
If you see ondemand, schedutil, or powersave, you are leaving latency on the table. Also read the live frequency to see the ramp in action:
grep MHz /proc/cpuinfo
The clean way, with the cpupower tool:
apt install linux-tools-common linux-tools-generic # Debian/Ubuntu cpupower frequency-set -g performance
Or write directly to sysfs for every core, no package needed:
for c in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do echo performance | sudo tee "$c" done
Re-read the governor afterward to confirm every core now says performance.
Both methods above are lost on reboot. Persist it. On systems with the cpupower service, set the governor in /etc/default/cpupower (or the distro's cpufrequtils config) and enable the service. A simple, portable alternative is a systemd unit that writes the sysfs values at boot, or adding the for loop above to a startup script that runs before your game servers launch. Whatever you choose, verify after a reboot — a governor that reverts to ondemand overnight quietly reintroduces the jitter you fixed.
The performance governor helps most on:
It matters less — or not at all — on many VPS plans, where the host controls CPU frequency and your guest may not even expose scaling_governor. If /sys/devices/system/cpu/cpu*/cpufreq/ does not exist in your VPS, frequency is the host's decision, and your real enemy there is steal time, not the governor.
The governor is only the operating-system layer of frequency control; two more knobs live below it. Turbo/boost lets a core briefly exceed its base clock — leave it enabled, since a game server benefits from every extra MHz on its single core. C-states are deep idle power states the core drops into between packets; entering and exiting them adds latency exactly like the governor's ramp does. On a dedicated box tuned for lowest latency, admins often disable the deepest C-states (via a kernel boot parameter such as processor.max_cstate=1 or the equivalent BIOS setting) so the core stays responsive. Do this only on bare metal you own and only if you have measured jitter that justifies it — it raises idle power and heat. The performance governor plus shallow C-states is the standard low-latency combination for a machine whose whole job is serving game frames.
ondemand on a dedicated box — the ramp latency is exactly what hurts a bursty game server. Set performance.cpupower frequency-set are not persistent. Bake it into boot.scaling_governor is absent, the host owns frequency. Chase steal instead.Confirm the change stuck and had an effect. Re-read scaling_governor for every core — all should say performance. Then watch the live clock under load with watch -n1 "grep MHz /proc/cpuinfo"; on performance the cores should sit at or near their maximum rated frequency constantly instead of bouncing between a low idle clock and boost. Finally, re-check your server FPS stability — the average may not change, but the dips should shrink. Combine this with pinning the server to a core so the same core is both dedicated and running flat-out.