Slow down, Keep It Cool

In a previous post, I discussed how to set the default power policy with Linux (Ubuntu) by detecting the battery/power status: if you’re plugged-in, set it to on-demand, if you’re running from the battery, set it to powersave. This is rather crude, but proved effective.

But CPUs that support SpeedStep (or similar) usually support a rather long list of possible speed settings. For example, my i7 supports about 15 different speeds, and “powersave” selects the slowest of all, 1.60GHz (on my laptop, that would be 800MHz). Maybe we could leave the policy to on-demand, but cap the maximum speed to something a bit lower than maximum?

There are many reasons to do that. One is that you don’t want to fry your harbls while having your laptop on your lap, another is to limit power consumption or heat dissipation in high-yield CPUs. For example, again, my i7 gets really hot when all cores go full-blast. The fans runs at maximum speed, it’s noisy, and it’s not always wanted.

First, you will need to install the package cpufrequtils:

sudo apt-get install cpufrequtils

This package provides a few utilities to control the speed of the CPU(s). One, cpufreq-info, can be invoked to list supported speeds and modes on all CPUs. Neglecting the fact that you may have heterogeneous CPUs in the same machine (which is possible, I guess), the bash snippet

cpufreq-info -c 0 \
  | grep "cpufreq stats" \
  | cut -d: -f 2- \
  | sed s/,/'\n'/g \
  | cut -d: -f 1 \
  | sed s/\ //g

…will list all available speeds on the (first) CPU. Getting the number of processors (again assuming they’re all exactly the same model), proves easy:

grep processor /proc/cpuinfo | cut -d: -f 2

Now, you can pick one of the available frequencies to set it as the maximum allowable frequency (and not to fix it to exactly that specific frequency, as the cpufreq Gnome applet does) using cpufreq-set:

cpufreq-set -c 0 -max 2.40GHz

You could also set the minimum speed if you wanted, but for now, let us concentrate only on the maximum allowable speed.

OK, this somewhat lacks automation. Let us write a quick scripts that allows you to list the available frequencies and set them:

/usr/bin/env bash

freqs=( $( cpufreq-info -c 0 \
           | grep "cpufreq stats" \
           | cut -d: -f 2- \
           | sed s/,/'\n'/g \
           | cut -d: -f 1 \
           | sed s/\ //g \

cpus=$(grep processor /proc/cpuinfo | cut -d: -f 2)

if [ $# -ge 1 ]
    case $1 in
            echo Supply one of:
            echo ${freqs[@]}
            lower_case_opt=$( echo $1 | tr [:upper:] [:lower:])

            for freq in ${freqs[@]}
                lower_case_freq=$(echo $freq | tr [:upper:] [:lower:])
                #echo $lower_case_opt $lower_case_freq
                if [ "$lower_case_opt" == "$lower_case_freq" ]

            if [ "$found" == 1 ]
                for cpu in ${cpus[@]}
                    cpufreq-set -c $cpu --max $1
                echo "invalid argument" $1

    echo "needs argument. Try -h or --help." >&2
    exit 1

Invoking the script with --help will list available CPU speeds, and invoking the script (with sudo) with a speed will let you cap the speeds to the speed you have specified.

You will either set the s-bit on that script or invoke it via (gk)sudo because cpufreq-set requires root privileges to change the CPUs’ speed. Better yet, is to invoke it via a GUI. Using Zenity, that’s pretty easy:

#!/usr/bin/env bash

values=$(./ -h | tail -n 1)

out=$( zenity \
    --title "Cap CPU Speed" \
    --list \
    --text "Select Maximum Speed:" \
    --column 1 \
    --hide-header \
    ${values[@]} \
    2> /dev/null

if [ $rs == 0 ]
    gksudo -S ./ $out

    if [ $rs == 0 ]
        notify-send \
            --icon=gnome-ccperiph \
            --category=info \
            --urgency=low \
            "CPU Speed" \
            "CPU speed was capped to $out"

You should see something like:

(with minor variations depending on your exact version of Gnome and theme).

Zenity outputs the results on standard output, and sets the fail/success result in the shell return value, accessible using $?. If the dialog succeeds, the script proceeds to ask root password using gksudo and, on success, launches (at last!) the script to cap the CPU speed.

* *

This is a rather simple script that sets all CPUs to a given maximum speed, but one could think using something a bit more sophisticated to set different speeds on each core; especially useful when you have some long-running, CPU-intensive tasks to execute. For example, you can keep cores 0 to 3 on-demand with no speed limit to run the user’s interactive processes and cap cores 4 to 7 to half speed (or even less?) and use taskset to “glue” the long-running processes to the slowed-down cores.

* *

So I guess you’re thinking “what’s the point of not using my CPU to its full capabilities?” Well, as I said earlier, you may not want to fry your knees, because sometimes laptops can get really hot. You may also want to cap the maximum CPU speed to maximize battery life. It doesn’t look like much, but a 4-cores, 8-thread, i7, capped to 1.4GHz (rather than, say, it’s 2.8GHz maximum speed) will give you a quite elongated battery life while not being as sluggish as the “powersave mode” policy—which will set the CPU speed to its minimum… as low as 800MHz on my laptop. You can think of it as a “powersave” mode where you decide how much you save, or don’t.

2 Responses to Slow down, Keep It Cool

  1. qrld says:

    Very usefull script, especially during listening to music at night. There is however one question – how to come back to autosetting the frequency?

    • Steven Pigeon says:

      I suppose you could have it launch another script that runs until it’s morning (depending on how you want to define morning) and cap the speed back to the maximum your computer supports.

      Capping does not affect the governor, only the maximum speed the governor has access to, so there’s no problem setting it to your maximum.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: