DietPi icon indicating copy to clipboard operation
DietPi copied to clipboard

Bug Report: CPU performance config not applied after reboot

Open miloit opened this issue 1 month ago • 7 comments

Creating a bug report/issue

  • [ x] I have searched the existing open and closed issues

Required Information

  • DietPi version |
G_DIETPI_VERSION_SUB=18
G_DIETPI_VERSION_RC=1
G_GITBRANCH='master'
G_GITOWNER='MichaIng'
G_LIVE_PATCH_STATUS[0]='applied'
  • Distro version | trixie
  • Kernel version |
Linux pihole 6.12.57-current-rockchip64 #1 SMP PREEMPT Sun Nov  2 13:15:23 UTC 2025 aarch64 GNU/Linux
  • SBC model |
NanoPi R5S/R5C (aarch64)  

Additional Information (if applicable)

Steps to reproduce

CPU performance settings defined in /boot/dietpi.txt are not applied after reboot. They appear in the config file correctly, but when checking via dietpi-launcher → Config → Performance, the settings revert to defaults (governor, min/max freq, etc.).

# CPU Governor: schedutil | ondemand | interactive | conservative | powersave | performance
CONFIG_CPU_GOVERNOR=conservative
CONFIG_CPU_ONDEMAND_SAMPLE_RATE=25000
CONFIG_CPU_ONDEMAND_SAMPLE_DOWNFACTOR=40
# Throttle Up Percentage: Percentage of average CPU usage during sampling rate at which CPU will be throttled up/down
CONFIG_CPU_USAGE_THROTTLE_UP=85
# CPU Frequency Limits: Disabled=disabled
# - Intel CPUs use a percentage value (%) from 0-100, e.g.: 55
CONFIG_CPU_MAX_FREQ=816
CONFIG_CPU_MIN_FREQ=408
# Disable Intel-based turbo/boost stepping
CONFIG_CPU_DISABLE_TURBO=0

Expected behaviour

Custom CPU performance values from /boot/dietpi.txt should be applied during boot and reflected in dietpi-config.

Actual behaviour

After reboot, default settings are applied and the governor/frequency revert to system defaults.

Extra details

picture picture2

miloit avatar Nov 08 '25 16:11 miloit

Can you check via cpu command whether the governor has been applied correctly after reboot? If not, please check logs:

journalctl -u dietpi-preboot

Something on my ToDo is to better handle cases where a certain governor is implemented as kernel module instead of builtin. The module needs to be loaded explicitly in that case, to appear in the menu list, respectively in /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors. And it needs to be loaded at boot for dietpi-preboot to apply it. I can imagine that this is the issue with the conservative governor in your case.

... although, at least the Rockchip edge kernel has it builtin. Can you check this:

grep CONSERVATIVE /boot/config-*

What generally needs to be done our end:

  • In the dietpi-config menu, before generating the list, loop through all governor_* modules and attempt to load them, if they exist.
  • When a governor is selected, and it was a dedicated module, add it to a /etc/modules-load.d config, otherwise dietpi-preboot won't be able to apply the governor at boot.

MichaIng avatar Nov 08 '25 17:11 MichaIng

cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
ondemand
ondemand
ondemand
ondemand

journalctl -u dietpi-preboot
Nov 08 18:20:21 pihole systemd[1]: Starting dietpi-preboot.service - DietPi-PreBoot...
Nov 08 18:20:22 pihole DietPi-PreBoot[383]: DietPi-CPU_set | CPU governors are not available on this system. This is probably a virtual machine. Aborting...
Nov 08 18:20:22 pihole systemd[1]: Finished dietpi-preboot.service - DietPi-PreBoot.
grep CONSERVATIVE /boot/config-*
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y

miloit avatar Nov 08 '25 17:11 miloit

Weird, this output is genetated if /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors does not exist when the script runs. It does exist now, right?

Is this an R5S or R5C? So I can try to replicate.

Probably the script needs to assured to run after udev or a certain device unit exists.

MichaIng avatar Nov 08 '25 17:11 MichaIng

r5c

this is my work around


cat cpu.sh 
#!/bin/bash

# Wait until CPU sysfs exists
for cpu in 0 1 2 3; do
    retries=0
    while [ ! -d /sys/devices/system/cpu/cpu${cpu}/cpufreq ] && [ $retries -lt 50 ]; do
        sleep 0.1
        ((retries++))
    done

    if [ -d /sys/devices/system/cpu/cpu${cpu}/cpufreq ]; then
        echo conservative > /sys/devices/system/cpu/cpu${cpu}/cpufreq/scaling_governor
        echo 408000 > /sys/devices/system/cpu/cpu${cpu}/cpufreq/scaling_min_freq
        echo 816000 > /sys/devices/system/cpu/cpu${cpu}/cpufreq/scaling_max_freq
    fi
done



cat /etc/systemd/system/cpu-freq.service
[Unit]
Description=Set CPU frequency limits and governor
After=systemd-modules-load.service

[Service]
Type=oneshot
ExecStart=/root/cpu.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target


miloit avatar Nov 08 '25 17:11 miloit

systemd-modules-load.service is already a good start, although it should be part of the default target. I hope I can replicate it and find the exact service or device node that is missing at this boot stage.

MichaIng avatar Nov 08 '25 18:11 MichaIng

If you need sth. please feel free to ask

miloit avatar Nov 09 '25 07:11 miloit

Anything found on your side?

miloit avatar Nov 23 '25 23:11 miloit

Okay, so I can replicate the issue on my R5C, but on R5S it works well 🤔. I wonder whether the udev rules to apply the LED triggers interfere.

In my case, systemd-modules-load.service finishes before dietpi-preboot.service starts, and this is also strictly ordered, since the prior has Before=sysinit.target, and the latter has implicitly After=sysinit.target (DefaultDependencies=no is needed to not imply this).

I'll test with some debug output at which point the CPUFreq sysfs nodes appear.

EDIT: Jep, 1 second too late:

Dec 07 19:10:00 DietPi systemd[1]: Starting cpufreq.service - Test CPUFreq sysfs node appearance...
Dec 07 19:10:01 DietPi systemd[1]: Starting dietpi-preboot.service - DietPi-PreBoot...
Dec 07 19:10:01 DietPi DietPi-PreBoot[372]: DietPi-CPU_set | CPU governors are not available on this system. This is probably a virtual machine. Aborting...
Dec 07 19:10:01 DietPi systemd[1]: Finished dietpi-preboot.service - DietPi-PreBoot.
Dec 07 19:10:02 DietPi systemd[1]: cpufreq.service: Deactivated successfully.
Dec 07 19:10:02 DietPi systemd[1]: Finished cpufreq.service - Test CPUFreq sysfs node appearance.

The problem is, there are zero system logs between those, i.e. no other service or target is reached in between and the kernel did not emit anything either 🤔.

EDIT2: This is handled by udev, which also loads the kernel module, it seems:

Dec 07 19:18:41 DietPi systemd[1]: Starting cpufreq.service - Test CPUFreq sysfs node appearance...
Dec 07 19:18:41 DietPi systemd[1]: Starting dietpi-preboot.service - DietPi-PreBoot...
Dec 07 19:18:42 DietPi systemd[1]: Finished dietpi-preboot.service - DietPi-PreBoot.
Dec 07 19:18:42 DietPi systemd-udevd[261]: scpi-cpufreq: Device is queued (SEQNUM=2888, ACTION=add)
Dec 07 19:18:42 DietPi systemd-udevd[261]: scpi-cpufreq: Device ready for processing (SEQNUM=2888, ACTION=add)
Dec 07 19:18:42 DietPi systemd-udevd[261]: scpi-cpufreq: sd-device-monitor(manager): Passed 187 byte to netlink monitor.
Dec 07 19:18:42 DietPi (udev-worker)[325]: scpi-cpufreq: Processing device (SEQNUM=2888, ACTION=add)
Dec 07 19:18:42 DietPi (udev-worker)[325]: scpi-cpufreq: Device processed (SEQNUM=2888, ACTION=add)
Dec 07 19:18:42 DietPi (udev-worker)[325]: scpi-cpufreq: sd-device-monitor(worker): Passed 187 byte to netlink monitor.
Dec 07 19:18:43 DietPi systemd-udevd[261]: cpufreq-dt: Device is queued (SEQNUM=2987, ACTION=add)
Dec 07 19:18:43 DietPi systemd-udevd[261]: cpufreq-dt: Device ready for processing (SEQNUM=2987, ACTION=add)
Dec 07 19:18:43 DietPi systemd-udevd[261]: cpufreq-dt: sd-device-monitor(manager): Passed 211 byte to netlink monitor.
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: Processing device (SEQNUM=2987, ACTION=add)
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: sd-device: Created database file '/run/udev/data/+platform:cpufreq-dt' for '/devices/platform/cpufreq-dt'.
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: /usr/lib/udev/rules.d/50-udev-default.rules:20 Importing properties from results of builtin command 'hwdb --subsystem=platform'
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: hwdb modalias key: "platform:cpufreq-dt"
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: No entry found from hwdb.
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: /usr/lib/udev/rules.d/50-udev-default.rules:20 Failed to run builtin 'hwdb --subsystem=platform': No data available
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: /usr/lib/udev/rules.d/50-udev-default.rules:29 Importing properties from results of builtin command 'path_id'
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: /usr/lib/udev/rules.d/80-drivers.rules:5 RUN 'kmod load'
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: sd-device: Created database file '/run/udev/data/+platform:cpufreq-dt' for '/devices/platform/cpufreq-dt'.
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: Running built-in command "kmod load"
Dec 07 19:18:43 DietPi (udev-worker)[309]: Loading module: platform:cpufreq-dt
Dec 07 19:18:43 DietPi (udev-worker)[309]: Inserted module 'cpufreq_dt'
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: sd-device: Created database file '/run/udev/data/+platform:cpufreq-dt' for '/devices/platform/cpufreq-dt'.
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: Device processed (SEQNUM=2987, ACTION=add)
Dec 07 19:18:43 DietPi (udev-worker)[309]: cpufreq-dt: sd-device-monitor(worker): Passed 270 byte to netlink monitor.
Dec 07 19:18:43 DietPi systemd[1]: cpufreq.service: Deactivated successfully.
Dec 07 19:18:43 DietPi systemd[1]: Finished cpufreq.service - Test CPUFreq sysfs node appearance.

EDIT3: Nope, our udev rules do not interfere. Without them, the above timing is exactly the same. Really nasty that there is not target or systemd-tracked device unit we could order ourselves after. Even if, cpufreq-dt is a relatively generic/often used CPU scheduling driver, but not the only one. I'll try to give it a systemd device unit and see whether ordering works then.

EDIT4: Nope, sadly After=sys-module-cpufreq_dt.device does not help either. The device node is created with

SUBSYSTEM=="module", KERNEL=="cpufreq_dt", ACTION=="add", TAG+="systemd"

but too early, basically at the start of the schedule for the device, before dietpi-preboot.service runs on its own, and long before the related kernel module is loaded.

The only way I see this can work reliably is to run udevadm settle. But that would delay the service quite a lot. ifupdown-pre.service calls udevadm settle:

Dec 07 20:01:42 DietPi systemd[1]: Starting ifupdown-pre.service - Helper to synchronize boot up for ifupdown...
Dec 07 20:01:42 DietPi systemd[1]: Starting cpufreq.service - Test CPUFreq sysfs node appearance...
Dec 07 20:01:43 DietPi udevadm[301]: Found container virtualization none.
Dec 07 20:01:43 DietPi udevadm[301]: Found cgroup2 on /sys/fs/cgroup/, full unified hierarchy
Dec 07 20:01:43 DietPi systemd[1]: Starting dietpi-preboot.service - DietPi-PreBoot...
Dec 07 20:01:44 DietPi DietPi-PreBoot[375]: DietPi-CPU_set | CPU governors are not available on this system. This is probably a virtual machine. Aborting...
Dec 07 20:01:44 DietPi systemd[1]: Finished dietpi-preboot.service - DietPi-PreBoot.
Dec 07 20:01:45 DietPi systemd[1]: cpufreq.service: Deactivated successfully.
Dec 07 20:01:45 DietPi systemd[1]: Finished cpufreq.service - Test CPUFreq sysfs node appearance.
Dec 07 20:01:47 DietPi systemd[1]: Finished ifupdown-pre.service - Helper to synchronize boot up for ifupdown.

I think this is only reasonable when we split off the /boot/dietpi/func/dietpi-set_cpu call into its own service. I anyway wanted to do this, will see whether I find time for this during beta phase.

MichaIng avatar Dec 07 '25 17:12 MichaIng