Selective Powertop tunables via Systemd

Selective Powertop tunables via Systemd

November 2, 2017
Linux
Powertop

Originally in the archlinux metal to desktop guide I advised using the powertop --auto-tune via a systemd unit, however this can be obnoxious if you’ve got peripherals (like usb based keyboards or mice) that you don’t want powering off constantly. For this laptop (T470s) I unplugged from the docking station and on battery ran the following:

powertop --calibrate

powertop --html=powerreport.html

awk -F '</?td ?>' '/tune/ { print $4 }' powerreport.html

The --calibrate can take a little while. You will want a profile of the hardware that is connected to the mainboard of this system, not anything connected via the dock or any ports. The results look like this:

echo '1500' > '/proc/sys/vm/dirty_writeback_centisecs';
echo '1' > '/sys/module/snd_hda_intel/parameters/power_save';
echo '0' > '/proc/sys/kernel/nmi_watchdog';
echo 'auto' > '/sys/bus/i2c/devices/i2c-0/device/power/control';
echo 'auto' > '/sys/bus/i2c/devices/i2c-2/device/power/control';
echo 'auto' > '/sys/bus/usb/devices/1-6/power/control';
echo 'auto' > '/sys/bus/usb/devices/2-3/power/control';
echo 'auto' > '/sys/bus/usb/devices/1-5/power/control';
echo 'auto' > '/sys/bus/i2c/devices/i2c-1/device/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:02.0/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:3c:00.0/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:1f.3/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:3a:00.0/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:00.0/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:14.2/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:14.0/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:1f.2/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:1c.0/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:1f.0/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:16.0/power/control';
echo 'auto' > '/sys/bus/pci/devices/0000:00:1f.6/power/control';
ethtool -s enp0s31f6 wol d;

As ethtool isn’t on the system I’m going to ignore that one and proceed with all the other lines. You can apply these via a variety of methods, the ArchWiki suggests module parameters, udev rules and sysctl… however lets look at two systemd based methods. Thanks to boucman for explaining each to me.

Method: systemd.service #

We can write a systemd service unit of type oneshot to set these parameters:

vim /etc/systemd/system/powertop.service

[Unit]
Description=Powertop tunings for T470s

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/sh -c "echo '1500' > '/proc/sys/vm/dirty_writeback_centisecs';"
ExecStart=/usr/bin/sh -c "echo '1' > '/sys/module/snd_hda_intel/parameters/power_save';"
ExecStart=/usr/bin/sh -c "echo '0' > '/proc/sys/kernel/nmi_watchdog';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/i2c/devices/i2c-0/device/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/i2c/devices/i2c-2/device/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/usb/devices/1-6/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/usb/devices/2-3/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/usb/devices/1-5/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/i2c/devices/i2c-1/device/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:02.0/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:3c:00.0/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:1f.3/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:3a:00.0/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:00.0/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:14.2/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:14.0/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:1f.2/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:1c.0/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:1f.0/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:16.0/power/control';"
ExecStart=/usr/bin/sh -c "echo 'auto' > '/sys/bus/pci/devices/0000:00:1f.6/power/control';"

[Install]
WantedBy=multi-user.target

Then enable the service and reboot.

Method: systemd-tmpfiles.d #

We can also use tmpfiles.d which is a slightly more elegant way to do things:

vim /etc/tmpfiles.d/powertop.conf

w /sys/module/snd_hda_intel/parameters/power_save - - - - 1
w /proc/sys/kernel/nmi_watchdog - - - - 0
w /sys/bus/i2c/devices/i2c-0/device/power/control - - - - auto
w /sys/bus/i2c/devices/i2c-2/device/power/control - - - - auto
w /sys/bus/usb/devices/1-6/power/control - - - - auto
w /sys/bus/usb/devices/2-3/power/control - - - - auto
w /sys/bus/usb/devices/1-5/power/control - - - - auto
w /sys/bus/i2c/devices/i2c-1/device/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:02.0/power/control - - - - auto
w /sys/bus/pci/devices/0000:3c:00.0/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:1f.3/power/control - - - - auto
w /sys/bus/pci/devices/0000:3a:00.0/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:00.0/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:14.2/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:14.0/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:1f.2/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:1c.0/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:1f.0/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:16.0/power/control - - - - auto
w /sys/bus/pci/devices/0000:00:1f.6/power/control - - - - auto

Reboot and the settings will be applied.

Many will scoff at both these methods and tell you that it is more advisable to pass udev parameters. I prefer these until I can find a reason to use udev instead.