Automatic power saving on a Linux laptop with PowerTOP and systemd

If you have a laptop and want to get more battery life, you may already know about a handy tool from Intel called PowerTOP.

PowerTOP not only monitors your system for interrupts but has a tunable section where you can enable various power saving tweaks. Toggling one such tweak in the PowerTOP interface will show you the specific Linux system command it ran in order to enable or disable it.

PowerTOP Tweaks

Furthermore, it takes an argument ––auto-tune which lets you enable all of the power saving measures it has detected.

The package on Fedora comes with a systemd service, so enabling power saving on boot is simple, just enable the service:
sudo systemctl enable powertop

I noticed, however, that putting some devices into low-power mode on my laptop has unwanted side effects. In my case, the audio system outputs white noise and the USB mouse and keyboard are too slow to wake up (which I find annoying when I want to quickly click on, or type something).

So I took note of the Linux commands that PowerTOP was running for the USB peripherals and the audio device when it disabled power saving. The plan is to use the power of powertop ––auto-tune but I’ll then turn power saving back off for those specific devices.

I created an executable script under /usr/local/sbin/powertop-fixups.sh to disable power saving on those devices:
#!/bin/sh
# Don't do powersave on intel sound, we get static noise
echo '0' > '/sys/module/snd_hda_intel/parameters/power_save'
 
# Don't suspend USB keyboard and mouse
# This takes time to wake up which is annoying
echo 'on' > '/sys/bus/usb/devices/1-2.1.1/power/control'
echo 'on' > '/sys/bus/usb/devices/1-2.2/power/control'

Now, I just needed to tell systemd to start my script on boot, which should require and start after the powertop service.

I created the following service file at /etc/systemd/system/powertop-fixups.service:
[Unit]
Description=PowerTOP fixups
Requires=powertop.service
After=powertop.service
 
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/powertop-fixups.sh
 
[Install]
WantedBy=multi-user.target

Then all I had to do was activate and enable it! Note that I don’t need to enable powertop.service itself, systemd will take care of that for me.

sudo systemctl daemon-reload
sudo systemctl enable powertop-fixups

Now I get the benefit of most of the power savings from PowerTOP, without the settings that were annoying.

11 thoughts on “Automatic power saving on a Linux laptop with PowerTOP and systemd

  1. Why powertop2tuned has to be discarded so quickly? It has proven awesome in my convertible lappy.

  2. I don’t think that powertop2tuned has been discarded, it’s still there but requires that you configure and run tuned service. This is just another way do quickly get benefits of powertop using the build in systemd service, but it doesn’t handle other things like tuned does.

  3. A suggestion for /usr/local/sbin/powertop-fixups.sh

    Rather than hard-code the USB device path (USB devices may often be changed between ports) search the “product” in each USB device for the specific string of the device you wish to enable.

    For example, my Media PC has a FLIRC remote receiver and a cheap Microsoft wireless keyboard receiver:

    echo ‘on’ > $( grep -l ‘flirc’ /sys/bus/usb/devices/*-*/product | sed ‘s/product/power\/control/’ )
    echo ‘on’ > $( grep -l ‘Microsoft’ /sys/bus/usb/devices/*-*/product | sed ‘s/product/power\/control/’ )

    I guess then the type could be changed from oneshot and a timer added to run once daily?
    (For now I’m lazy and just leaving it as oneshot on boot!)

  4. This does not work for me. I am able to start powertop auto tune but the USB mouse keeps going off . I followed all of the above steps. I am on Pop OS 20.04

  5. Yeah, I guess that’s part of the downside of putting everything into low power state. The mouse stops working while the USB is sleeping, but in theory it should wake up again if you click or move your mouse? If not, then you should be able to exclude powertop from putting your USB bus to sleep, which I document in the post. Note though that the USB bus address that I configure is probably different for your device, and you’ll need to work out what port your devices are on. I expect that if you’re following it exactly, that’s why it’s not working.

  6. Of course I used my USB bus address…I have also tried the rc.local way and it too doesn’t seem to work…I guess I’ll have to remove powertop altogether and have to deal with the battery issues.

  7. Hey Hitesh,

    If your mouse disappears when you start powertop that means that powertop is working and if you got the USB address correct, then there might be systemd/rc.local issues or other chips/buses that also need to be on. It’s totally specific to your laptop. As a troubleshooting step, maybe you can try to manually turn the power back on for the USB mouse address and then work your way through other devices? This way you can see if you can get it to work at all, then later configure the system to do it automatically.

    You can do it manually like this:

    # echo 'on' > '/sys/bus/usb/devices/1-2.1.1/power/control'

    You can always apply that to all USB devices and see if you can get it to do what you want at all.

    -c

  8. Hey guys,

    I took some of the ideas above and came up with a way to improve powertop-fixups.sh by using a user-defined list of USB device descriptions to determine which should have power management disabled:

    #!/bin/sh

    # This is a space-separated list of strings which can be found by running (for USB devices): “cat /sys/bus/usb/devices/*-*/product”
    POWERON_USB=(“usb receiver”)

    # For each of the USB devices listed in POWERON_USB,
    # check whether the kernel sees it, and disable
    # power management on it if so.
    for oneDevice in ${POWERON_USB[*]}; do
    if ( grep -liq $oneDevice /sys/bus/usb/devices/*-*/product ); then
    echo ‘on’ > $(grep -li $oneDevice /sys/bus/usb/devices/*-*/product | sed ‘s/product/power\/control/’)
    fi
    done

Leave a Reply

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