Files
Nomarchy/modules/nixos/oom.nix
Bernardo Magri 2055842c33
All checks were successful
Check / eval (push) Successful in 4m1s
feat(memory): enable zram compressed-RAM swap by default (#76 slice)
First slice of BACKLOG #76 (hibernation + zram, split): zramSwap on by
default in modules/nixos/oom.nix — the memory-pressure layer before
earlyoom. zstd @ 50% RAM (nixpkgs defaults, explicit for reproducibility),
priority 100 so day-to-day paging fills zram first and any disk swapfile
stays reserved for #76's hibernate image (hibernation can't resume from
volatile zram). Follows the earlyoom mkDefault precedent — no toggle.

Adds checks.zram-swap runNixOSTest importing oom.nix, asserting the device
is an active swap, uses [zstd], and carries priority 100.

Verified: V2 checks.zram-swap PASS (/dev/zram0 in /proc/swaps, zstd,
prio 100); V1 full distro toplevel builds; V0 flake check --no-build green.
#76 remainder (disk swapfile default + resume + installer) still open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 16:07:55 +01:00

62 lines
2.7 KiB
Nix

# Memory-pressure protection: keep the desktop alive when RAM runs out.
#
# A workstation that compiles from source WILL exhaust memory eventually —
# a big `nix build`, a runaway eval, a browser tab. The kernel's own OOM
# killer acts only after the system has thrashed itself unresponsive
# (often minutes of frozen desktop) and then picks by badness score,
# which can land on the compositor.
#
# earlyoom over systemd-oomd — a deliberate choice: oomd kills whole
# cgroups, and a Hyprland session runs as ONE scope (nothing spawns
# per-app systemd scopes here, unlike GNOME), so under pressure oomd
# would take out the entire desktop to save it. earlyoom kills a single
# process (highest oom_score ≈ the hog) BEFORE the thrash point — "kill
# the build step, keep the session". nixpkgs default-enables oomd in an
# inert state (no slices monitored); it's disabled outright below so
# there is exactly one owner of the OOM story.
#
# zram sits one layer earlier: a compressed RAM swap that absorbs
# day-to-day memory pressure (a browser's idle tabs, a big eval's cold
# pages) before it ever reaches the earlyoom threshold — more headroom
# on the same RAM, no disk. High swap priority so the kernel fills zram
# first; any real disk swapfile stays reserved for the hibernate image
# (BACKLOG #76's other half — hibernation can't resume from volatile
# zram, so day-to-day paging must not consume the disk swap). zstd @ 50%
# RAM are the nixpkgs defaults, kept explicit for reproducibility.
{ lib, ... }:
{
zramSwap = {
enable = lib.mkDefault true;
algorithm = lib.mkDefault "zstd";
memoryPercent = lib.mkDefault 50;
# Beats any disk swapfile's auto-assigned (negative) priority, so
# day-to-day paging lands in zram and the disk swap is left for
# hibernation. See the header note and BACKLOG #76.
priority = lib.mkDefault 100;
};
services.earlyoom = {
enable = lib.mkDefault true;
# Desktop toast when something is killed (relayed via
# systembus-notify), so a vanished build/tab is explained rather
# than mysterious.
enableNotifications = lib.mkDefault true;
# Never pick the session plumbing: losing the compositor or the lock
# screen IS the outage this module exists to prevent (and killing a
# Wayland session-lock client trips its go-to-a-tty failsafe). No
# --prefer tuning: highest-memory selection already targets the hog.
# Matched unanchored — NixOS wrappers rename comm to ".foo-wrapped".
extraArgs = lib.mkDefault [
"--avoid"
"(Hyprland|hyprlock|greetd|waybar|pipewire|wireplumber|Xwayland|nix-daemon|systemd)"
];
};
# One owner (see header): oomd ships default-on but inert; make the
# earlyoom choice explicit and total.
systemd.oomd.enable = lib.mkDefault false;
}