DISTRO: Fedora 41 KDE
GOAL: Im trying to automatically set some cpu parameters (per-CPU max frequency, governors, energy policy, etc.) during my boot process. I wrote a script to do this (it lives at /usr/local/bin/cpu-tune.sh)...I just need this to get run automatically.
WHY: My i9-7940x will happily draw 300 W all day if it has sufficient work to do. These tweaks allow me to selectively slow down the hottest cores so they run cooler. I lose maybe 1% max performance, in in exchange and my hottest CPU core temps drop by 10 C. (and i no longer fail any of the mprime tests)
CUSTOM BOOT SEQUENCE: My system bootup is unlike most Fedora systems. I use Unified Kernel Images (UKIs) to boot directly from the UEFI (no grub/systemd-boot). These images are signed with my personal signing key, since i use secure boot with all keys other than my own removed. The UKI then asks for my password, unlocks a LUKS partition, imports the root ZFS pool from the device-mapper block device (I use ZFS on root) and mounts the various ZFS datasets that make up my root filesystem.
WHAT IVE TRIED: a bunch of stuff.
first I tried a simple systemd service that was more-or-less:
[Unit]
Description=Force CPU tuning udev re-trigger
After=systemd-udevd.service systemd-udev-trigger.service
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/bin/bash /usr/local/bin/cpu-tune.sh
[Install]
WantedBy=multi-user.target
This didnt work, even if I manually started the service with systemctl.
NOTE: running /usr/bin/bash /usr/local/bin/tune-cpu.sh manually works...but it doesnt in the systemd service.
so i tried adding some extra capabilities
User=root
# shared keyring
KeyringMode=shared
# Required privileges
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_SYS_RAWIO CAP_DAC_OVERRIDE
AmbientCapabilities=CAP_SYS_ADMIN CAP_SYS_RAWIO CAP_DAC_OVERRIDE
# Disable systemd protections that block /sys writes
ProtectSystem=no
ProtectKernelTunables=no
ProtectKernelModules=no
ProtectControlGroups=no
and...no change. still doesnt work. so i figured id try udev instead. added a custom rule
ACTION=="add|change", SUBSYSTEM=="cpu", KERNEL=="cpu[0-9]*", RUN+="/usr/bin/bash /usr/local/bin/cpu-tune.sh %k"
and made cpu-tune.sh:
/usr/local/bin/cpu-tune.sh is:
#!/usr/bin/bash
# cpu-tune.sh - invoked by udev with %k (e.g. cpu0)
# Keep this tiny and fast: udev wants short-running helpers.
nn="${1##*[^0-9]}"
# small helper to write safely (retry a few times)
safe_write() {
local file="$1"
local value="$2"
local i=0
while :; do
if [ -w "${file}" ] || [ ! -e "${file}" ] && [ -w "$(dirname "$file")" ]; then
printf '%s' "$value" > "$file" && return 0
fi
i=$((i+1))
if [ $i -ge 5 ]; then
printf '%s: failed writing %s -> %s\n' "$(date -Iseconds)" "$file" "$value" >> /var/log/cpu-tune.log
return 1
fi
sleep 0.05
done
}
case "$nn" in
3|5|17|19)
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/energy_performance_preference" "balance_performance"
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/scaling_governor" "powersave"
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/scaling_max_freq" "3900000"
safe_write "/sys/devices/system/cpu/cpu${nn}/power/energy_perf_bias" "15"
;;
4|8|9|11|18|22|23|25)
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/energy_performance_preference" "balance_performance"
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/scaling_governor" "powersave"
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/scaling_max_freq" "4000000"
safe_write "/sys/devices/system/cpu/cpu${nn}/power/energy_perf_bias" "15"
;;
1|15|13|27)
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/energy_performance_preference" "balance_performance"
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/scaling_governor" "powersave"
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/scaling_max_freq" "4100000"
safe_write "/sys/devices/system/cpu/cpu${nn}/power/energy_perf_bias" "15"
;;
*)
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/energy_performance_preference" "performance"
safe_write "/sys/devices/system/cpu/cpu${nn}/cpufreq/scaling_governor" "performance"
safe_write "/sys/devices/system/cpu/cpu${nn}/power/energy_perf_bias" "0"
;;
esac
# also try enabling hwp dynamic boost once per invocation (harmless if not present)
safe_write "/sys/devices/system/cpu/intel_pstate/hwp_dynamic_boost" "1" || true
This one i can trigger with udevadm trigger --subsystem-match=cpu. But does it trigger on boot? no, of course not. So i figure ill have systemd run the udevadm command for me. i change the systemd service above so that
ExecStart=/bin/udevadm trigger --subsystem-match=cpu
And it works! well, if i manually start the service at least. But does that service run during boot? no, no it doesnt.
so, finally, i recreate my UKI so that the udev rules and the xcpu-tune.sh script are present. And.....still doesnt work.
At this point im sorta out of ideas....anyone know what im doing wrong?