Motivation

Modern computer systems can be quite power hungry. This is especially true for systems that are always on, like servers. With rising electricity prices, it makes sense to reduce power consumption. This article will show you how to reduce your power consumption in 2 minutes.

Personal note

In my opinion, it makes sense to avoid unnecessary power consumption where possible. Not only for cost reasons, but also for environmental reasons. I’m not a big fan of the “greenwashing” that is going on in the tech industry. But I do think that we should try to reduce our carbon footprint where possible, especially when it’s possible with little effort.

My results

I’m running a Intel NUC 9 Extreme with a Xeon E-2286M CPU 24/7. Through using the following settings, I was able to reduce my power consumption from 34W to 12W during idle. The CPU still boosts to higher frequencies when needed, but it does so less often. In conclusion, I’m able to reduce my power consumption without sacrificing meaningfull performance.

Technical background

For simplicity, I will over-simplify the technical background. The CPU frequency scaling is a feature that is implemented in the CPU. It allows the CPU to run at different frequencies. Running higher frequencies requires higher voltages to run stable, which in turn requires more power even without doing any work. Our goal: the CPU should automatically adjust the frequency based on the current workload. This allows the CPU to run at a lower frequency when possible. This reduces power consumption without affecting performance in a meaningful way.

Fun fact: the CPU frequency scaling is also called “dynamic frequency scaling” or “dynamic voltage scaling”. A few extra percent of performance will require exponentially more power. It can make sense, to run a CPU a few percent under it’s maximum frequency.

Linux

Depending on the CPU, the CPU frequency scaling is implemented differently. For Intel CPUs, the CPU frequency scaling is implemented in the kernel. For AMD CPUs, the CPU frequency scaling is implemented in the CPU itself. This means that the CPU frequency scaling is not available on AMD CPUs when using a Linux kernel that is older than 5.10.

Available governor profiles

Every CPU supports different governor profiles. To list all available governor profiles, run the following command:

root@pve:~# cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
performance powersave

As we can see, my Intel Xeon E-2286M CPU supports two governor profiles: performance and powersave. The performance governor profile will run the CPU at the highest possible frequency. The powersave governor profile will run the CPU at the lowest possible frequency, but will still be able to boost to a higher possible frequency when needed.

setting the governor profile

As usally, NixOS users are benefitting from the declarative nature of NixOS. The CPU frequency scaling is configured in the powerManagement module. The following configuration will set the governor profile to powersave:

{
  powerManagement = {
    cpuFreqGovernor = lib.mkDefault "powersave";
  };
}

Important: you can only use one of the profiles that are listed in /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors. If you try to use a profile that is not listed, the kernel will fall back to the default governor profile.

When using a regular linux system, it’s also easy to set the governor profile. The following command will set the governor profile to powersave:

# set the governor profile to powersave
root@pve:~# echo "powersave" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

There are a lot additional tools to configure the CPU frequency scaling. For example, you can use cpupower. The following command will set the governor profile to powersave using cpupower:

# set the governor profile to powersave
root@pve:~ cpupower -c all frequency-set -g powersave

# verify that the governor profile is set to powersave
root@pve:~ cpupower -c all frequency-info

Making the change permanent is a bit more complicated. You can use systemd to make the change permanent. Using a simple cronjob also does the job. For example:

# creating service file
root@pve:~ nano /etc/systemd/system/cpupower.service
[Unit]
Description=CPU powersave
[Service]
Type=oneshot
ExecStart=/usr/bin/cpupower -c all frequency-set -g powersave
[Install]
WantedBy=multi-user.target
# enabling service
root@pve:~ systemctl daemon-reload
root@pve:~ systemctl enable cpupower.service

In case you don’t want to install cpupower, you can also use crontab -e (as root) to make the change permanent. For example:

# 
# For more information see the manual pages of crontab(5) and cron(8)
# 
# m h  dom mon dow   command

# set the governor profile to powersave during startup
@reboot echo "powersave" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

# set the governor profile to performance during the afternoon
0 16 * * * echo "performance" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
0 20 * * * echo "powersave" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

This might seem a bit hacky and while it certainly is, it works. If you want to use a more elegant solution, you can use systemd as described above.

Since I’m hosting a few gameservers for friends, I’m setting the governor profile to performance during the afternoon. While the performance difference is negligible, it just feels great knowing that my CPU is running at it’s maximum frequency when needed the most. Also, it won’t downclock during the afternoon anyway, since the CPU is under heavy load.