From 7e779ca0f7be25482a73e073e83e5107507e5cb5 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Thu, 2 Apr 2026 13:13:38 -0400 Subject: [PATCH] power optimizations --- configuration.nix | 14 +------ modules/power.nix | 93 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 modules/power.nix diff --git a/configuration.nix b/configuration.nix index 13a1582..b96ea97 100644 --- a/configuration.nix +++ b/configuration.nix @@ -20,6 +20,7 @@ ./modules/no-rgb.nix ./modules/security.nix ./modules/ntfy-alerts.nix + ./modules/power.nix ./services/postgresql.nix ./services/jellyfin.nix @@ -91,13 +92,6 @@ services.kmscon.enable = true; - systemd.targets = { - sleep.enable = false; - suspend.enable = false; - hibernate.enable = false; - hybrid-sleep.enable = false; - }; - # Disable serial getty on ttyS0 to prevent dmesg warnings systemd.services."serial-getty@ttyS0".enable = false; @@ -109,12 +103,6 @@ enable = false; }; - powerManagement = { - powertop.enable = true; - enable = true; - cpuFreqGovernor = "powersave"; - }; - # https://github.com/NixOS/nixpkgs/issues/101459#issuecomment-758306434 security.pam.loginLimits = [ { diff --git a/modules/power.nix b/modules/power.nix new file mode 100644 index 0000000..98e6cda --- /dev/null +++ b/modules/power.nix @@ -0,0 +1,93 @@ +{ + lib, + pkgs, + ... +}: +{ + powerManagement = { + enable = true; + powertop.enable = true; + cpuFreqGovernor = "powersave"; + }; + + # Always-on server: disable all sleep targets. + systemd.targets = { + sleep.enable = false; + suspend.enable = false; + hibernate.enable = false; + hybrid-sleep.enable = false; + }; + + boot.kernelParams = [ + # Disable NMI watchdog at boot. Eliminates periodic perf-counter interrupts + # across all cores (~1 W). Safe: apcupsd provides hardware hang detection + # via UPS, and softlockup watchdog remains active. + "nmi_watchdog=0" + + # Route kernel work items to already-busy CPUs rather than waking idle ones. + # Reduces C-state exit frequency at the cost of slightly higher latency on + # work items -- irrelevant for a server whose latency-sensitive paths are + # all in userspace (caddy, jellyfin). + "workqueue.power_efficient=1" + + # Force PCIe ASPM on even if the BIOS doesn't advertise support. ASRock + # B550M Pro4 BIOS defaults are conservative; the Zen 3 root complex and + # all downstream devices (NVMe, AHCI, Intel NIC) support L1 substates. + # powertop auto-tune sets the policy to powersupersave at runtime, but + # without `force` the kernel may refuse to enable ASPM at all if the BIOS + # opted out, making the policy write a no-op. + "pcie_aspm=force" + ]; + + boot.kernel.sysctl = { + # Belt-and-suspenders: also set via boot param, but sysctl ensures it + # stays off if anything re-enables it at runtime. + "kernel.nmi_watchdog" = 0; + }; + + # Server has no audio consumers. Power-gate the HDA codec at module load + # rather than waiting for powertop auto-tune to do it after boot. + boot.extraModprobeConfig = '' + options snd_hda_intel power_save=1 power_save_controller=Y + ''; + + # Apply sysfs power knobs that powertop --auto-tune cannot reach (hardened + # kernel blocks debugfs mount, so powertop silently skips ASPM policy and + # may only lower EPP to balance_power instead of power). + # + # AMD pstate EPP "power": deepest P-states, fastest core parking. Safe because: + # - xmrig runs at Nice=19 / CPUSchedulingPolicy=idle and tolerates latency + # - web services (caddy, jellyfin) are I/O-bound; the ~50 us extra C-state + # exit latency is invisible behind network RTT + # - Minecraft server benefits from single-thread boost, which pstate still + # provides on demand even in "power" mode (just with slightly slower ramp) + # + # ASPM powersupersave: deepest PCIe link power states (L1.1/L1.2). The + # pcie_aspm=force boot param enables ASPM, but the runtime policy defaults + # to "default" which only uses L0s. powersupersave adds L1 substates for + # all downstream devices (NVMe, AHCI, NIC). + systemd.services.power-tune = { + description = "Apply power-saving sysfs knobs (EPP, ASPM policy)"; + after = [ "multi-user.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = lib.getExe ( + pkgs.writeShellApplication { + name = "power-tune"; + text = '' + # AMD pstate energy performance preference + for epp in /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference; do + [ -f "$epp" ] && echo power > "$epp" + done + + # PCIe ASPM policy + aspm=/sys/module/pcie_aspm/parameters/policy + [ -f "$aspm" ] && echo powersupersave > "$aspm" + ''; + } + ); + }; + }; +}