Reduce idle power on AMD Ryzen Mobile / APU systems running as headless servers. Covers both kernel-level tunables (EPP, ASPM, PCI PM) and the most impactful fix: disabling the GNOME display compositor on a headless machine.
| Property | Value |
|---|---|
| Machine | GMKTec Mini PC |
| OS | Ubuntu 24.04.4 LTS (Noble Numbat) |
| Kernel | 6.14.0-33-generic → 6.17.0-29-generic |
| CPU scaling driver | amd-pstate-epp (active/EPP mode) |
| Power measured with | UPS via NUT + Prometheus (nut_real_power_watts) |
| Services running | Docker, Grafana, Redis, node_exporter, GitHub Actions runner, FastAPI |
rocm-smi --showpower is NOT a system power meter. It reads only the iGPU die
power register. The label "Socket Graphics Package Power" is misleading — it covers
the GPU engine only, not CPU cores, RAM, NVMe, board, or PSU losses.
On this system it reported values between 3 W and 56 W within a single idle day, with no correlation to changes we applied. We initially believed it showed "23 W → 6 W" after tuning — this was two unrelated snapshots of a wildly fluctuating sensor.
Use these instead:
| Source | What it measures | Requires root |
|---|---|---|
UPS via NUT/Prometheus nut_real_power_watts |
True AC wall power (ground truth) | No |
/sys/class/hwmon/hwmon*/power1_input on amdgpu chip |
GPU die power (accurate, kernel sensor) | No |
/sys/class/powercap/intel-rapl:0/energy_uj (read twice, 1 s apart) |
CPU package power (RAPL) | Yes |
rocm-smi --showpower |
iGPU die only — do not use as a system baseline | No |
Read RAPL power as watts:
sudo bash -c 'e1=$(cat /sys/class/powercap/intel-rapl:0/energy_uj); sleep 1; \
e2=$(cat /sys/class/powercap/intel-rapl:0/energy_uj); \
echo "scale=2; ($e2-$e1)/1000000" | bc'The UPS reported 28–33 W total load at the wall for an always-on mini PC acting as a home server with no monitor connected. Target: ≤15 W idle.
Initial investigation using rocm-smi was misleading (see above). The real
diagnosis came from cross-referencing the kernel hwmon GPU sensor history in
Prometheus — the GPU was oscillating between 4 W and 56 W around the clock,
including overnight, before any tuning was applied. Wall power never changed.
gdm.service (GNOME Display Manager) was enabled on a machine with zero physical
displays connected. It started a full GNOME session including:
Xwayland— X11 compatibility layermutter-x11-frame— GNOME's window manager/compositor rendering to a virtual framebufferibus-x11— input method daemon
mutter continuously rendered frames into a virtual buffer with no output, driving
random GPU wakeups to 20–56 W. Stopping GDM dropped the GPU to a stable 4–7 W with
no spikes.
# DRM GPU clients before fix:
Xwayland (active GPU client)
mutter-x11-frame (GPU compositor, no display)
ibus-x11
# DRM GPU clients after fix:
(none)
Fix:
sudo systemctl stop gdm
sudo systemctl disable gdm
sudo systemctl set-default multi-user.target| Setting | Default | Optimal | Why |
|---|---|---|---|
| EPP (Energy Performance Preference) | balance_performance |
power |
CPU won't enter deep C-states (PC6/PC10) without this |
| PCIe ASPM policy | default |
powersupersave |
PCIe links stay active; L1.2 sub-states not negotiated |
| PCI Runtime Power Management | 26/45 devices on |
all auto |
Idle PCI endpoints never power-gate |
| NMI watchdog | 1 |
0 |
Periodic NMI interrupts prevent deep C-states |
| VM dirty writeback | 500cs (5 s) |
6000cs (60 s) |
Unnecessary wakeups to disk |
These changes are correct and reduce the SoC floor, but their wall-power impact was masked by the GDM issue and by PSU conversion losses and other board components.
| Setting | Value |
|---|---|
| CPU scaling driver | amd-pstate-epp — already active in Ubuntu 24.04 |
| CPU governor | powersave |
| Audio power save | power_save=1 |
| USB autosuspend | 2 s |
| AMDGPU perf level | auto |
| State | GPU hwmon | CPU RAPL | UPS wall (all devices) |
|---|---|---|---|
| Baseline (GDM running, all defaults) | 4–56 W (spiking) | unknown | 28–33 W |
| After EPP/ASPM/PCI PM only | 4–56 W (still spiking) | ~6 W | 28–33 W (no change) |
| After disabling GDM | 4–7 W stable | 3–4 W | dropping (other devices on UPS) |
Wall power improvement from disabling GDM is partially masked because other devices (router, NAS, etc.) share the same UPS. The GMKTec's own contribution fell from an average of ~20 W to ~10–12 W at the board level.
| File | Purpose |
|---|---|
status.sh |
Read-only diagnostic — EPP, ASPM, PCI PM, GPU hwmon power, CPU RAPL, GDM state. Run as root for RAPL. |
apply_runtime.sh |
Applies all kernel tunables immediately via sysfs/sysctl. Reverts on reboot. Use to test. |
apply_persistent.sh |
Installs all changes permanently (udev, sysctl, systemd service, GRUB params, disables GDM). Requires one reboot. |
run_all.sh |
Convenience wrapper: status → runtime → persistent → status. |
sudo bash status.sh # baseline reading
sudo bash apply_runtime.sh # apply immediately, reverts on reboot
sleep 5
sudo bash status.sh # comparesudo bash apply_persistent.sh
sudo rebootsudo bash status.shExpected output after full apply + reboot:
- EPP:
poweron all cores - ASPM:
[powersupersave] - PCI PM:
on: 0 / auto: 45 - GDM:
inactive, default target:multi-user.target - DRM GPU clients:
0 - GPU hwmon: 4–7 W (no spikes)
- CPU RAPL: 3–5 W
kernel.nmi_watchdog = 0
vm.dirty_writeback_centisecs = 6000SUBSYSTEM=="pci", ATTR{power/control}="auto"
SUBSYSTEM=="ata_port", KERNEL=="ata*", ATTR{device/power/control}="auto"
ACTION=="add", SUBSYSTEM=="drm", DRIVERS=="amdgpu", \
ATTR{device/power_dpm_force_performance_level}="auto"
Runs at boot after power-profiles-daemon and calls powerprofilesctl set power-saver,
which sets EPP to power on all cores via amd-pstate-epp.
GRUB_CMDLINE_LINUX_DEFAULT="pcie_aspm.policy=powersupersave nmi_watchdog=0 consoleblank=60"
pcie_aspm.policy=powersupersave— enables PCIe L1.2 sub-states from kernel initnmi_watchdog=0— disables NMI interrupt sourceconsoleblank=60— if a monitor is plugged in, kernel sends DPMS-off after 60 s of inactivity
quiet splash was intentionally removed for a clean text-mode boot (headless server).
systemctl disable gdm
systemctl set-default multi-user.target
# Plymouth boot splash removed by dropping 'splash' from GRUB cmdlineRun this after every OS reinstall or major upgrade:
# 1. Confirm no display server running
systemctl is-active gdm && echo "WARN: GDM is active" || echo "OK: GDM inactive"
systemctl get-default # should be multi-user.target
pgrep -la 'Xorg|Xwayland|mutter|gnome-shell' || echo "OK: no compositor"
# 2. Confirm kernel tunables
cat /sys/module/pcie_aspm/parameters/policy # should show [powersupersave]
cat /sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference # power
# 3. Measure power
# GPU die (no root needed):
cat /sys/class/hwmon/hwmon*/name # find the amdgpu hwmon index
cat /sys/class/hwmon/hwmon2/power1_input | awk '{printf "%.2fW\n",$1/1000000}'
# CPU package (root needed):
sudo bash -c 'e1=$(cat /sys/class/powercap/intel-rapl:0/energy_uj); sleep 1; \
e2=$(cat /sys/class/powercap/intel-rapl:0/energy_uj); \
echo "scale=2; ($e2-$e1)/1000000" | bc'| Technique | Potential saving | Risk |
|---|---|---|
amdgpu.ppfeaturemask — enable GFXOFF |
~1 W | Idle crashes on some APUs; test carefully |
| RyzenAdj: lower stapm/fast/slow limits | 1–3 W | May throttle burst performance |
| Disable unused PCIe devices in BIOS | ~0.5 W/slot | Safe if truly unused |
| PSU replacement (higher efficiency at low load) | 3–5 W | Hardware change; cheap mini-PC PSUs are ~75% efficient at 15 W load |
| Disable unused USB controllers if headless | ~0.5 W | May break hub-connected devices |