Difference between revisions of "Power management"

From ArchWiki
Jump to navigation Jump to search
m (→‎Hybrid sleep: style: daemon operations)
m (→‎Hybrid sleep: link fix)
(2 intermediate revisions by the same user not shown)
Line 64: Line 64:
 
==== Hybrid sleep ====
 
==== Hybrid sleep ====
  
{{ic|systemctl hybrid-sleep}} both hibernates and suspends at the same time. This combines some of the benefits and drawbacks of suspension and hibernation. This is useful in case a computer were to suddenly lose power (AC disconnection or battery depletion) since upon powerup it will resume from hibernation. If there is no power loss, then it will resume from suspension, which is much faster than resuming from hibernation. However, since "hybrid-sleep" has to dump memory to swap in order for hibernation to work, it is slower to enter sleep than a plain {{ic|systemctl suspend}}.  
+
{{ic|systemctl hybrid-sleep}} both hibernates and suspends at the same time. This combines some of the benefits and drawbacks of suspension and hibernation. This is useful in case a computer were to suddenly lose power (AC disconnection or battery depletion) since upon powerup it will resume from hibernation. If there is no power loss, then it will resume from suspension, which is much faster than resuming from hibernation. However, since "hybrid-sleep" has to dump memory to swap in order for hibernation to work, it is slower to enter sleep than a plain {{ic|systemctl suspend}}. An alternative is a [[#Delayed_hibernation_service_file|delayed hibernation service file]].
 
 
An alternative approach is delayed hibernation. This makes use of sleep hooks to suspend as usual but sets a timer to wake up later to perform hibernation. Here, entering sleep is faster than {{ic|systemctl hybrid-sleep}} since no hibernation is performed initially. However, unlike "hybrid-sleep", at this point there is no protection against power loss via hibernation while in suspension. This caveat makes this approach more suitable for laptops than desktops. Since hibernation is delayed, the laptop battery is only used during suspension and to trigger the eventual hibernation. This uses less power over the long-term than a "hybrid-sleep" which will remain suspended until the battery is drained. Note that if your laptop has a spinning hard disk, when it wakes up from suspend in order to hibernate, you may not want to be moving or carrying the laptop for these few seconds. Delayed hibernation may be desirable both to reduce power use as well as for security reasons (e.g. when using full disk encryption). An example script is located [http://superuser.com/questions/298672/linuxhow-to-hibernate-after-a-period-of-sleep here]. See also [https://bbs.archlinux.org/viewtopic.php?pid=1420279#p1420279 this post] for an updated systemd sleep hook.
 
 
 
A slightly updated version of the service is:
 
{{hc|/etc/systemd/system/suspend-to-hibernate.service|<nowiki>
 
[Unit]
 
Description=Delayed hibernation trigger
 
Documentation=https://bbs.archlinux.org/viewtopic.php?pid=1420279#p1420279
 
Documentation=https://wiki.archlinux.org/index.php/Power_management
 
Before=suspend.target
 
Conflicts=hibernate.target hybrid-suspend.target
 
StopWhenUnneeded=true
 
 
 
[Service]
 
Type=oneshot
 
RemainAfterExit=yes
 
Environment="WAKEALARM=/sys/class/rtc/rtc0/wakealarm"
 
Environment="SLEEPLENGTH=+2hour"
 
ExecStart=-/usr/bin/sh -c 'echo -n "alarm set for "; date +%%s -d$SLEEPLENGTH | tee $WAKEALARM'
 
ExecStop=-/usr/bin/sh -c '\
 
  alarm=$(cat $WAKEALARM); \
 
  now=$(date +%%s); \
 
  if [ -z "$alarm" ] || [ "$now" -ge "$alarm" ]; then \
 
    echo "hibernate triggered"; \
 
    systemctl hibernate; \
 
  else \
 
    echo "normal wakeup"; \
 
  fi; \
 
  echo 0 > $WAKEALARM; \
 
'
 
 
 
[Install]
 
WantedBy=sleep.target
 
</nowiki>
 
}}
 
 
 
The {{ic|Before}} and {{ic|Conflicts}} options ensure it only is run for suspension and not hibernation--otherwise the service will run twice if delayed hibernation is triggered. The {{ic|WantedBy}} and {{ic|StopWhenUnneeded}} options are so it is started before sleep and stops upon resume. (Note that the {{ic|suspend.target}} and {{ic|hibernate.target}} targets do not stop when unneeded, but {{ic|sleep.target}} does). [[systemd#Using units|Enable]] the service.
 
  
 
=== Sleep hooks ===
 
=== Sleep hooks ===
Line 195: Line 158:
 
* {{ic|1=<nowiki>StopWhenUnneeded=yes</nowiki>}}: When active, the service will be stopped if no other active service requires it. In this specific example, it will be stopped after ''sleep.target'' is stopped.
 
* {{ic|1=<nowiki>StopWhenUnneeded=yes</nowiki>}}: When active, the service will be stopped if no other active service requires it. In this specific example, it will be stopped after ''sleep.target'' is stopped.
 
* Because ''sleep.target'' is pulled in by ''suspend.target'', ''hibernate.target'' and ''hybrid-sleep.target'' and ''sleep.target'' itself is a ''StopWhenUnneeded'' service, the hook is guaranteed to start/stop properly for different tasks.
 
* Because ''sleep.target'' is pulled in by ''suspend.target'', ''hibernate.target'' and ''hybrid-sleep.target'' and ''sleep.target'' itself is a ''StopWhenUnneeded'' service, the hook is guaranteed to start/stop properly for different tasks.
 +
 +
==== Delayed hibernation service file ====
 +
 +
An alternative approach is delayed hibernation. This makes use of sleep hooks to suspend as usual but sets a timer to wake up later to perform hibernation. Here, entering sleep is faster than {{ic|systemctl hybrid-sleep}} since no hibernation is performed initially. However, unlike "hybrid-sleep", at this point there is no protection against power loss via hibernation while in suspension. This caveat makes this approach more suitable for laptops than desktops. Since hibernation is delayed, the laptop battery is only used during suspension and to trigger the eventual hibernation. This uses less power over the long-term than a "hybrid-sleep" which will remain suspended until the battery is drained. Note that if your laptop has a spinning hard disk, when it wakes up from suspend in order to hibernate, you may not want to be moving or carrying the laptop for these few seconds. Delayed hibernation may be desirable both to reduce power use as well as for security reasons (e.g. when using full disk encryption). An example script is located [http://superuser.com/questions/298672/linuxhow-to-hibernate-after-a-period-of-sleep here]. See also [https://bbs.archlinux.org/viewtopic.php?pid=1420279#p1420279 this post] for an updated systemd sleep hook.
 +
 +
A slightly updated version of the service is:
 +
{{hc|/etc/systemd/system/suspend-to-hibernate.service|<nowiki>
 +
[Unit]
 +
Description=Delayed hibernation trigger
 +
Documentation=https://bbs.archlinux.org/viewtopic.php?pid=1420279#p1420279
 +
Documentation=https://wiki.archlinux.org/index.php/Power_management
 +
Before=suspend.target
 +
Conflicts=hibernate.target hybrid-suspend.target
 +
StopWhenUnneeded=true
 +
 +
[Service]
 +
Type=oneshot
 +
RemainAfterExit=yes
 +
Environment="WAKEALARM=/sys/class/rtc/rtc0/wakealarm"
 +
Environment="SLEEPLENGTH=+2hour"
 +
ExecStart=-/usr/bin/sh -c 'echo -n "alarm set for "; date +%%s -d$SLEEPLENGTH | tee $WAKEALARM'
 +
ExecStop=-/usr/bin/sh -c '\
 +
  alarm=$(cat $WAKEALARM); \
 +
  now=$(date +%%s); \
 +
  if [ -z "$alarm" ] || [ "$now" -ge "$alarm" ]; then \
 +
    echo "hibernate triggered"; \
 +
    systemctl hibernate; \
 +
  else \
 +
    echo "normal wakeup"; \
 +
  fi; \
 +
  echo 0 > $WAKEALARM; \
 +
'
 +
 +
[Install]
 +
WantedBy=sleep.target
 +
</nowiki>
 +
}}
 +
 +
The {{ic|Before}} and {{ic|Conflicts}} options ensure it only is run for suspension and not hibernation--otherwise the service will run twice if delayed hibernation is triggered. The {{ic|WantedBy}} and {{ic|StopWhenUnneeded}} options are so it is started before sleep and stops upon resume. (Note that the {{ic|suspend.target}} and {{ic|hibernate.target}} targets do not stop when unneeded, but {{ic|sleep.target}} does). [[systemd#Using units|Enable]] the service.
  
 
==== Hooks in /usr/lib/systemd/system-sleep ====
 
==== Hooks in /usr/lib/systemd/system-sleep ====

Revision as of 19:27, 24 July 2014

zh-CN:Power Management

The purpose of this page is to provide general overview of power management in Arch Linux. As Arch Linux uses systemd as system manager, this article focuses on it.

There are multiple places where one can change power management settings:

There are also many power management tools:

Note: Power settings you set in one place/tool could be overwritten in another place/tool.

Power management with systemd

ACPI events

systemd handles some power-related ACPI events. They can be configured via the following options from /etc/systemd/logind.conf:

  • HandlePowerKey: specifies which action is invoked when the power key is pressed.
  • HandleSuspendKey: specifies which action is invoked when the suspend key is pressed.
  • HandleHibernateKey: specifies which action is invoked when the hibernate key is pressed.
  • HandleLidSwitch: specifies which action is invoked when the lid is closed.

The specified action can be one of ignore, poweroff, reboot, halt, suspend, hibernate, hybrid-sleep, lock or kexec.

If these options are not configured, systemd will use its defaults: HandlePowerKey=poweroff, HandleSuspendKey=suspend, HandleHibernateKey=hibernate, and HandleLidSwitch=suspend.

On systems which run no graphical setup or only a simple window manager like i3 or awesome, this may replace the acpid daemon which is usually used to react to these ACPI events.

Note:
  • Restart the systemd-logind daemon for your changes to take effect.
  • systemd cannot handle AC and Battery ACPI events, so if you use Laptop Mode Tools or other similar tools acpid is still required.
  • The HandleLidSwitch option does not trigger an action if an external monitor is connected when the lid is closed.
Warning: With systemd versions 211 and 212 HandleLidSwitch option was broken on systems with NVIDIA binary drivers installed. This was fixed in version 213. See systemd bug tracker and BBS topic.

In the current version of systemd, the Handle* options will apply throughout the system unless they are "inhibited" (temporarily turned off) by a program, such as a power manager inside a desktop environment. If these inhibits are not taken, you can end up with a situation where systemd suspends your system, then when it wakes up the other power manager suspends it again.

Warning: Currently, the power managers in the newest versions of KDE and GNOME are the only ones that issue the necessary "inhibited" commands. Until the others do, you will need to set the Handle options to ignore if you want your ACPI events to be handled by Xfce, acpid or other programs.

Suspend and hibernate

systemd provides commands for suspend to RAM, hibernate and a hybrid suspend using the kernel's native suspend/resume functionality. There are also mechanisms to add hooks to customize pre- and post-suspend actions.

Note: systemd can also use other suspend backends (such as Uswsusp or TuxOnIce), in addition to the default kernel backend, in order to put the computer to sleep or hibernate. See Uswsusp#With systemd for an example.

systemctl suspend should work out of the box, for systemctl hibernate to work on your system you need to follow the instructions at Suspend and Hibernate#Hibernation.

Hybrid sleep

systemctl hybrid-sleep both hibernates and suspends at the same time. This combines some of the benefits and drawbacks of suspension and hibernation. This is useful in case a computer were to suddenly lose power (AC disconnection or battery depletion) since upon powerup it will resume from hibernation. If there is no power loss, then it will resume from suspension, which is much faster than resuming from hibernation. However, since "hybrid-sleep" has to dump memory to swap in order for hibernation to work, it is slower to enter sleep than a plain systemctl suspend. An alternative is a delayed hibernation service file.

Sleep hooks

systemd does not use pm-utils to put the machine to sleep when using systemctl suspend, systemctl hibernate or systemctl hybrid-sleep; pm-utils hooks, including any custom hooks, will not be run. However, systemd provides two similar mechanisms to run custom scripts on these events.

Suspend/resume service files

Service files can be hooked into suspend.target, hibernate.target and sleep.target to execute actions before or after suspend/hibernate. Separate files should be created for user actions and root/system actions. Enable the suspend@user and resume@user services to have them started at boot. Examples:

/etc/systemd/system/suspend@.service
[Unit]
Description=User suspend actions
Before=sleep.target

[Service]
User=%I
Type=forking
Environment=DISPLAY=:0
ExecStartPre= -/usr/bin/pkill -u %u unison ; /usr/local/bin/music.sh stop ; /usr/bin/mysql -e 'slave stop'
ExecStart=/usr/bin/sflock

[Install]
WantedBy=sleep.target
/etc/systemd/system/resume@.service
[Unit]
Description=User resume actions
After=suspend.target

[Service]
User=%I
Type=simple
ExecStartPre=/usr/local/bin/ssh-connect.sh
ExecStart=/usr/bin/mysql -e 'slave start'

[Install]
WantedBy=suspend.target

For root/system actions (enable the root-resume and root-suspend services to have them started at boot):

/etc/systemd/system/root-resume.service
[Unit]
Description=Local system resume actions
After=suspend.target

[Service]
Type=simple
ExecStart=/usr/bin/systemctl restart mnt-media.automount

[Install]
WantedBy=suspend.target
/etc/systemd/system/root-suspend.service
[Unit]
Description=Local system suspend actions
Before=sleep.target

[Service]
Type=simple
ExecStart=-/usr/bin/pkill sshfs

[Install]
WantedBy=sleep.target

A couple of handy hints about these service files (more in man systemd.service):

  • If Type=OneShot then you can use multiple ExecStart= lines. Otherwise only one ExecStart line is allowed. You can add more commands with either ExecStartPre or by separating commands with a semicolon (see the first example above; note the spaces before and after the semicolon, as they are required).
  • A command prefixed with - will cause a non-zero exit status to be ignored and treated as a successful command.
  • The best place to find errors when troubleshooting these service files is of course with journalctl.

Combined Suspend/resume service file

With the combined suspend/resume service file, a single hook does all the work for different phases (sleep/resume) and for different targets (suspend/hibernate/hybrid-sleep).

Example and explanation:

/etc/systemd/system/wicd-sleep.service
[Unit]
Description=Wicd sleep hook
Before=sleep.target
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=-/usr/share/wicd/daemon/suspend.py
ExecStop=-/usr/share/wicd/daemon/autoconnect.py

[Install]
WantedBy=sleep.target
  • RemainAfterExit=yes: After started, the service is considered active until it is explicitly stopped.
  • StopWhenUnneeded=yes: When active, the service will be stopped if no other active service requires it. In this specific example, it will be stopped after sleep.target is stopped.
  • Because sleep.target is pulled in by suspend.target, hibernate.target and hybrid-sleep.target and sleep.target itself is a StopWhenUnneeded service, the hook is guaranteed to start/stop properly for different tasks.

Delayed hibernation service file

An alternative approach is delayed hibernation. This makes use of sleep hooks to suspend as usual but sets a timer to wake up later to perform hibernation. Here, entering sleep is faster than systemctl hybrid-sleep since no hibernation is performed initially. However, unlike "hybrid-sleep", at this point there is no protection against power loss via hibernation while in suspension. This caveat makes this approach more suitable for laptops than desktops. Since hibernation is delayed, the laptop battery is only used during suspension and to trigger the eventual hibernation. This uses less power over the long-term than a "hybrid-sleep" which will remain suspended until the battery is drained. Note that if your laptop has a spinning hard disk, when it wakes up from suspend in order to hibernate, you may not want to be moving or carrying the laptop for these few seconds. Delayed hibernation may be desirable both to reduce power use as well as for security reasons (e.g. when using full disk encryption). An example script is located here. See also this post for an updated systemd sleep hook.

A slightly updated version of the service is:

/etc/systemd/system/suspend-to-hibernate.service
[Unit]
Description=Delayed hibernation trigger
Documentation=https://bbs.archlinux.org/viewtopic.php?pid=1420279#p1420279
Documentation=https://wiki.archlinux.org/index.php/Power_management
Before=suspend.target
Conflicts=hibernate.target hybrid-suspend.target
StopWhenUnneeded=true

[Service]
Type=oneshot
RemainAfterExit=yes
Environment="WAKEALARM=/sys/class/rtc/rtc0/wakealarm"
Environment="SLEEPLENGTH=+2hour"
ExecStart=-/usr/bin/sh -c 'echo -n "alarm set for "; date +%%s -d$SLEEPLENGTH | tee $WAKEALARM'
ExecStop=-/usr/bin/sh -c '\
  alarm=$(cat $WAKEALARM); \
  now=$(date +%%s); \
  if [ -z "$alarm" ] || [ "$now" -ge "$alarm" ]; then \
     echo "hibernate triggered"; \
     systemctl hibernate; \
  else \
     echo "normal wakeup"; \
  fi; \
  echo 0 > $WAKEALARM; \
'

[Install]
WantedBy=sleep.target

The Before and Conflicts options ensure it only is run for suspension and not hibernation--otherwise the service will run twice if delayed hibernation is triggered. The WantedBy and StopWhenUnneeded options are so it is started before sleep and stops upon resume. (Note that the suspend.target and hibernate.target targets do not stop when unneeded, but sleep.target does). Enable the service.

Hooks in /usr/lib/systemd/system-sleep

systemd runs all executables in /usr/lib/systemd/system-sleep/, passing two arguments to each of them:

  • Argument 1: either pre or post, depending on whether the machine is going to sleep or waking up
  • Argument 2: suspend, hibernate or hybrid-sleep, depending on which is being invoked

In contrast to pm-utils, systemd will run these scripts concurrently and not one after another.

The output of any custom script will be logged by systemd-suspend.service, systemd-hibernate.service or systemd-hybrid-sleep.service. You can see its output in systemd's journal:

# journalctl -b -u systemd-suspend
Note: You can also use sleep.target, suspend.target, hibernate.target or hybrid-sleep.target to hook units into the sleep state logic instead of using custom scripts.

An example of a custom sleep script:

/usr/lib/systemd/system-sleep/example.sh
#!/bin/sh
case $1/$2 in
  pre/*)
    echo "Going to $2..."
    ;;
  post/*)
    echo "Waking up from $2..."
    ;;
esac

Do not forget to make your script executable:

# chmod a+x /usr/lib/systemd/system-sleep/example.sh

See man 7 systemd.special and man 8 systemd-sleep for more details.

See Also