Skip to content

About

Reduce AMD Ryzen Mobile idle power from ~23W to ~6W on Linux — runtime & persistent tuning scripts

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

Repository files navigation

Ryzen Mobile Power Optimization (Linux)

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.


System Under Test

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

⚠ Measurement Lessons Learned

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'

Problem

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.


Root Cause Analysis

Finding 1 — The dominant culprit: headless GNOME compositor

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 layer
  • mutter-x11-frame — GNOME's window manager/compositor rendering to a virtual framebuffer
  • ibus-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

Finding 2 — Kernel tunables (valid but secondary impact)

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.

What was already correct out of the box

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

Measured Results

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.


Files in This Repository

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.

Usage

1. Test first (no permanent changes)

sudo bash status.sh        # baseline reading

sudo bash apply_runtime.sh # apply immediately, reverts on reboot

sleep 5
sudo bash status.sh        # compare

2. Make permanent

sudo bash apply_persistent.sh
sudo reboot

3. Verify after reboot

sudo bash status.sh

Expected output after full apply + reboot:

  • EPP: power on 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

What apply_persistent.sh Installs

/etc/sysctl.d/80-ryzen-power.conf

kernel.nmi_watchdog = 0
vm.dirty_writeback_centisecs = 6000

/etc/udev/rules.d/40-ryzen-pci-pm.rules

SUBSYSTEM=="pci", ATTR{power/control}="auto"
SUBSYSTEM=="ata_port", KERNEL=="ata*", ATTR{device/power/control}="auto"

/etc/udev/rules.d/41-amdgpu-power.rules

ACTION=="add", SUBSYSTEM=="drm", DRIVERS=="amdgpu", \
    ATTR{device/power_dpm_force_performance_level}="auto"

/etc/systemd/system/ryzen-epp-power.service

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.

/etc/default/grub (modified)

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 init
  • nmi_watchdog=0 — disables NMI interrupt source
  • consoleblank=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).

GDM and boot splash disabled

systemctl disable gdm
systemctl set-default multi-user.target
# Plymouth boot splash removed by dropping 'splash' from GRUB cmdline

Headless Server Checklist

Run 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'

Further Tuning (not applied here)

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

References

About

Reduce AMD Ryzen Mobile idle power from ~23W to ~6W on Linux — runtime & persistent tuning scripts

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages