First Published - September 2020
Update - December 2020
Computational performance increases by a factor of at least two per decade at the same Thermal Design Power or TDP - i.e. - processors will usually outperform their ten-year-old equivalents by a factor of at least two at the same TDP. This can also be seen as processors getting power efficient by a factor of at least two per decade at the same performance. Of course, exceptions exist and will continue to exist - for example - there are processors that not only outperform their ten-year-old equivalents by higher factors but also outperform their same-year siblings by higher factors - at the same TDP. This happens because of several reasons including but not limited to design and manufacturing processes which are beyond the scope of this article but one important manufacturing reason is binning. Also note that although TDP isn't a measure of actual power consumption, it is a decent indicator of the same. Please read about CPU Power Dissipation and Performance Per Watt for more information.
Human performance, however, has various limits regardless of where we are in time - for example, our reading and writing speeds do not double per decade even though the amount of our reading and writing might've more than doubled per decade, perhaps since writing and reading were invented. The same goes for our typing speed as it doesn't double per decade even though the amount of our typing might've more than doubled per decade, perhaps since typing was invented. Within the computational context, our usual workloads such as writing, reading and programming are now largely mild workloads and these are only going to get milder as processors get faster. For example, writers and programmers used writing software (also known as text-editors) twenty years ago that ran on twenty-year-old computers without any problems, and writing tools today are largely the same barring a few cosmetic changes along the way. Please see text editors for more information about typical and atypical features and https://en.wikipedia.org/wiki/Comparison_of_text_editors to compare various writing tools.
Modern programmers' writing software are often called integrated development environments or studios and the like, but they're just fancy names for text-editors with a few contextual features added. Of course those integrated development environments or studios have several other features/tools too like debuggers, profilers and compilers or integration of those other features/tools, but they'll only be used every once in a while, and the computer will still idle away for most of the time. The same goes for several other types of computer uses and their corresponding software including but not limited to retail, accounting, clinic, hospital and manufacturing - where the computers are idle for most of the time, and yet again - these are only going to get milder as processors get faster.
So, unless we start buying computers with lowest possible speeds we can get away with, we might end up wasting energy. Besides, it makes sense to buy a faster computer within our budget just for the sake of future proofing which might indirectly benefit us in terms of money saved over time as well as the environment itself in terms of reduced electronic waste. So then, we're stuck with a situation where we have computers with fast processors idling for most of the time, especially when those computers are being used for mild workloads as discussed above 'cause most workloads are mild workloads with spiky or bursty loads once in a while depending on the actual type of use. Even server processors are idling away merrily under low as well as spiky or bursty loads.
Consequently, automated energy saving technologies are built into modern processors as well as modern operating systems, but they are generic in nature and they depend on sampling to make decisions about when and how to save energy. Moreover, the energy required to keep a processor running doesn't scale down beyond a certain point if one has to keep the processor ready to rapidly scale up when required, as the processor has to be kept at a higher voltage state even when idling. Now, this problem exists not because of manufacturing processes but because of limitations of physics and because of the way processors are designed. While we can't beat the limitations of physics we can design asynchronous processors but they're considerably difficult to design and test as compared to synchronous processors, which is why most processors on the market (circa 2020) are still synchronous processors.
Now, depending on specific workloads you might be willing to sacrifice those generic automated energy saving technologies in favor of programming your own, and if that is so, you've come to the right place. Remember you're not going to save millions of bucks worth of energy unless you have millions of computers but whatever you end up saving adds up as there are millions of computer users usually involved in mild workloads, each of whom might have computers with powerful processors where the processing power is there in case it's needed. This article is about saving energy when processing power is NOT needed without actually sacrificing processing power. For example, on a popular processor (less than three years old from 2020) the energy savings might reach about 20 watts per hour which translates to approximately 36 kilowatt-hours (or 36 units) of electricity saved per year if that computer is being used for about 5 hours a day on mild workloads such as reading, writing or programming - your wattage might vary depending on your processor's characteristics and your workload. If you use your computer for say 10 hours a day mostly on such mild workloads then that saving will be around 72 kilowatt-hours (or 72 units) of electricity per year. If a billion people with mild workloads do the same ... well, we'll directly benefit the environment while saving money. On laptops too it may result in additional benefits in the form of an extended battery backup on the same charge and an extended battery life due to less charging cycles being used. Those companies out there don't put money into researching energy saving technologies for no reason. Sounds like fun? Well, follow on.
To follow this article beyond this point you use or know how to use a GNU/Linux based operating system. You also need to know how to fire up a terminal and run basic commands including looking up manual or info pages.
First things first - The Linux kernel is a modern operating system kernel having several energy saving features including but not limited to Energy Aware Scheduling, CPU frequency scaling governors, shutdown, suspend to disk (AKA hibernate) and suspend to RAM; but, for the purpose of this article we are only interested in CPU frequency scaling governors.
You can see the list of governors available in your system by running
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
and the output will usually be
conservative ondemand userspace powersave performance schedutil
You can see a list of governors for all CPUs by running
for (( i=0; i<`nproc`; i++ ))
do
cat /sys/devices/system/cpu/cpu$i/cpufreq/scaling_available_governors
done
All lists will usually be the same unless you use some exotic processor with different per core or per thread characteristics. Remember, a CPU as used in this context actually means a processing unit 'cause the modern CPU is a single device which has one or more chips, where each chip might have one or more processing cores, where each core might have one or more threads and it is these cores or threads that show up as cpu0, cpu1 and so on to cpuN. Also most desktop/laptop/server CPUs (circa 2020) do not have separate per core voltages and currents which means you'll need to set all cores at a low frequency to truly save energy. Where such features are available you will have more opportunities and mechanisms of saving energy.
You can also check the currently active governor on your system by running
for (( i=0; i<`nproc`; i++ ))
do
cat /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor
done
Regardless of what your currently active governor is, you could set your CPU frequency scaling governor (only one can be active at a time) to powersave and save maximum energy as the powersave-governor statically sets the CPU frequency to the lowest allowed value and with it the CPU will run at corresponding voltages and currents thereby saving energy.
To change the governor of all CPUs to powersave run
for (( i=0; i<`nproc`; i++ ))
do
sudo su -c "echo powersave > /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor" root
done
To change the governor of all CPUs to any available governor, you just need to replace powersave in the above command with the governor of your choice.
You can check sensor values like voltage, current and temperature by running
sensors
and you can monitor those values continuously by running
watch -d sensors
as this command will run the command sensors repeatedly with a default delay of two seconds (but you can change the watch command's delay between updates up to a delay of just 0.1 second by running watch -n 0.1 -d sensors for a delay of 0.1 second between updates, or watch -n 3 -d sensors for a delay of 3 seconds between updates) and show any differences in the output from the output from a previous invocation - to quit this program (watch) you have to press Ctrl+C in the terminal window where it's running.
Now, reserve a terminal window for running a watch -d sensors command (I'll refer to this window as the sensors-window from here on) and in a new terminal window you can go ahead and experiment with various governors except the userspace-governor (will talk about it later) and observe the output in the sensors-window. Also go ahead and open up any programs of your liking such as firefox, chrome or libreoffice and do your usual thing; if you're a programmer you can compile a program or a project; or if you want you can play a game and observe the output in the sensors-window. If you end up playing a game, do so within a window rather than a full-screen as our motivation is to observe the sensors-window. Of course, if you have the knowledge of scripting you can pipe the output of sensors to a file or a database, but this article isn't about detailed power consumption statistics and so I will not be discussing such mechanisms here.
The example stated above was for a modern CPU with the CPU frequency scaling governor set to powersave instead of ondemand which is the usual governor on a modern GNU/Linux distribution, where it will result in savings of about 20 watts per hour on mild loads such as writing (writing text or writing code) while the CPU idles away merrily, spare for a few spikes in CPU load every now and then during activated features such as spell check, type ahead, context based type ahead while writing code and the like. And, as already mentioned, 20 watts per hour doesn't sound much, but on larger scales the savings add up. But, using the powersave-governor means your computer runs statically at the lowest possible frequency, which is why we have the ondemand-governor as the default in the first place. However, the ondemand-governor wastes energy as it keeps the CPU at a higher voltage since this governor is ready to rapidly scale the frequency as required.
Other dynamic governors might keep the CPU at a lower energy state, but even they do not solve the problem fully, as they monitor the CPU load which might be spiky or bursty, resulting in dynamic frequency scaling several times (usually per second, but configurable) even though you might be willing to run at lowest speed for some spiky or bursty loads 'cause they don't make much of a difference to you.
Also, using static governors is obviously not what anyone wants since setting the CPU frequency statically to anything above the lowest possible speed will waste energy on mild workloads, while setting it to the lowest frequency will require one to manually switch the frequency repeatedly on an as needed basis.
The only solution is to experiment and measure at various settings and make an informed decision about when you need full speed and when you're comfortable with running at lowest speed and so on. For example, you might realize that you're comfortable with powersave-governor while typing (writing or programming), you want schedutil-governor or conservative-governor when checking email or reading news, and you need performance-governor or ondemand-governor when compiling your programs.
If you want to learn more about those governors you can consult the documentation in the Linux kernel's sources. But to summarize - conservative, ondemand and schedutil are dynamic governors while powersave, performance and userspace are static governors. Here, dynamic governors sample some quantity, usually CPU load, and make a decision to scale the CPU frequency on the basis of the sampled quantity, while the static governors set the frequency to a fixed value and the CPU runs at that frequency regardless of the CPU load. One point to remember is that most modern CPUs have what are usually known as boost modes and static governors can't make use of them.
So ... does that mean one has to manually keep changing the governor (or its equivalent on other systems) to change the CPU frequency as needed? Of course not, besides that is very inconvenient and almost nobody will do that ... it seems most people follow a path of least-inconvenience and this behavior is partly responsible for erosion of privacy ... oops ... this article isn't about privacy ... well, you get the gist. The ultimate solution is automation of changing frequency or governor on the basis of currently running programs. For the above example a governor-switching-automation will sample currently running programs and on detection of an email/news/browser program without a compiler/related program it will switch to the schedutil-governor but if it detects a compiler/related program it will switch to the ondemand-governor and so on. A simple but automated rules-based decision making process. This article only shows a few ways to experiment, measure and analyze without spoon-feeding you. I might write an article about such a governor-switching-automation someday, but I'll give you a hint right now - you can program your own automation by writing a Systemd service (or its equivalent) from the knowledge you obtain here. I'll give you another hint and this one doesn't need any sampling whatsoever - Wrappers. With that in mind, let's move on.
Update - Please note that there are processors (circa Nov 2020) that may have hardware-based logic allowing them to run in lowest power states until a sustained load is detected which makes the application of knowledge from this article kind of moot if the hardware-based-sustained-load-logic works for you - however, this article itself will still be useful. The same goes for any old/future processors including but not limited to processors with wide ranges of per-watt-performance (where this article might actually be much more useful) and asynchronous processors. For a recent example of a processor with a wide range you can check https://arstechnica.com/gadgets/2020/12/new-risc-v-cpu-claims-recordbreaking-performance-per-watt/.
You can check your CPU load by running
uptime
and it will show the load averages for last 1, 5 and 15 minutes.
You can monitor your CPU load by running
top
and it will show plenty of system information including load averages for last 1, 5 and 15 minutes. To quit monitoring you'll have to press q.
The program vmstat shows a ton of information including CPU load information but I won't be talking about vmstat in this article. We will make use of what's available and calculate load average (in percentage) since boot by running
cat /proc/stat | grep 'cpu ' | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage "%"}'
and you can calculate per CPU load average (in percentage) since boot by running
for (( i=0; i<`nproc`; i++ ))
do
cat /proc/stat | grep cpu$i | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage "%"}'
done
but you should take that with a grain of salt because of sampling rate and erratic loads, especially when using writing programs as they'd be idle for most of the time as they process keystrokes and perform spell check, grammar analysis, frequency counts of characters and words and the like - the load being erratic due to our typing speed being much slower than the computer's processing speed. Moreover, the above load average calculation commands don't make use of all information available in /proc/stat (they only use major factors affecting CPU load). To know more about /proc/stat you can consult the documentation in the Linux kernel's sources. Monitoring CPU load averages under different conditions of use might be useful to make informed decisions about the rules for a custom governor-switching-automation.
You can also calculate the average runtime frequency continuously by running
for (( i=1, cf=0; ; i++ ))
do
f=$(cat /proc/cpuinfo | grep -i mhz | cut -f3 | cut -d" " -f2 | awk '{SUM += $1} END {print SUM}')
f=$(echo $f `nproc` | awk '{print $1/$2}')
cf=$(echo $cf $f | awk '{print $1 + $2}')
avg=$(echo $cf $i | awk '{print $1/$2}')
echo $avg
sleep 1
done
which is obviously not useful for static governors as we already know the average runtime frequency since the frequency is static with static governors, but useful for dynamic governors even if this is just a calculation - remember, values such as average frequency (technically a weighted mean) or total power used since last processor reset, etc. directly made available by CPU (or other hardware where power can be saved) in what are called model-specific-registers and/or via machine-instructions would be considerably better than calculations, but as of this writing (circa 2020) I do not know of existence of such hardware based interfaces. To restrict output of the above command to a single line replace the text [echo $avg] with [printf "$avg\r"].
Again, note that within that single second delay there might be frequency spikes and that the values we actually read are just snapshots at the time they're read but that is what we have and for our purpose here that is enough. Of course you can change the delay to any value you want, but keep in mind that a lesser delay will cause the above average runtime frequency calculation to run more frequently thereby increasing its own weight in CPU load and possibly of CPU frequency that we're calculating, while a higher delay might exacerbate the spiky workload problem as the real values are just snapshots of frequencies at the time they're read from /proc/cpuinfo.
Remember I said I'll talk about userspace governor later? Well, that is because the userspace governor directly lets the user to set the frequency to a fixed value from a list of allowed frequencies and the CPU will then run at that fixed frequency regardless of CPU load.
To list available frequencies for the userspace governor run
for (( i=0; i<`nproc`; i++ )); do sudo su -c "echo userspace > /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor" root; done
for (( i=0; i<`nproc`; i++ )); do cat /sys/devices/system/cpu/cpu$i/cpufreq/scaling_available_frequencies; done
where setting the governor to userspace may not be required but we set it first anyway as scaling_available_frequencies are useful only with the userspace governor.
Now to set a particular frequency that you'll have to choose from the list shown by the above command run
for (( i=0; i<`nproc`; i++ )); do sudo su -c "echo userspace > /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor" root; sudo su -c "echo 1000000 > /sys/devices/system/cpu/cpu$i/cpufreq/scaling_setspeed" root; done
where I've used 1000000 KHz (which is 1 GHz) but you'll have to choose from your own list or your command may fail silently or perhaps with an error. Also, remember that scaling_setspeed works only with userspace governor. A command setting this path (scaling_setspeed) even with a valid value on a non-userspace governor will fail, most likely with an error.
You can get some statistical information from /sys/devices/system/cpu/<cpuN>/cpufreq/stats/time_in_state by running
for (( i=0; i<`nproc`; i++ ))
do
echo cpu$i "----------"
cat /sys/devices/system/cpu/cpu$i/cpufreq/stats/time_in_state
done
but modern processors have boost modes (for example your processor might have 1 GHz to 3 GHz in 500 MHz steps but it can boost to 4 GHz ...) so go ahead and experiment by taxing your processor and checking those stats or look up documentation in the Linux kernel for the files available at paths /sys/devices/system/cpu/<cpuN>/cpufreq and /sys/devices/system/cpu/<cpuN>/cpufreq/stats.
Well, that wraps it up for now. Hope you learnt something. Cheers.