Fixing Pm-Utils Userspace Governor for Linux and BSD

09:17 Sun, 05 Feb 2012

Slackware, like other Linuxes and BSDs, uses pm-utils to manage sleep and resume, including managing the cpu frequency governors. The standard scripts restore the governor after the machine has woken from sleep mode, but they don't restore the governor's frequency. Here is how to fix it.

I run Slackware on my laptop, as I've mentioned here before, and about the only issue I have with it instead of the natively installed Vista Home is that it runs a bit hot. From what I can tell (because Vista does not give you a lot of tools to investigate), Vista does two things more aggressively: it slows down the CPU frequency, and it changes the fan speed sooner. However, the benefits of have a unix-y environment more than make up for that so I am happy with running Slackware.

However, that does not mean I can't tweak things a bit, such as setting up a CPU frequency governor and scaling the frequency, which I wrote about previously.

Pm-utils

Slackware uses pm-utils, a suite of scripts from freedesktop.org, to manage suspend and resume. Among other things, pm-utils saves the governor setting on suspend and restores it on resume (suspend means hibernate or sleep, and resume means wake up). Here is the function (in /usr/lib/pm-utils/sleep.d/94cpufreq) that saves the settings:

hibernate_cpufreq()
{
  ( cd /sys/devices/system/cpu/
  for x in cpu[0-9]*; do
    # if cpufreq is a symlink, it is handled by another cpu. Skip.
    [ -L "$x/cpufreq" ] && continue
    gov="$x/cpufreq/scaling_governor"
    # if we do not have a scaling_governor file, skip.
    [ -f "$gov" ] || continue
    # if our temporary governor is not available, skip.
    grep -q "$TEMPORARY_CPUFREQ_GOVERNOR" \
      "$x/cpufreq/scaling_available_governors" || continue
    savestate "${x}_governor" < "$gov"
    echo "$TEMPORARY_CPUFREQ_GOVERNOR" > "$gov"
  done )
}

It is pretty straightforward: for each CPU, check if the governor is a scaling type and save its value if it is. (savestate is a function in another file that saves the current state in /var/run/pm-utils/pm-suspend/storage.)

Here is the corresponding function that restores the settings on wakeup:

thaw_cpufreq()
{
  ( cd /sys/devices/system/cpu/
  for x in cpu[0-9]*/cpufreq/scaling_governor ; do
    [ -f "$x" ] || continue
    state_exists "${x%%/*}_governor" || continue
    restorestate "${x%%/*}_governor" > "$x"
  done )
}

Again, straightforward: if there is a saved value for the CPU's governor, restore it.

So far, so good.

However, astute readers and anyone who read the summary at the beginning will realise that there is a bug for the userspace governor. First, a bit on governors.

Of the five available governors, convervative, performance, powersave, ondemand and userspace, userspace is the only one that does not have a default value(s) associated with it. The other governors come with reasonably sensible defaults, and some of them even allow you to change their values. Userspace comes with no defaults, which makes sense because the whole point of a userspace governor is that it is up to the user to control it.

Bug

Back to pm-utils. You can see from the scripts that nowhere do they save and restore the parameters that the governors control. That means when the machine wakes up it restores whichever governor was in use, but not any of the governor's parameters. For the userspace governor, you are back to a fixed CPU frequency at maximum, which you probably don't want because otherwise why are you using the userspace governor in the first place.

It is kind of annoying to wonder why the fan suddenly is going at full blast. Then you check the CPU's frequency. Oh, it's at max, when I thought I had set it to a middle value. Oh yeah, I closed the lid earlier and put the laptop into sleep mode.

Fix

It is an easy fix. Check if the governor is "userspace" and save the current frequency setting on suspend, and restore it on resume.

All changes to the pm-utils scripts should be done in /etc/pm otherwise they will be lost on any upgrade. Copy /usr/lib/pm-utils/sleep.d/94cpufreq to /etc/pm/sleep.d/. Edit the file to add the lines marked with "-->":

hibernate_cpufreq()
{
  ( cd /sys/devices/system/cpu/
  for x in cpu[0-9]*; do
    # if cpufreq is a symlink, it is handled by another cpu. Skip.
    [ -L "$x/cpufreq" ] && continue
    gov="$x/cpufreq/scaling_governor"
    # if we do not have a scaling_governor file, skip.
    [ -f "$gov" ] || continue
    # if our temporary governor is not available, skip.
    grep -q "$TEMPORARY_CPUFREQ_GOVERNOR" \
      "$x/cpufreq/scaling_available_governors" || continue
    savestate "${x}_governor" < "$gov"
--> # Save userspace governor's frequency
--> [ $(cat "$gov") = "userspace" ] && \
-->     savestate "${x}_frequency" < "$x/cpufreq/scaling_cur_freq"
    echo "$TEMPORARY_CPUFREQ_GOVERNOR" > "$gov"
  done )
}

thaw_cpufreq() { ( cd /sys/devices/system/cpu/ for x in cpu[0-9]*/cpufreq/scaling_governor ; do [ -f "$x" ] || continue state_exists "${x%%/*}_governor" || continue restorestate "${x%%/*}_governor" > "$x" --> # If frequency has been saved, restore it. --> state_exists "${x%%/*}_frequency" || continue --> restorestate "${x%%/*}_frequency" > "${x%%_*}_setspeed" done ) }

More bugs

This still does not save any parameters for other governors. It does not concern me because I mainly use the userspace governor and the others have sensible defaults anyway.

If you want to save parameters for the other governors, the fix is fairly easy. Check in /sys/devices/system/cpu/cpu0/cpufreq (for CPU0; check the other CPUs too) for the parameters that the governor can set. They will be the files with write access. Modify the code to save and restore them.

Freedesktop.org

I have a love-hate relationship with freedesktop.org. I am grateful someone has taken on the thankless task of attempting to make a set of standards for Linux desktops. I really dislike some of their design decisions, and much of the xdg-mime stuff seems unnecessarily convoluted and obtuse. The complete lack of documentation is appalling. Try to fix an invalid mime association that has an incorrect default application and you seem to go round-and-round in circles.

Anyway, I was going to submit the small changes above as a bug fix. Then I noticed that there are minor bugs still outstanding from 2008, four years ago. Perhaps development has stopped completely.

I hope freedesktop.org has a future. Possibly the schism between KDE, Unity desktop and Gnome will resolve, otherwise those of us who use none of those desktops will be caught up in the crossfire of conflicting and different standards, to our detriment.

Categories: unix

Leave a comment

Your email address will not be published. Required fields are marked *

Plain text only please, any < or > are removed.