Stop Linux Gaming Stutter: Automatic CPU Scheduler Switching with sched_ext (2026)
estimated read time: 13 minutes
TL;DR
Install
scx-scheds, drop a config into Gamemode, and addgamemoderunto your Steam launch options. Every game automatically switches to a low-latency CPU scheduler on launch and switches back when you’re done. Takes about 20 minutes. Works on Intel and AMD.
I’ve been running Linux as my daily gaming OS for a while now and the one thing that kept bugging me was stutter — not from GPU drivers or Proton, but from the CPU scheduler treating a game with the same priority as any other process. Kernel 6.12 finally gives us a clean fix for this, and it’s surprisingly straightforward to set up.
Quick Setup
Prerequisites
- Kernel 6.12+ with sched_ext support (6.15+ recommended)
- Arch Linux or an Arch-based distro
Check your kernel:
uname -r
# Should be 6.12.0 or higher
If you need to upgrade:
sudo pacman -S linux-zen linux-zen-headers
# Then reboot
Step 1: Install scx Schedulers
scx-scheds is in the official Arch repos — no AUR needed:
sudo pacman -S scx-scheds
Verify:
scxctl list
# Should show: lavd, rusty, bpfland, central, etc.
Step 2: Polkit — Passwordless Switching
Gamemode needs to call scxctl without a password prompt. Create a polkit rule for wheel group users:
sudo nano /etc/polkit-1/rules.d/99-scx-loader.rules
Paste:
polkit.addRule(function (action, subject) {
if (action.id.indexOf("org.scx.") === 0 && subject.isInGroup("wheel")) {
return polkit.Result.YES;
}
});
Reload polkit:
sudo systemctl restart polkit
Test it works without a password prompt:
scxctl switch -s lavd
scxctl status
# Should show: Current scheduler: lavd
scxctl switch -s rusty
Step 3: Install & Configure Gamemode
sudo pacman -S gamemode lib32-gamemode
sudo systemctl enable --now gamemoded
First, check your CPU so you know which config to use:
lscpu | grep "Model name"
Create /etc/gamemode.ini:
sudo nano /etc/gamemode.ini
Intel, or AMD without X3D (most users) — just the scheduler switch, nothing else needed:
[custom]
; Switch to low-latency scheduler when a game launches
start=scxctl switch -s lavd
; Switch back to throughput scheduler when the game closes
stop=scxctl switch -s rusty
AMD Ryzen 7800X3D — single V-Cache CCD, core pinning is optional but adds a small benefit:
[cpu]
; 7800X3D has one CCD, so all cores have V-Cache — pinning reduces migration overhead
pin_cores=0-7
[custom]
start=scxctl switch -s lavd
stop=scxctl switch -s rusty
AMD Ryzen 7950X3D or 7900X3D — two CCDs but only CCD0 has V-Cache, so pinning is important here. Without it the scheduler can silently put your game on the slower die:
[cpu]
; Pins games to the V-Cache die (CCD0). Cores 0-7 physical, 16-23 their SMT siblings
pin_cores=0-7,16-23
[custom]
start=scxctl switch -s lavd
stop=scxctl switch -s rusty
Not sure which applies to you? See the Core Pinning section for a full explanation of the architecture difference.
Restart the Gamemode daemon:
sudo systemctl restart gamemoded
Step 4: Enable for Your Games
Steam: Right-click a game → Properties → General → Launch Options:
gamemoderun %command%
Lutris: System Options → Enable Gamemode (checkbox).
Heroic Games Launcher: Add gamemoderun to the game’s launch arguments.
That’s it. Every game launch now automatically switches to scx_lavd. Every close switches back to scx_rusty.
Verifying It Works
Launch a game, then in a terminal:
scxctl status
# Should show: Current scheduler: lavd
Watch Gamemode logs in real time:
journalctl -u gamemoded -f
Close the game:
scxctl status
# Should show: Current scheduler: rusty
Not on Arch Linux?
Other distros: The scx schedulers and Gamemode config are identical on Fedora, Ubuntu, and Pop!_OS — only the package manager differs. On Fedora: sudo dnf install scx-scheds gamemode. On Ubuntu 24.04+: sudo apt install scx-scheds gamemode. The polkit rules and gamemode.ini config are copy-paste identical.
Intel CPUs: Everything in this guide works the same way on Intel. The only section that doesn’t apply is the Ryzen X3D core pinning — skip pin_cores in your gamemode.ini and follow the rest as-is.
How It Works
The Problem: CFS Doesn’t Optimize for Gaming
Linux gaming in 2026 is excellent — Proton, solid GPU drivers, Steam Deck — but most distributions still use the Completely Fair Scheduler (CFS). CFS is designed for server workloads: maximize throughput, treat everything fairly.
That’s the problem. When you’re gaming and a background task spins up (Discord, browser, compiler), CFS gives both equal CPU time. Your game stutters because the scheduler doesn’t know it’s latency-sensitive.
sched_ext changes this. Merged in Linux 6.12, it lets you hot-swap CPU schedulers at runtime — no reboot, no kernel rebuild, just load a different scheduler based on your workload.
Why Two Schedulers?
Like many home Linux desktop users, my main machine is a multi-purpose workstation — switching between admin tasks like writing documentation, programming, and CPU/GPU-intensive creative workflows. In any case, I want the CPU to optimise its performance for whatever is in front of me at the time.
PC gaming adds a unique angle to this. Most games are optimised for 8 threads of compute rather than raw parallelism, but players are acutely sensitive to any frame delay that presents itself as a stutter, elastic-banding, or input lag. The reason I’ve chosen two schedulers is exactly that: I want my PC to automatically shift gear when I start a game, moving from a throughput-focused desktop mode to one that minimises latency and delivers smooth gameplay.
scx_lavd (Latency-criticality Aware Virtual Deadline) was developed by Igalia for the Steam Deck. It minimizes latency spikes, improves 1% low FPS, and keeps games responsive even with background tasks running. Meta uses it in production because it handles mixed workloads brilliantly.
scx_rusty is a general-purpose global scheduler optimized for throughput. Perfect for desktop use: browser tabs, background compilation, music streaming. In my testing, scx_rusty gave 5-7x throughput improvement over CFS for parallel builds.
scx_lavd vs scx_rusty: Quick Comparison
| Feature | scx_lavd | scx_rusty | CFS (default) |
|---|---|---|---|
| Optimized for | Gaming, low latency | Throughput, desktop | General fairness |
| 1% Low FPS | ⭐⭐⭐⭐⭐ Best | ⭐⭐ Poor | ⭐⭐⭐ Good |
| Compile Speed | ⭐⭐⭐ Good | ⭐⭐⭐⭐⭐ 5-7x faster | ⭐⭐⭐ Baseline |
| Frame Time Variance | 2.9ms (smooth) | 4.8ms (stuttery) | 4.2ms (okay) |
| Best Use Case | FPS/action games | Background tasks | Server workloads |
Use scx_lavd when gaming, scx_rusty for everything else.
Understanding Gamemode
Gamemode is a daemon from Feral Interactive (the studio behind Linux ports of games like Total War and XCOM) that automatically applies a suite of performance optimisations the moment a game launches — and undoes them cleanly when the game closes.
Think of it as a “gaming profile” that runs in the background. When you start a game, Gamemode:
- Switches the CPU governor to
performance(maximum clock speed) - Applies process priority (niceness) boosts to the game
- Disables CPU core parking and power saving
- Runs any custom shell commands you define — this is how we hook in the scheduler switch
The key word is automatic. You don’t open a terminal, you don’t run a script manually — you just launch your game the usual way via Steam or Lutris, and Gamemode handles everything in the background.
If you’ve heard of Windows tools like Process Lasso or Razer Cortex, Gamemode is the Linux equivalent — except it’s open source, lightweight (~1MB), and integrates cleanly with the desktop.
How the hook works
Gamemode exposes two custom command slots in its config:
start=— runs when a game registers with Gamemodestop=— runs when the game exits
We use these to call scxctl switch, so the scheduler changes happen alongside all the other optimisations with zero extra effort from you.
Testing Schedulers Manually
Before relying on Gamemode, it’s worth verifying the schedulers work as expected.
Baseline: Default CFS
stress-ng --cpu $(nproc) --timeout 30s --metrics-brief
Note the “bogo ops/sec” — this is your baseline throughput.
scx_rusty: General Compute
scxctl switch -s rusty
stress-ng --cpu $(nproc) --timeout 30s --metrics-brief
On my machine (Ryzen 9 7950X3D, 16C/32T):
- CFS: ~180,000 bogo ops/sec
- scx_rusty: ~920,000 bogo ops/sec (5.1x improvement!)
Your numbers will vary by CPU, but the relative gap between schedulers should be consistent.
scx_lavd: Gaming Mode
scxctl switch -s lavd
Run the stress test — you’ll see lower throughput than scx_rusty. That’s intentional: scx_lavd trades raw throughput for latency.
Switch back when done:
scxctl switch -s rusty
Advanced: Ryzen 7950X3D Core Pinning Explained
The pin_cores=0-7,16-23 line in the Gamemode config is critical for 7950X3D and 7900X3D performance.
The Problem: Dual-CCD Architecture
Ryzen 7950X3D has two CCDs (chiplets):
- CCD0 (cores 0-7): 96MB 3D V-Cache — optimized for gaming
- CCD1 (cores 8-15): 32MB regular L3 — optimized for productivity
Only CCD0 has the 3D V-Cache. If your game runs on CCD1, you lose 20-30% FPS.
On Windows, the Xbox Game Bar driver automatically pins games to CCD0. Linux doesn’t have this. Without manual pinning, the scheduler randomly assigns cores, and your game will:
- Run on the wrong CCD (slower)
- Migrate between CCDs mid-game (stuttering)
- Fight with background tasks for V-Cache cores
Core Topology on 7950X3D
Cores 0-7: Physical cores (CCD0, 3D V-Cache) ← Pin games here
Cores 8-15: Physical cores (CCD1, regular cache)
Cores 16-23: SMT siblings of 0-7 (CCD0)
Cores 24-31: SMT siblings of 8-15 (CCD1)
By pinning to 0-7,16-23 we lock the game to CCD0, use all 8 physical cores and their SMT threads, and let background tasks run freely on CCD1.
Verifying Your CCD Layout
lscpu -e
# Look for cores 0-7 and their L3 cache size
Or install hwloc for a visual diagram:
sudo pacman -S hwloc
lstopo --no-io
Should You Pin?
| CPU | Action |
|---|---|
| 7950X3D | Mandatory — 2 CCDs, only CCD0 has V-Cache |
| 7900X3D | Mandatory — same architecture |
| 7800X3D | Optional — single CCD, all cores have V-Cache |
| Non-X3D | Not needed — no cache difference between chiplets |
Advanced: Spring Boot Benchmark — Why scx_rusty Wins for Desktop
To confirm which scheduler to use when not gaming, I ran scx schedulers under realistic CPU load using a Spring Boot banking application — the same kind of pressure you’d see from a background compiler, Docker build, or local dev server.
Test Setup
- CPU: AMD Ryzen 9 7950X3D (16C/32T)
- RAM: 64GB DDR5
- Test environment: QEMU/KVM VM (16GB RAM, 8 vCPUs, kernel 6.12.6 with sched_ext)
- Load test: Gatling, 17,370 requests, 5-minute runs
Results
| Scheduler | Success Rate | Mean Response | p95 Response | Best For |
|---|---|---|---|---|
| scx_rusty ⭐ | 95.2% | 1,154ms | 5,048ms | CPU-intensive throughput |
| scx_lavd | 100% | 19,895ms | 39,669ms | Interactive/latency-sensitive |
| CFS (default) | 77.7% | 1,669ms | 9,392ms | General purpose baseline |
| scx_layered | 98.7% | 38,458ms | 57,502ms | Multi-tenant fairness |
| scx_bpfland | 31.8% | 22,696ms | 53,974ms | ❌ Poor fit for this workload |
scx_rusty’s work-stealing, load-balancing design keeps all cores busy for CPU-bound tasks. scx_lavd trades that raw throughput for latency guarantees — the right call for gaming, the wrong call for batch processing.
Full benchmark details: github.com/dfoulkes/scx_test_harness
Monitoring Scheduler Performance
# Check current scheduler
scxctl status
# List all available schedulers
scxctl list
# Deeper kernel-level stats (requires debugfs)
sudo cat /sys/kernel/debug/sched/ext/stats
The stats file shows latency percentiles (p50, p90, p99), runqueue depth, and context switches — useful if you want to confirm scx_lavd is actually reducing tail latency.
Troubleshooting
scxctl says “sched_ext not supported”
uname -r
# Must be 6.12.0 or higher
zgrep CONFIG_SCHED_CLASS_EXT /proc/config.gz
# Should show: CONFIG_SCHED_CLASS_EXT=y
If the config flag is missing, switch to linux-zen:
sudo pacman -S linux-zen linux-zen-headers
Gamemode doesn’t switch schedulers
# Check the daemon is running
systemctl status gamemoded
# Test scxctl manually (should work without a password prompt)
scxctl switch -s lavd
scxctl status
# If you get a password prompt, verify the polkit rule
cat /etc/polkit-1/rules.d/99-scx-loader.rules
sudo systemctl restart polkit
Scheduler crashes or game stutters
dmesg | grep scx
Common cause: CPU governor stuck on powersave. Fix immediately:
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
Make it permanent via Gamemode:
[cpu]
governor=performance
Why This Matters
Most Linux gaming guides obsess over GPU drivers, Proton, and Wine. Almost no one talks about the CPU scheduler — even though it’s the first thing your game interacts with.
sched_ext changes the game. We can now optimize the scheduler for the workload:
- Gaming → scx_lavd (low latency, smooth 1% lows)
- Compiling → scx_rusty (high throughput)
- Server → scx_central (consistency over peak performance)
Linux gaming in 2026 isn’t just “good enough” — it’s competitive. scx_lavd can deliver smoother frame pacing than Windows defaults because the scheduler is optimised specifically for latency-sensitive interactive workloads, regardless of what CPU you’re running.
This is why Steam Deck works. This is why Valve invested in sched_ext. The future is here.
FAQ
Does scx_lavd work on Intel CPUs? Yes. scx_lavd is scheduler logic, not hardware-specific. Intel users won’t benefit from the CCD core pinning, but the latency improvements and automatic Gamemode switching work identically.
Do I need to reboot to switch schedulers?
No. That’s the entire point of sched_ext — schedulers are hot-swappable at runtime via scxctl switch. No reboot, no kernel module reload.
Will this break anything? scx schedulers run in BPF userspace and fall back gracefully to CFS if they crash. The worst case is your game reverts to CFS mid-session. In practice, scx_lavd and scx_rusty are stable on 6.12+ kernels.
What’s the difference between scx_lavd and scx_bpfland? Both target low latency but use different scheduling policies. My benchmarks show scx_bpfland performing poorly under mixed workloads. Stick with scx_lavd for gaming.
Does this work with Lutris and Heroic Games Launcher?
Yes. Enable Gamemode in Lutris via System Options → Enable Gamemode. For Heroic, add gamemoderun to the game’s launch arguments. The scheduler switching happens the same way.
Is this the same as what Steam Deck uses? Yes — Valve ships scx_lavd on Steam Deck OS for exactly this reason. This guide replicates that setup on desktop Arch Linux.
Do I need a Ryzen X3D CPU to benefit? No. Any CPU on kernel 6.12+ benefits from scx_lavd’s latency improvements. The core pinning section is X3D-specific, but the rest of the guide applies universally.
Further Reading
- sched_ext kernel documentation
- scx GitHub repo
- Arch Wiki: Gaming
- Gamemode GitHub
- Phoronix: sched_ext benchmarks
- Arch Package: scx-scheds
Conclusion
This setup takes 20 minutes to configure and delivers measurable improvements. scx_lavd reduces stutter and improves 1% lows for gaming; scx_rusty gives you back full throughput the moment you close the game. Gamemode automates the switch so you never think about it again.
The magic isn’t in the hardware. It’s in the scheduler understanding that your game is latency-sensitive and your background Discord isn’t.
Questions? Find me on GitHub.