For: Intel 8th–10th gen Core i5/i7, NVIDIA Turing/Ampere, 16GB RAM, CachyOS with Wayland.
Kernel: linux-cachyos, PREEMPT, 1000Hz, EEVDF default, sched_ext enabled.
Every section explains what CachyOS gives you out of the box, what to add, and the tradeoffs. All config files are at the bottom: copy, paste, done.
CachyOS ships with aggressive defaults. Know what's already tuned so you don't break it or do it twice.
The flagship linux-cachyos package (what most installs run) includes PREEMPT (full preemption), 1000Hz tick rate, Clang ThinLTO, x86-64-v3/v4 targeting, and NTSYNC for Wine/Proton. All of this is there from install.
linux-cachyos defaults to EEVDF (Earliest Eligible Virtual Deadline First, mainline's scheduler since Linux 6.6), not BORE. BORE (Burst-Oriented Response Enhancer, a fork of EEVDF tuned for burst and interactive responsiveness) is a separate package, linux-cachyos-bore. Install it and reboot if you want BORE as your always-on scheduler. What both variants share is CONFIG_SCHED_CLASS_EXT=y, the sched_ext framework, which lets you load a completely different BPF scheduler at runtime with no reboot. That's a bigger lever than picking BORE vs EEVDF at install time. See §5.vm.swappiness = 100
vm.vfs_cache_pressure = 50
vm.dirty_bytes = 268435456
vm.dirty_background_bytes = 67108864
vm.dirty_writeback_centisecs = 1500
vm.page-cluster = 0
kernel.nmi_watchdog = 0
kernel.split_lock_mitigate = 0
kernel.printk = 3 3 3 3
kernel.kptr_restrict = 2
net.core.netdev_max_backlog = 4096
fs.file-max = 2097152zstd compression, RAM-sized, swap priority 100. A udev rule sets vm.swappiness=150 at activation. High swappiness keeps file cache in RAM and pushes cold anonymous pages into compressed ZRAM instead.
always + defer+madvise defrag + max_ptes_none=409. Benefits tcmalloc apps (Chromium, Proton games) without the historical memory bloat.
bfq for HDDs, mq-deadline for SATA SSDs, kyber for NVMe.
NVreg_UsePageAttributeTable=1, NVreg_InitializeSystemMemoryAllocations=0, NVreg_DynamicPowerManagement=0x02. CachyOS sets these for you.
| Setting | Value |
|---|---|
| Journal max size | 50 MB |
| Service start timeout | 15 s |
| Service stop timeout | 10 s |
| DefaultLimitNOFILE (system) | 2048:2097152 |
| DefaultLimitNOFILE (user) | 1024:1048576 |
rtkit + audio group rtprio 99. SATA ALPM = max_performance. hdparm -B 254 -S 0 on HDDs. iTCO_wdt + sp5100_tco blacklisted. NTP via Cloudflare + Google. DNS via systemd-resolved.
Rule #1: Don't fuck up your system without a net. CachyOS defaults to BTRFS. Use it:
sudo btrfs subvolume snapshot / /@pre-optimizationRule #2: Test one change at a time. Rebooting after applying the whole list is a recipe for not knowing what broke.
CachyOS uses Limine. Parameters go in /etc/default/limine and apply with sudo limine-mkinitcpio. If you use GRUB or systemd-boot the parameters are identical; only where you put them differs.
quiet mitigations=off nowatchdog nmi_watchdog=0 nvidia_drm.modeset=1
tsc=reliable clocksource=tsc intel_pstate=active preempt=full
split_lock_detect=off pcie_aspm=performance intel_idle.max_cstate=1
transparent_hugepage=madvise splash rw| Parameter | Effect | Skip if |
|---|---|---|
mitigations=off | Disable all CPU vulnerability mitigations | Machine handles sensitive data or untrusted code |
nowatchdog | Disable all watchdog timers | n/a |
nvidia_drm.modeset=1 | DRM modesetting (required for Wayland) | X11 only |
tsc=reliable clocksource=tsc | Force TSC as clocksource | Unstable TSC hardware (rare) |
intel_pstate=active | Intel P-State active mode | AMD CPU |
preempt=full | Full kernel preemption | Already in CachyOS kernel; adding anyway is harmless |
split_lock_detect=off | Disable split lock detection | Server workloads |
pcie_aspm=performance | Disable PCIe power management | Laptops (battery impact) |
intel_idle.max_cstate=1 | Limit CPU to C1 idle state | Laptops or power-sensitive machines |
Kernel update survival guide: After a pacman -Syu, check your NVIDIA params and scheduler availability:
cat /proc/driver/nvidia/params | grep -E "UsePageAttributeTable|InitializeSystemMemoryAllocations"
cat /sys/block/nvme0n1/queue/scheduler # if ADIOS is gone, revert to kyber# Edit and apply
sudo nano /etc/default/limine
sudo limine-mkinitcpio
sudo rebootLock the governor to performance using three mechanisms; each covers gaps in the others.
Step 1: cpupower service
sudo systemctl enable --now cpupower
echo 'governor="performance"' | sudo tee /etc/cpupower.confStep 2: tmpfiles.d: these run at early boot, before any desktop session. A power manager daemon can't override what was set before it started.
# /etc/tmpfiles.d/force-performance.conf
w /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor - - - - performance
# /etc/tmpfiles.d/force-epp-performance.conf
w /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference - - - - performanceVerify:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# → performance
cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference
# → performancelinux-cachyos ships EEVDF as its default scheduler, not BORE. See the correction in §1. EEVDF vs BORE matters less than what actually sets CachyOS apart here: CONFIG_SCHED_CLASS_EXT=y is built into the default kernel, so sched_ext (SCX) is available from install. SCX schedulers are CPU schedulers implemented as loadable BPF programs. You can swap the whole scheduling algorithm at runtime. No reboot, no separate kernel, and you're back on EEVDF the moment you stop one.
sudo pacman -S scx-scheds scx-tools
# scx_loader (background service, D-Bus API) and scxctl (CLI client) come with scx-toolsIf you want the newest experimental schedulers before they land in the stable branch, use scx-scheds-git scx-tools-git instead.
# One-off test. Ctrl+C stops it and you're back on EEVDF.
sudo scx_bpfland
# Managed via scxctl, which talks to the scx_loader D-Bus service
sudo systemctl enable --now scx_loader
scxctl start --sched bpfland --mode gaming
scxctl get # what's running right now
scxctl stop # back to EEVDFCachyOS Kernel Manager and the standalone SCX Manager GUI both wrap the same scx_loader service if you'd rather click through it than type it.
The i5-9400F is a monolithic 6-core, 6-thread die. No SMT, no heterogeneous P/E cores. That rules out most of the SMT-contention and hybrid-core-aware flags other schedulers expose, so the choice really comes down to raw interactivity under load.
| Scheduler | Best for | Notes |
|---|---|---|
scx_bpfland | General desktop and gaming | vruntime-based, prioritizes interactive tasks, L2/L3-cache aware placement. Low Latency mode: -m performance -w |
scx_cake | Gaming specifically | Classifies threads into 4 tiers by measured runtime (input/audio → render → physics/AI → background compile) so frame-critical threads never queue behind a shader-compile job. esports profile drops the quantum to 1ms for competitive FPS titles |
scx_lavd | Gaming, latency-sensitive workloads | Built for gaming's latency-critical, communication-heavy pattern. --performance flag maximizes responsiveness. --autopower adjusts power mode automatically through LAVD's Core Compaction logic, which matters more on a laptop than on this 6C/6T desktop chip |
scx_flash | Consistency under stress | EDF-based, rewards tasks that yield the CPU early. Gaming mode: -m all |
scx_rusty | Desktop and multimedia | The original CachyOS SCX scheduler pitch. Interactivity close to BORE without a kernel rebuild |
Numbers below are from a real CS2 benchmark run on this exact machine (COSMIC/Wayland, i5-9400F, GTX 1650 at the 75W/1860MHz lock from §9), launch options LOW_LATENCY_LAYER=1 LOW_LATENCY_LAYER_REFLEX=1 SDL_VIDEODRIVER=wayland gamemoderun %command% -sdlaudiodriver pulse -novid, both schedulers on their low-latency/esports profile:
CS2: scx_cake vs scx_lavd (lowlatency, 2 runs)
Avg FPS P1 low P99 (ms)
cake r1 208.9 116.7 8.57
cake r2 208.1 109.1 9.16
cake avg 208.5 112.9 8.87
lavd r1 208.6 108.2 9.24
lavd r2 200.4 91.2 10.96
lavd avg 204.5 99.7 10.10scx_cake beat scx_lavd on this box, mainly on consistency: cake's 1% low stayed within about 8ms of itself across both runs, lavd's second run dropped a spike that cost it roughly 13ms of 1% low margin against cake's average. That's one bad run out of two though, not a verdict. Worth another 2 to 3 passes before writing lavd off entirely, especially since it's tuned around gaming workloads on paper and might just need a different flag set on a 6-core chip with no SMT than it gets on the hardware it's usually benchmarked on. scx_bpfland and scx_cake were the best performers overall on this setup. Your mileage may genuinely vary since SCX performance is workload- and CPU-topology-dependent. Run your own comparison with schbench/cachyos-benchmarker and the games you actually play before locking anything in.
sudo mkdir -p /etc/scx_loader
sudo cp /usr/share/scx_loader/config.toml /etc/scx_loader/config.toml# /etc/scx_loader/config.toml
default_sched = "scx_cake"
default_mode = "Gaming"sudo systemctl enable --now scx_loader.serviceSwap to bpfland for testing with scxctl switch --sched bpfland --mode gaming, no need to edit the config file for a quick comparison.
power-profiles-daemon in §14 so it stops fighting the locked-performance governor. If you've masked it, that auto-switch integration won't fire. Set default_mode = "Gaming" directly instead, or use scx_loader's game-performance hook so it switches automatically when Gamemode launches a game, regardless of what the power profile daemon is doing.§10 tells you to disable ananicy-cpp because it fights Gamemode's renice values. That's still correct and has nothing to do with sched_ext. Separately, ananicy-cpp used to cause stalls when combined with early SCX schedulers. On current scx-scheds releases the two are generally fine together. If you re-enable ananicy-cpp for other reasons and see stalls, disabling it is still the first thing to try.
sudo pacman -S schbench cachyos-benchmarker
schbench -m 2 -t 8 -r 60 # wakeup and request latency percentiles
cachyos-benchmarker ~/bench/ # full suite: compiles, encodes, hashes, renders, per-schedulerRun the same test across EEVDF (default, nothing loaded), BORE if you install that variant, and 2 to 3 SCX schedulers before picking one permanently. A scheduler that wins on paper for "gaming" can still lose on your specific combination of a 6-core no-SMT budget CPU and one GPU doing all the rendering work. That's exactly what the cake vs lavd numbers above show: run it yourself, don't take a table off a forum post as gospel, including this one.
CachyOS defaults to zstd. On a 6-core CPU without hyperthreading, zstd compression eats measurable CPU during memory pressure. Switch to lz4 if you have fewer than 8 threads or notice CPU spikes under load.
# /etc/systemd/zram-generator.conf.d/override.conf
[zram0]
compression-algorithm = lz4| Algorithm | Compression speed | Decompression speed | Ratio |
|---|---|---|---|
| lz4 | ~3–4x faster | ~5x faster | ~15–20% worse |
| zstd (default) | baseline | baseline | baseline |
sudo systemctl restart systemd-zram-setup@zram0Linux defaults allow 20% of RAM (~3.2GB on 16GB) to become dirty before throttling writes. When you download or extract a large file, everything buffers in page cache, then flushes all at once. The resulting I/O storm starves the compositor. You see stutter.
# In /etc/sysctl.d/99-latency.conf:
vm.dirty_background_ratio = 3
vm.dirty_ratio = 8| Parameter | Kernel default | Recommended | Effect |
|---|---|---|---|
vm.dirty_background_ratio | 10 | 3 | Start flushing at ~500MB dirty (16GB RAM) |
vm.dirty_ratio | 20 | 8 | Throttle writes at ~1.3GB dirty |
SSD root:
UUID=... / xfs defaults,lazytime,noatime,inode64,logbsize=256k,noquota 0 1HDD bulk storage:
UUID=... /mount/point xfs defaults,noatime,nofail,allocsize=64m 0 0| Option | Effect | When |
|---|---|---|
lazytime | Buffer atime/mtime in RAM, flush opportunistically | SSD root, huge metadata write reduction |
noatime | Never update access time | Always. No reason to track atime on desktop |
inode64 | Inodes across full 64-bit space | Required for >1TB volumes |
logbsize=256k | Larger journal buffer (default 32k) | SSD only |
noquota | Disable quota accounting | Unless you need quotas |
allocsize=64m | Pre-allocate 64MB extents | HDD, sequential writes (media, backups) |
nofail | Boot continues if drive missing | Non-critical secondary drives |
tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0Puts /tmp in RAM. Reduces SSD writes, speeds up temp file operations. Negligible memory cost on 16GB.
If you have a second SSD for downloads or temp data, F2FS excels at sequential writes. Ideal for drives where data integrity isn't critical.
sudo mkfs.f2fs -f /dev/sdX # destructive, wipes the driveCachyOS defaults: mq-deadline (SSD), kyber (NVMe), bfq (HDD). ADIOS (Adaptive Disk I/O Scheduler, a CachyOS kernel feature) balances throughput and latency better for single-user desktops:
# /etc/udev/rules.d/60-ioschedulers.rules
# HDD: BFQ
ACTION=="add|change", KERNEL=="sd[a-z]*", ATTR{queue/rotational}=="1",
ATTR{queue/scheduler}="bfq"
# SSD: ADIOS
ACTION=="add|change", KERNEL=="sd[a-z]*|mmcblk[0-9]*", ATTR{queue/rotational}=="0",
ATTR{queue/scheduler}="adios"
# NVMe: ADIOS
ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/rotational}=="0",
ATTR{queue/scheduler}="adios"sudo udevadm control --reload-rules && sudo udevadm triggerNVMe APST (optional): Some NVMe drives aggressively enter power-saving states. Disable it:
echo 0 | sudo tee /sys/class/nvme/nvme0/device/power/controlsudo systemctl enable --now nvidia-persistenced
Keeps driver loaded with no apps using GPU. Kills the ~1–3s init delay on first launch after boot.
NVIDIA defaults to Limited Range (16–235) over HDMI, causing black crush and washed out colors.
# /etc/X11/xorg.conf.d/20-nvidia-full-rgb.conf
Section "Device"
Identifier "NVIDIA"
Driver "nvidia"
Option "ColorSpace" "RGB"
Option "ColorRange" "Full"
EndSection
Note: If nvidia-settings daemon is running, it might override this. Kill it if needed: sudo pkill nvidia-settings.
Put these in /etc/environment; they apply system-wide:
__GL_THREADED_OPTIMIZATION=1
__GL_SHADER_DISK_CACHE=1
__GL_SHADER_DISK_CACHE_SKIP_CLEANUP=1
__GL_VRR_ALLOWED=0
__GL_SYNC_TO_VBLANK=0
__GL_MaxFramesAllowed=1
VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
WINEDEBUG=-all| Variable | Effect | Skip if |
|---|---|---|
__GL_THREADED_OPTIMIZATION=1 | Multi-threaded OpenGL queue | n/a |
__GL_SHADER_DISK_CACHE=1 | Persist compiled shaders to disk | Disk space extremely tight |
__GL_SHADER_DISK_CACHE_SKIP_CLEANUP=1 | Stop driver from purging cache | n/a |
__GL_SYNC_TO_VBLANK=0 | Disable V-Sync at driver level | If tearing bothers you |
__GL_VRR_ALLOWED=0 | Disable VRR/GSync | If you use a VRR display |
__GL_MaxFramesAllowed=1 | 1 pre-rendered frame (lowest latency) | n/a |
VK_ICD_FILENAMES=... | Force NVIDIA Vulkan ICD | Only if multiple GPUs |
WINEDEBUG=-all | Suppress Wine debug output | If debugging Wine issues |
__GL_SHADER_DISK_CACHE=1 enables the cache, but without a size limit, the driver uses its default cap of 1 GB (increased from 128 MB in driver 460). Modern titles (especially DXVK/VKD3D) can generate 2–4 GB of shaders across your library. When the cache exceeds the limit, the driver purges older entries, forcing recompilation on next launch, causing stutter and longer load times.
Set a global size limit to prevent eviction:
mkdir -p ~/.config/environment.d
echo "__GL_SHADER_DISK_CACHE_SIZE=12000000000" > ~/.config/environment.d/shader_cache.conf
Log out and back in, or reboot. Verify with:
env | grep __GL_SHADER_DISK_CACHE_SIZE
The GTX 1650's 4 GB VRAM bounds the shader permutation space. Beyond 4 GB disk cache, you're caching permutations for games you haven't launched in months without improving current-session hit rates.
__GL_SHADER_DISK_CACHE_SIZE globally ensures every application uses the same limit. If you set it per‑game and omit it on some launches, the driver reverts to the 1 GB default and wipes the cache when it exceeds the smaller limit.
Optional: clear legacy caches (old .nv path still uses 128 MB default):
rm -rf ~/.nv/GLCache ~/.cache/nvidia/GLCache
The driver will rebuild under the new XDG path (~/.cache/nvidia/GLCache) with the 4 GB cap applied.
__GL_SYNC_TO_VBLANK=0 + __GL_VRR_ALLOWED=0 disable all sync. You will see tearing. Uncapped unsynchronized frames have the lowest input latency. Set both to 1 if you prefer tear-free.
nvidia_drm.modeset=1 is necessary but not sufficient. Requirements:
nvidia-smi --query-gpu=driver_version --format=csv,noheader)If you get black screens or flickering, switch to X11.
LACT controls NVIDIA GPUs through NVML. GUI for overclocking, fan curves, monitoring.
sudo systemctl enable --now lactdTuring and later NVIDIA GPUs don't support traditional Linux undervolting. Instead: lock GPU clock below stock boost and add a positive P8 voltage offset. The GPU runs at higher voltage than it naturally would at that clock, with no power throttling and cooler running than stock boost.
| Setting | Recommendation | How to find yours |
|---|---|---|
| Power Limit | Max (varies by card) | nvidia-smi -q -d POWER |
| GPU Min Clock | 300 MHz | Stock minimum |
| GPU Max Clock | ~100 MHz below stock boost | nvidia-smi -q -d CLOCK | grep "Max Clocks" |
| GPU Offset (P8) | +50 to +100 MHz | Start at +50, test, increase |
| VRAM Offset (P8) | +500 to +900 MHz | Start at +500, test, increase gradually |
| Temp | 40°C | 45°C | 60°C | 70°C | 80°C |
|---|---|---|---|---|---|
| Fan | 40% | 50% | 55% | 65% | 80% |
Quiet at idle-moderate, aggressive past 70°C. Adjust to your card's cooler. Stay under 75°C during extended loads.
Stability: Run a demanding game for 2–3 hours. Reduce VRAM offset by 50MHz if you see artifacts, crashes, or driver errors. Test a full 8+ hour session before calling it stable.
Gamemode applies optimizations when you launch with gamemoderun %command%.
# /etc/gamemode.ini
[general]
renice = 20
ioprio = 0
[gpu]
apply = 1
nv_powermizer_mode = 1
[custom]
start = nvidia-smi -pm 1
end = nvidia-smi -pm 0| Setting | Value | Effect |
|---|---|---|
renice | 20 | Highest scheduling priority |
ioprio | 0 | Realtime I/O priority |
nv_powermizer_mode | 1 | Force max GPU clock level |
| start script | nvidia-smi -pm 1 | Enable persistence on game launch |
| end script | nvidia-smi -pm 0 | Disable persistence on game exit |
# /etc/security/limits.d/10-gamemode.conf
@gamemode - nice -10
sudo usermod -aG gamemode $USERananicy-cpp, an auto-priority daemon. It fights Gamemode's nice values, causing microstuttering. Disable it:sudo systemctl disable --now ananicy-cpp
| Scenario | Command |
|---|---|
| Native Linux | SDL_VIDEODRIVER=wayland gamemoderun %command% |
| Windows / Proton | PROTON_ENABLE_WAYLAND=1 gamemoderun %command% |
Replicates NVIDIA Control Panel "High Quality" filtering. NVIDIA Settings on Linux doesn't expose per-game control.
# DXVK (DirectX 9/10/11 via Proton)
DXVK_ANISO=16 DXVK_LODBIAS=-0.5 PROTON_ENABLE_WAYLAND=1 gamemoderun %command%
# Native OpenGL
__GL_LOG_ANISO=16 __GL_TEXTURE_LOD_BIAS=-0.5 SDL_VIDEODRIVER=wayland gamemoderun %command%
| Variable | Effect |
|---|---|
DXVK_ANISO=16 / __GL_LOG_ANISO=16 | 16x anisotropic filtering |
DXVK_LODBIAS=-0.5 / __GL_TEXTURE_LOD_BIAS=-0.5 | Force higher-res mipmaps |
Gamescope adds compositing latency. On a native Wayland compositor with fullscreen bypass (COSMIC, KWin, Mutter), you don't need it. Only use it for FSR upscaling, HDR tonemapping, or nested sessions.
sudo pacman -S proton-cachyos-native proton-cachyos-slr# ~/.config/MangoHud/MangoHud.conf
hud_compact
hud_no_margin
text_outline
background_alpha=0.3
font_size=14
table_columns=2
fps
frametime
gpu_stats
gpu_temp
gpu_core_clock
gpu_mem_clock
vram
cpu_stats
cpu_temp
cpu_mhz
wine
No frametime graph. It's a massive visual for one number. Compact two-column layout shows everything at a glance.
DLSS-style upscaling on non-RTX hardware via FSR injection. Install as Wine DLL override per-game. OptiScaler on GitHub.
# Wine DLL overrides
onlinefix64=n;winmm=n,b;steam_api64=n;version=n,b# /etc/pipewire/pipewire.conf.d/10-low-latency.conf
context.properties = {
default.clock.rate = 48000
default.clock.quantum = 128
default.clock.min-quantum = 128
default.clock.max-quantum = 512
}| Setting | Value | Effect |
|---|---|---|
| clock.rate | 48000 Hz | Standard sample rate |
| quantum | 128 samples | ~2.67ms processing cycle |
| min-quantum | 128 | Minimum block size |
| max-quantum | 512 | Maximum block size (~10.67ms) |
Latency: 128 / 48000 ≈ 2.67ms per cycle. Round-trip ≈ 5.3ms + hardware.
Tradeoff: Lower quantum = lower latency, higher CPU. 128 is good for competitive/rhythm games. 256 (~5.3ms) is fine for general desktop.
systemctl --user restart pipewire
pw-top # check QUANT column during playbackCachyOS already provides: rtkit daemon, audio group rtprio 99, CPU DMA latency device access, snd_hda_intel power save disabled on AC, HPET/RTC permissions for audio group.
# In /etc/sysctl.d/99-latency.conf:
net.core.netdev_max_backlog = 16384
net.ipv4.tcp_fastopen = 3
net.core.somaxconn = 1024| Setting | CachyOS default | Recommended | Why |
|---|---|---|---|
netdev_max_backlog | 4096 | 16384 | Larger per-CPU buffer, fewer drops under burst |
tcp_fastopen | 0 (off) | 3 | Client+server TFO, saves 1 RTT on repeat connections |
somaxconn | 4096 (kernel) | 1024 | Desktop tuning, not server |
CachyOS already provides: fq_codel qdisc, cubic TCP congestion, 120s keepalive, Cloudflare/Google NTP, systemd-resolved DNS.
Wine/Proton opens many FDs. CachyOS defaults are generous but can be raised further.
# /etc/security/limits.conf
* hard core 0
* soft core 0
* hard nofile 524288
* soft nofile 524288
root hard nofile 524288
root soft nofile 524288| Setting | Value | Why |
|---|---|---|
| Core dumps | 0 (off) | Prevent crash dump disk use. Re-enable if debugging crashes. |
| nofile | 524288 | Wine/Proton needs many simultaneous FDs |
# /etc/sysctl.d/99-latency.conf
vm.swappiness = 180
vm.dirty_background_ratio = 3
vm.dirty_ratio = 8
net.core.somaxconn = 1024
net.core.netdev_max_backlog = 16384
net.ipv4.tcp_fastopen = 3
fs.file-max = 2147483647
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 1024vm.swappiness=180 set here, but CachyOS ZRAM udev overrides to 150 at runtime. The high value signals intent: aggressively push cold anon pages to ZRAM. Effective: 150.
sudo sysctl --systemThese are enabled by default on CachyOS. They're useless on a dedicated gaming desktop.
| Service | Command | Why |
|---|---|---|
ananicy-cpp | disable --now | Fights Gamemode for nice values |
power-profiles-daemon | mask | Overrides manual CPU governor |
NetworkManager-wait-online | disable | Unnecessary boot delay |
lvm2-monitor | mask | Unless you use LVM |
bluetooth | disable --now | Unless you use Bluetooth |
geoclue | disable --now | Location services, not needed |
ModemManager | disable --now | No cellular modem |
upower | disable --now | No battery-powered hardware |
disable stops auto-start but allows activation as a dependency. mask blocks any activation. Mask only when certain.
A Wayland compositor with fullscreen bypass (direct scanout) hands the display buffer directly to the GPU when a game goes fullscreen, with no compositing step and no added latency.
Good options: COSMIC, KWin (KDE Plasma), Mutter (GNOME). All support this.
NVIDIA + Wayland requires: nvidia_drm.modeset=1 in boot parameters. Without it, Wayland sessions fall back to software rendering or fail.
Reality check: If you have driver < 550.xx or a compositor without explicit sync, Wayland will be a flickery mess. Use X11.
Gamescope: Skip it unless you need FSR upscaling, HDR tonemapping, or nested sessions. A native compositor with fullscreen bypass is faster.
Don't want to apply everything? These 4 things give 90% of the gain with 10% of the effort.
| # | Change | Command / Config |
|---|---|---|
| 1 | CPU Governor | sudo systemctl enable --now cpupower + /etc/cpupower.conf with governor="performance" |
| 2 | ZRAM → lz4 (if 6-core) | /etc/systemd/zram-generator.conf.d/override.conf → compression-algorithm = lz4 |
| 3 | Dirty Ratio | vm.dirty_background_ratio = 3, vm.dirty_ratio = 8 in sysctl |
| 4 | Disable ananicy-cpp | sudo systemctl disable --now ananicy-cpp |
Do these and you'll solve 80% of the stutter and latency issues. The rest is fine-tuning.
# ── Boot ──
cat /proc/cmdline
# ── CPU ──
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor # → performance
cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference # → performance
# ── Kernel ──
zcat /proc/config.gz | grep CONFIG_PREEMPT # → CONFIG_PREEMPT=y
zcat /proc/config.gz | grep CONFIG_HZ= # → CONFIG_HZ=1000
zcat /proc/config.gz | grep CONFIG_SCHED_CLASS_EXT # → =y
uname -r # "-bore" in the string = BORE kernel, otherwise EEVDF
scxctl get # → currently loaded SCX scheduler, or "none" for EEVDF/BORE
# ── Memory ──
zramctl # check compression, size
sysctl vm.swappiness # → 150
sysctl vm.dirty_background_ratio vm.dirty_ratio # → 3 and 8
# ── Storage ──
cat /sys/block/sdX/queue/scheduler # → [adios] for SSD, [bfq] for HDD
# ── GPU ──
nvidia-smi -q | grep Persistence # → Enabled
nvidia-smi -q -d CLOCK | grep "Max Clocks"
# ── Audio ──
pw-top # QUANT = 128 during playback
# ── Network ──
sysctl net.ipv4.tcp_fastopen # → 3
sysctl net.core.netdev_max_backlog # → 16384
# ── Limits ──
ulimit -n # → 524288
# ── Gamemode (while game is running) ──
gamemoded -s # → "gamemode is active"
# ── Services ──
systemctl is-active ananicy-cpp power-profiles-daemon # → inactive
If your system doesn't boot after changing kernel parameters:
mount /dev/sdXY /mnt (and /boot if separate).arch-chroot /mnt./etc/default/limine.bak or remove the offending parameter, then limine-mkinitcpio.Alternatively, if you used BTRFS snapshots (@pre-optimization), roll back from the bootloader menu or rename subvolumes from the chroot.
All paths absolute from / unless noted. Create these files, apply, reboot.
KERNEL_CMDLINE[default]+="quiet mitigations=off nowatchdog nmi_watchdog=0 nvidia_drm.modeset=1 tsc=reliable clocksource=tsc intel_pstate=active preempt=full split_lock_detect=off pcie_aspm=performance intel_idle.max_cstate=1 transparent_hugepage=madvise splash rw root=UUID=..."
Apply: sudo limine-mkinitcpio && sudo reboot
default_sched = "scx_bpfland"
default_mode = "Gaming"
Apply: sudo systemctl enable --now scx_loader.service
w /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor - - - - performancew /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference - - - - performancevm.swappiness = 180
vm.dirty_background_ratio = 3
vm.dirty_ratio = 8
net.core.somaxconn = 1024
net.core.netdev_max_backlog = 16384
net.ipv4.tcp_fastopen = 3
fs.file-max = 2147483647
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 1024
Apply: sudo sysctl --system
* hard core 0
* soft core 0
* hard nofile 524288
* soft nofile 524288
root hard nofile 524288
root soft nofile 524288@gamemode - nice -10__GL_THREADED_OPTIMIZATION=1
__GL_SHADER_DISK_CACHE=1
__GL_SHADER_DISK_CACHE_SKIP_CLEANUP=1
__GL_VRR_ALLOWED=0
__GL_SYNC_TO_VBLANK=0
__GL_MaxFramesAllowed=1
VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
WINEDEBUG=-all[zram0]
compression-algorithm = lz4
Apply: sudo systemctl restart systemd-zram-setup@zram0
# HDD: BFQ
ACTION=="add|change", KERNEL=="sd[a-z]*", ATTR{queue/rotational}=="1", \
ATTR{queue/scheduler}="bfq"
# SSD: ADIOS
ACTION=="add|change", KERNEL=="sd[a-z]*|mmcblk[0-9]*", ATTR{queue/rotational}=="0",
ATTR{queue/scheduler}="adios"
# NVMe: ADIOS
ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/rotational}=="0",
ATTR{queue/scheduler}="adios"
Apply: sudo udevadm control --reload-rules && sudo udevadm trigger
context.properties = {
default.clock.rate = 48000
default.clock.quantum = 128
default.clock.min-quantum = 128
default.clock.max-quantum = 512
}
Apply: systemctl --user restart pipewire
[general]
renice = 20
ioprio = 0
[gpu]
apply = 1
nv_powermizer_mode = 1
[custom]
start = nvidia-smi -pm 1
end = nvidia-smi -pm 0
Section "Device"
Identifier "NVIDIA"
Driver "nvidia"
Option "ColorSpace" "RGB"
Option "ColorRange" "Full"
EndSectionUUID=<boot> /boot vfat defaults,umask=0077 0 2
UUID=<root> / xfs defaults,lazytime,noatime,inode64,logbsize=256k,noquota 0 1
tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0
UUID=<hdd> /mnt/data xfs defaults,noatime,nofail,allocsize=64m 0 0
UUID=<ssd> /mnt/scratch f2fs defaults,noatime,nofail 0 0hud_compact
hud_no_margin
text_outline
background_alpha=0.3
font_size=14
table_columns=2
fps
frametime
gpu_stats
gpu_temp
gpu_core_clock
gpu_mem_clock
vram
cpu_stats
cpu_temp
cpu_mhz
wine