8.9 KiB
Battery Optimizations
This guide goes over the various optimizations for laptops that you can configure to improve your battery life.
Important
You will need to follow this guide even if you're using my dotfiles, as it requires enabling certain services which I don't enable automatically from the installation scripts.
This is because not all devices need power management services running (desktop devices don't have a battery).
UPower
UPower is a DBus service that provides power management support to applications, which can request data about the current power state through this DBus interface.
Additionally, UPower can perform a certain action when your battery life reaches a critical point, like entering hibarnation when below 2%.
pacman -S upower
systemctl start --now upower
You can adjust UPower configuration in /etc/UPower/UPower.conf
, I quite like
the defaults settings here. The relevant settings to look at are:
PercentageLow=20.0
PercentageCritical=5.0
PercentageAction=2.0
CriticalPowerAction=HybridSleep
Acpid
Acpid is a daemon that can deliver ACPI power management events. When an event occurs, it executes a program to handle that event. These events are:
- Pressing special keys, including the Power/Sleep/Suspend button, but also things like wlan/airplane mode toggle button, volume buttons, brightness, ...
- Closing a notebook lid
- (Un)Plugging an AC power adapter from a notebook
- (Un)Plugging phone jack etc.
By default, these events would otherwise go unhandled, which isn't ideal.
pacman -S acpid
systemctl enable --now acpid
Tip
By default
acpid
already has some basic handling of these ACPI events, so you shouldn't need to change anything, however, if you would want to run something custom on one of these events, you can configure it to do so in/etc/acpi/handler.sh
Systemd suspend-then-hibernate
I like to use systemctl suspend-then-hibernate
command when entering a
suspend state (usually configured from an idle daemon, such as hypridle or
swayidle). This command allows my system to remain suspended for some amount of
time, after which it will enter hibernation. This is really nice, because if I
forget that I had my laptop suspended and leave it like that while unplugged
for a long amount of time, this will prevent the battery from being drained for
no reason.
To configure automatic hibernation with this command, we'll want to modify
/etc/systemd/sleep.conf
, and add:
HibernateDelaySec=10800
That will configure automatic hibernation after 3 hours of being in a suspend state.
Power Profiles Daemon
Many people like using something complex like TLP to manage power, however, in
many cases, you can achieve good results with something much simpler:
power-profiles-daemon
.
Simply put, power-profiles-daemon
is a CPU throttle, allowing you to switch
between various "power profiles" (power-saver, balanced, performance). I like
using a custom shell-script that checks the current battery percentage and
status (charging/discharging) and dynamically set the power profile based on
these values.
Note
Power Profiles Daemon only performs a subset of what TLP would do. Which of these tools you wish to use depends on your workfload and preferences:
- If the laptop frequently runs under medium or high load, such as during video playback or compiling, using
power-saver
profile withpower-profiles-daemon
can provide similar energy savings as TLP.- However, TLP offers advantages over
power-profiles-daemon
when the laptop is idle, such as during periods of no user input or low load operations like text editing or browsing.In my personal opinion,
power-profiles-daemon
is quite sufficient and I don't have a great need for TLP. Also TLP is actually quite limiting in it's configuration in comparison to being able to use something like a shell script and switch profiles depending on both the charging state & the current percentage or any other custom rules whereas TLP only exposes some simple configuration options, that will enable performance/balanced mode when on AC power and power-safe when on battery power, but you can't really mess with anything more dynamic.
Tip
If you think you'd prefer TLP over
power-profiles-daemon
, feel free to skip this section, the section below will cover TLP as an alternative to this.
Tip
It may be worth it to look into
system76-power
as an alternative topower-profiles-daemon
.
To set up power-profiles-daemon, we'll first install it and enable it as a systemd service:
pacman -S power-profiles-daemon
systemctl enable --now power-profiles-daemon
Setting power profile manually
To try things out, you can set the power profile manually, using
powerprofilesctl
command:
powerprofilesctl set power-saver
powerprofilesctl set balanced
powerprofilesctl set performance # won't work on all machines
However, having to set your power profile manually each time wouldn't be very convenient, so I'm only showing this as an example / something you can try out initially to see what results it can give you.
Setting power profiles automatically
To make power-profiles-daemon
actually useful and seamless, I like using a
shell script that monitors the battery state and switches the power mode
depending on certain conditions. I like placing my system-wide scripts into
/usr/local/bin
, so let's use: /usr/local/bin/power-profiles-monitor
:
#!/usr/bin/env bash
set -euo pipefail
if [ "$EUID" -ne 0 ]; then
echo "You must run this script as root"
exit 1
fi
BAT=$(echo /sys/class/power_supply/BAT*) # only supports single-battery systems
BAT_STATUS="$BAT/status"
BAT_CAP="$BAT/capacity"
OVERRIDE_FLAG="/tmp/power-monitor-override"
POWER_SAVE_PERCENT=50 # Enter power-save mode if on bat and below this capacity
HAS_PERFORMANCE="$(powerprofilesctl list | grep "performance" || true)" # the || true ignores grep failing with non-zero code
# monitor loop
prev=0
while true; do
# check if override is set
if [ -f "$OVERRIDE_FLAG" ]; then
echo "Override flag set, waiting for release"
inotifywait -qq "$OVERRIDE_FLAG"
continue
fi
# read the current state
status="$(cat "$BAT_STATUS")"
capacity="$(cat "$BAT_CAP")"
if [[ $status == "Discharging" ]]; then
if [[ $capacity -le $POWER_SAVE_PERCENT ]]; then
profile="power-saver"
else
profile="balanced"
fi
else
if [[ -n $HAS_PERFORMANCE ]]; then
profile="performance"
else
profile="balanced"
fi
fi
# Set the new profile
if [[ "$profile" != "$prev" ]]; then
echo -en "Setting power profile to ${profile}\n"
powerprofilesctl set $profile
prev=$profile
fi
# wait for changes in status or capacity files
# i.e. for the next power change event
inotifywait -qq "$BAT_STATUS" "$BAT_CAP"
done
Note
You will need
inotify-tools
package installed for theinotifywait
command to work.
As you can see, it's a pretty simple script, that will run forever, but spend most time just waiting for the battery status to change, re-running once it does.
We could now run this script manually, but that's not a great solution,
instead, we can create a custom systemd service which will run it for us
automatically. To do this, we'll create a new file:
/etc/systemd/system/power-profiles-monitor.service
with the following
content:
[Unit]
Description=Monitor the battery status, switching power profiles accordingly
Wants=power-profiles-daemon.service
[Service]
ExecStart=/usr/local/bin/power-profiles-monitor
Restart=on-failure
Type=simple
[Install]
WantedBy=default.target
With that, we can now enable our service:
systemctl daemon-reload # make systemd aware of the new service
systemctl enable --now power-profiles-monitor
Tip
You may have noticed that the script
TLP
Important
TLP is an alternative solution to handle power management, it cannot be used in combination with
power-profiles-daemon
.
TODO: This section is work-in-progress, as I'm not using TLP right now.
If you wish to set up TLP, I'd suggest that you check out the official TLP
documentation, alongside with a
guide on achieving a similar profile switching behavior as
power-profiles-daemon
offers with it:
here. Additionally, there is an Arch
Linux Wiki page for TLP.