Power Management Guide Dennis Nienhüser Power Management is the key to extend battery run time on mobile systems like laptops. This guide assists you setting it up on your laptop. 1.15 August 29, 2004 Introduction
Why Power Management?

Capacity and lifetime of laptop batteries has improved much in the last years. Nevertheless modern processors consume much more energy than older ones and each laptop generation introduces more devices hungry for energy. That's why Power Management is more important than ever. Increasing battery run time doesn't necessarily mean buying another battery. Much can be achieved applying intelligent Power Management policies.

A quick overview

Please notice that this guide describes Power Management for laptops. While some sections might also suite for servers, others do not and may even cause harm. Please do not apply anything from this guide to a server unless you really know what you are doing.

As this guide has become rather long, here's a short overview helping you to find your way through it.

The Prerequisites chapter talks about some requirements that should be met before any of the following device individual sections will work. This includes BIOS settings, kernel configuration and some simplifications in user land. The following three chapters focus on devices that typically consume most energy - processor, display and hard drive. Each can be configured seperately. CPU Power Management shows how to adjust the processor's frequency to save a maximum of energy whithout losing too much performance. A few different tricks prevent your hard drive from working unnecessarily often in Disk Power Management (decreasing noise level as a nice side effect). Some notes on Wireless LAN and USB finish the device section in Power Management for other devices while another chapter is dedicated to the (rather experimental) sleep states. Last not least Troubleshooting lists common pitfalls.

Power Budget for each component

Nearly every component can operate in different states - off, sleep, idle, active to name a few - consuming a different amount of energy. Major parts are consumed by the LCD display, CPU, chipset and hard drives. Often one is able to activate OS-independent Power Management in the BIOS, but an intelligent setup in the operating system adapting to different situations can achieve much more.

Prerequisites
What has to be done first

Before going into the details on making individual devices Power Management aware, make sure certain requirements are met. After controlling the BIOS settings, some kernel options want to be enabled - these are in short ACPI, sleep states and CPU frequency scaling. As power saving most of the time comes along with performance loss or increased latency, it should only be enabled when running on batteries. That's where a new runlevel battery comes in handy.

The BIOS part

First have a look into your BIOS Power Management settings. The best way is to combine BIOS and operating system policies, but for the moment it's better to disable most of the BIOS part. This makes sure it doesn't interfere with your policies. Don't forget to re-check BIOS settings after you configured everything else.

Configuring the kernel

ACPI (Advanced Configuration and Power Interface) support in the kernel is still work in progress. Using a recent kernel will make sure you'll get the most out of it.

In kernel config, activate at least these options:

Power Management Options --->
  [*] Power Management Support
  [ ] Software Suspend
  [ ] Suspend-to-Disk Support

  ACPI( Advanced Configuration and Power Interface ) Support --->
    [*] ACPI Support
    [ ]   Sleep States
    <M>   AC Adapter
    <M>   Battery
    <M>   Button
    <M>   Fan
    <M>   Processor
    <M>     Thermal Zone
    < >   ASUS/Medion Laptop Extras
    < >   Toshiba Laptop Extras
    [ ]   Debug Statements
    
  CPU Frequency Scaling --->
    [*] CPU Frequency scaling
          Default CPUFreq governor (userspace)
    <*>   'performance' governor
    <*>   'powersave' governor
    <*>   CPU frequency table helpers
    <M> ACPI Processor P-States driver
    <*> CPUFreq driver for your processor

Decide yourself whether you want to enable Software Suspend, Suspend-to-Disk and Sleep States (see below). If you own an ASUS, Medion or Toshiba laptop, enable the appropriate section.

Compile your kernel, make sure the right modules get loaded at startup and boot into your new ACPI-enabled kernel. Next run emerge sys-apps/acpid to get the acpi daemon. This one informs you about events like switching from AC to battery or closing the lid. Make sure the module button is loaded if you didn't compile it into the kernel and start acpid with /etc/init.d/acpid start. Run rc-update add acpid default to load it on startup. You'll soon see how to use it.

# emerge sys-apps/acpid
# modprobe button
# /etc/init.d/acpid start
# rc-update add acpid default
Creating a "battery" runlevel

The default policy will be to enable Power Management only when needed - running on batteries. To make the switch between AC and battery convenient, create a runlevel battery that holds all the scripts starting and stopping Power Management.

You can safely skip this section if you don't like the idea of having another runlevel. However, skipping this step will make the rest a bit trickier to set up. The next sections assume a runlevel battery exists.
# cd /etc/runlevels
# cp -a default battery

Finished. Your new runlevel battery contains everything like default, but there is no automatic switch between both yet. Time to change it.

Reacting on ACPI events

Typical ACPI events are closing the lid, changing the power source or pressing the sleep button. Every acpi event recognized by the kernel is catched by acpid which calls /etc/acpi/default.sh. Here is a basic modification supporting runlevel switching:

#!/bin/sh

set $*

group=${1/\/*/}
action=${1/*\//}

# runlevel to use in AC mode
RLVL_AC="default"
# runlevel to use in battery mode
RLVL_BATTERY="battery"

# file indicating the AC state
AC_STATE="/proc/acpi/ac_adapter/AC/state"
# this string means running on AC
AC_ON="on-line"
# this string means running on batteries
AC_OFF="off-line"

function SwitchRunlevel() {
  if [[ "$(grep ${AC_OFF} ${AC_STATE})" != "" && "$(cat /var/lib/init.d/softlevel)" != "${RLVL_BATTERY}" ]]
  then
    logger "Switching to ${RLVL_BATTERY} runlevel"
    /sbin/rc ${RLVL_BATTERY}
  elif [[ "$(grep ${AC_ON} ${AC_STATE})" != "" && "$(cat /var/lib/init.d/softlevel)" != "${RLVL_AC}" ]]
  then
    logger "Switching to ${RLVL_AC} runlevel"
    /sbin/rc ${RLVL_AC}
  fi
}


case "$group" in
  battery)
    case "$action" in
      battery) 
        SwitchRunlevel
        ;;
      *) 
        logger "ACPI group battery / action $action is not defined"
        ;;
    esac
    ;;

  ac_adapter)
    case "$action" in
      ac_adapter)
        SwitchRunlevel
        ;;
      *)
        logger "ACPI group ac_adapter / action $action is not defined"
        ;;
    esac
    ;;
  *)
    logger "ACPI group $group / action $action is not defined"
    ;;
esac

Give it a try: Plug AC in and out and watch syslog for the "Switching to AC mode" or "Switching to battery mode" messages.

Due to the nature of the event mechanism, your laptop will boot into runlevel default regardless of the AC/battery state. You can add another entry to the boot loader with softlevel=boot, but it's likely to forget choosing it. A better way is faking an ACPI event in the end of the boot process and let the /etc/acpi/default.sh script decide whether a runlevel change is necessary. Open /etc/conf.d/local.start in your favourite editor and add these lines:

# Fake acpi event to switch runlevel if running on batteries
/etc/acpi/default.sh "battery/battery"

Prepared like this you can activate Power Management policies for individual devices.

CPU Power Management
Setting the frequency manually

Decreasing CPU speed and voltage has two advantages: On the one hand less energy is consumed, on the other hand there is thermal improvement as your system doesn't get as hot as running on full speed. The main disadvantage is obviously the loss of performance. Decreasing processor speed is a trade off between performance loss and energy saving.

Not every laptop supports frequency scaling. If unsure, have a look at the list of supported processors in the Troubleshooting section to verify your's is supported.

It's time to test whether CPU frequency changing works. To get comfortable with the interface to the kernel, first do some manual speed modifications. To set another CPU speed, use:

(Get current frequency)
# cat /proc/cpuinfo | grep "cpu MHz"

(Lists supported frequencies. This might fail.)
# cd /sys/devices/system/cpu/cpu0/cpufreq/
# cat scaling_available_frequencies

(Change frequency to 1 GHz (1000000 KHz)
Replace with a frequency your laptop supports.)
# echo -n userspace > scaling_governor
# echo -n 1000000 > scaling_setspeed

(Verify frequency was changed)
# cat /proc/cpuinfo | grep "cpu MHz"

If you are getting error messages, please refer to the Troubleshooting chapter in the end of this guide.

You can also write to scaling_max_freq and scaling_min_freq to set boundaries the frequency should stay in between.

Some kernel seem to be buggy about updating /proc/cpuinfo. If you don't see any change there, this doesn't neccessarily mean the CPU frequency wasn't changed. If this happens to you, run emerge x86info, update your kernel as asked and check the current frequency with x86info -mhz.
Automated frequency adaption

The above is quite nice, but not doable in daily life. Better let your system set the appropriate frequency automatically. A couple of user space programs like to do it for you. The following table gives a quick overview to help you decide on one of them.

cpudynAlso supports disk standbycpufreqSophisticated setup possibleComplicated setupspeedfreq Small yet powerful
Useful client/server interface
Kernel 2.6 series onlypowernowdSupports SMP
Name Pro Con

While adjusting the frequency to the current load looks simple on the first view, it's not such a trivial task. A bad algorithm can cause switching between two frequencies all the time or wasting energy when setting frequency to an unnecessary high level.

Which one to choose? If you have no idea about it, first try speedfreq:

# emerge speedfreq
# rc-update add speedfreq battery

speedfreq can be configured by editing /etc/conf.d/speedfreq. For example, if you like users to be able to change the policy, modify SPEEDFREQ_OPTS="" to SPEEDFREQ_OPTS="-u". Having done your changes, start the daemon.

# /etc/init.d/speedfreq start

Setting up cpufreq is a little bit more complicated.

Do not run more than one of the above programs at the same time. It may cause confusion like switching between two frequencies all the time. If you just installed speedfreq, skip cpufreq now.
# emerge cpufreqd
# rc-update add cpufreqd battery

cpufreqd comes with a default configuration in /etc/cpufreqd.conf. Change the config file to fit your needs. The following will save more energy than the default one - at the cost of less performance, of course.

[General]
pidfile=/var/run/cpufreqd.pid
poll_interval=2
pm_type=acpi
# Uncomment the following line to enable ACPI workaround (see cpufreqd.conf(5))
# acpi_workaround=1
verbosity=4 #(if you want a minimal logging set to 5)

# Full performance
[Profile]
name=ac
minfreq=600000
maxfreq=1400000
policy=performance

# Maximum power saving
[Profile]
name=battery
minfreq=600000
maxfreq=900000
policy=powersave

# Constant frequency
[Profile]
name=dvd
minfreq=900000
maxfreq=1100000
policy=powersave

# Full performance when running on AC
[Rule]
name=ac_on
ac=on
profile=ac

# Compiling should be fast if battery state is ok
[Rule]
name=compiling
ac=off
battery_interval=30-100
programs=emerge,make,gcc,cpp
cpu_interval=0-100
profile=ac

# watching DVD's gets sluggish with slow CPU frequency
# Can also be used for games etc.
[Rule]
name=dvd_watching
ac=off
battery_interval=15-100
programs=xine,mplayer,avidemux,kaffeine,kmplayer
cpu_interval=0-100
profile=dvd

# If above doesn't apply, maximise power saving
[Rule]
name=battery_on
ac=off
battery_interval=0-100
cpu_interval=0-100
profile=battery

cpudyn and powernowd are installed in the same way as speedfreq.

The last thing to check is that your new policies do a good job. An easy way to do so is monitoring the CPU speed while working with your laptop:

# watch -n 1 cat /proc/cpuinfo | grep "cpu MHz"

If /proc/cpuinfo doesn't get updated (see above), monitor the CPU frequency with:

# watch -n 1 x86info -mhz

Depending on your setup, CPU speed should increase on heavy load, decrease on no activity or just stay at the same level.

LCD Power Management
Energy consumer no. 1

As you can see in figure 1.1, the LCD display consumes the biggest part of energy (might not be the case for non-mobile CPU's). Thus it's quite important not only to shut the display off when not needed, but also to reduce it's backlight if possible. Most laptops offer the possibility to control the backlight dimming.

First thing to check is the standby/suspend/off timings of the display. As this depends heavily on your windowmanager, I'll let you figure it out yourself. Just two common places: Blanking the terminal can be done with setterm -blank <number-of-minutesM>, setterm -powersave on and setterm -powerdown <number-of-minutesM>. For Xorg, modify /etc/X11/xorg.conf similar to this:

Section "ServerLayout"
  Identifier  [...]
  [...]
  Option  "BlankTime"  "5"  # Blank the screen after 5 minutes (Fake)
  Option  "StandbyTime"  "10"  # Turn off screen after 10 minutes (DPMS)
  Option  "SuspendTime"  "20"  # Full suspend after 20 minutes
  Option  "OffTime"  "30"  # Turn off after half an hour
  [...]
EndSection

[...]

Section "Monitor"
  Identifier  [...]
  Option  "DPMS"  "true"
  [...]
EndSection

This is the same for XFree86 and /etc/X11/XF86Config.

Probably more important is the backlight dimming. If you have access to the dimming settings via a tool, write a small script that dims the backlight in battery mode and place it in your battery runlevel.

Disk Power Management
Sleep when idle

Let's bring the hard disk to sleep as early as possible whenever it is not needed. I'll show you two possibilities to do it. First cpudyn supports Disk Power Management. Uncomment the lines in the "Disk Options" section in /etc/conf.d/cpudyn. To put your first disk to sleep after 60 seconds of no activity, you would modify it like this:

################################################
# DISK OPTIONS
# (disabled by default)
################################################

#
# Timeout to put the disk in standby mode if there was no
# io during that period (in seconds)
#

TIMEOUT=60

#
# Specified disks to spindown (comma separated devices)
#

DISKS=/dev/hda

The second possibility is using a small script and hdparm. Create /etc/init.d/pm.hda like this:

#!/sbin/runscript
start() {
  ebegin "Activating Power Management for Hard Drives"
  hdparm -q -S12 /dev/hda
  eend $?
}

stop () {
  ebegin "Deactivating Power Management for Hard Drives"
  hdparm -q -S253 /dev/hda
  eend $?
}

See man hdparm for the options. If your script is ready, add it to the battery runlevel.

# /sbin/depscan.sh
# rc-update add pm.hda battery
Be careful with sleep/spin down settings of your hard drive. Setting it to small values might wear out your drive and lose warranty.
Increasing idle time - laptop-mode

Recent kernels (2.6.6 and greater, recent 2.4 ones and others with patches) include the so-called laptop-mode. When activated, dirty buffers are written to disk on read calls or after 10 minutes (instead of 30 seconds). This minimizes the time the hard disk needs to be spun up.

To start and stop laptop-mode, create a script /etc/init.d/laptop-mode. You can take the one included in /usr/src/linux/Documentation/laptop-mode.txt. Onces it's ready, make sure it gets called.

# rc-update add laptop-mode battery
Once again: Be careful with sleep/spin down settings of your hard drive. Setting it to small values might wear out your drive and lose warranty. Be sure to read the documentation in laptop-mode.txt. Make sure to stop laptop-mode before your battery runs out of power and data gets written to disk - otherwise you will at least lose the last 10 minutes of your work.
Other tricks

Besides putting your disk to sleep state as early as possible, it is a good idea to minimize disk accesses. Have a look at processes that write to your disk frequently - the syslogd is a good candidate. You probably don't want to shut it down completely, but it's possible to modify the config file so that "unnecessary" things don't get logged and thus don't create disk traffic. Cups writes to disk periodically, so consider shutting it down and only enable it manually when needed.

# rc-update del cupsd battery

Another possibility is to deactivate swap in battery mode. Before writing a swapon/swapoff switcher, make sure there is enough RAM and swap isn't used heavily, otherwise you'll be in big problems.

If you don't want to use laptop-mode, it's still possible to minimize disk access by mounting certain directories as tmpfs - write accesses are not stored on a disk, but in main memory and get lost with unmounting. Often it's useful to mount /tmp like this - you don't have to pay special attention as it gets cleared on every reboot regardless whether it was mounted on disk or in RAM. Just make sure you have enough RAM and no program (like a download client or compress utility) needs extraordinary much space in /tmp. To activate this, enable tmpfs support in your kernel and add a line to /etc/fstab like this:

none  /tmp  tmpfs  size=32m  0 0
Pay attention to the size parameter and modify it for your system. If you're unsure, don't try this at all, it can become a perfomance bottleneck easily. In case you want to mount /var/log like this, make sure to merge the log files to disk before unmounting. They are essential. Don't attempt to mount /var/tmp like this. Portage uses it for compiling...
Power Management for other devices
Wireless Power Management

Wireless LAN cards consume quite a few energy. Put them in Power Management mode in analogy to the pm.hda script.

#!/sbin/runscript
start() {
  ebegin "Activating Power Management for Wireless LAN"
  iwconfig wlan0 power on power max period 3
  eend $?
}

stop () {
  ebegin "Deactivating Power Management for Wireless LAN"
  iwconfig wlan0 power off
  eend $?
}

Starting this script will put wlan0 in Power Management mode, going to sleep at the latest three seconds after no traffic. Save it as /etc/init.d/pm.wlan0 and add it to the battery runlevel like the disk script above. See man iwconfig for details and more options. If your driver and access point support changing the beacon time, this is a good starting point to save even more energy.

USB Power Management

There are two problems with USB devices regarding energy consumption: First, devices like USB mice, digital cameras or USB sticks consume energy while plugged in. You cannot avoid this (nevertheless remove them in case they're not needed). Second, when there are USB devices plugged in, the USB host controller periodically accesses the bus which in turn prevents the CPU from going into C3/4 sleep mode. The OS answer to this problem is the so called "USB selective suspend", which has not yet been implemented in the kernel. USB selective suspend only allows bus accesses in case the device is in use. The cruel workaround until it's implemented is as following: Compile USB support and devices as modules and remove them via a script while they are not in use (e.g. when closing the lid).

Sleep states: sleep, standby, suspend to disk
Overview

ACPI defines different sleep states. The more important ones are

  • S1 aka Standby
  • S3 aka Suspend to RAM aka Sleep
  • S4 aka Suspend to Disk aka Hibernate

They can be called whenever the system is not in use, but a shutdown is not wanted due to the long boot time.

Sleep, Standby & Hibernate

The ACPI support for these sleep states is marked as experimental for good reason. APM sleep states seem to be more stable, however you can't use APM and ACPI together.

Altough sleep state support is improving much, it's still rather experimental. At last I got swsusp2 and suspend to RAM to work, but be warned: This will very likely not work but damage your data/system.

There are currently three implementations for S4. The original one is swsusp, then there is swsusp2 which has the nicest interface (including bootsplash support), but requires manual kernel patching. Last not least we have Suspend-to-Disk, a fork of swsusp.

If this confused you, have a look at a feature comparison. If you still are confused and don't know which one to choose, first give swsusp2 a try, it looks most promising.

The kernel part for this is as following:

Power Management Options --->

  (sleep and standby)
  ACPI( Advanced Configuration and Power Interface ) Support --->
    [*] ACPI Support
       [*]   Sleep States

  (hibernate with swsusp)
  [*] Software Suspend (EXPERIMENTAL)
  
  (hibernate with swsusp2)
  Software Suspend 2
    --- Image Storage (you need at least one writer)
    [*]    Swap Writer
    --- Page Transformers
    [*]    LZF image compression
    (/dev/"your-swap-here")    Default resume device name

  (hibernate with Suspend-to-Disk)
  [*] Suspend-to-Disk Suport
  (/dev/"your-swap-here") Default resume partition

Compile your kernel with the appropriate options enabled and issue cat /proc/acpi/sleep for 2.4 series respectively cat /sys/power/state for 2.6 to find out what is supported. The latter gives me standby mem disk. For swsusp, the kernel parameter resume=/dev/"your-swap-here" has to be appended. If booting is not possible due to a broken image, use noresume for swsusp, pmdisk=off for Suspend-to-Disk and noresume2 for swsusp2.

To put your system in one of the sleep states, use

(kernel 2.4 series)
# echo 1 > /proc/acpi/sleep          (standby)
# echo 3 > /proc/acpi/sleep          (sleep)

(kernel 2.6 series)
# echo -n standby > /sys/power/state standby
# echo -n mem > /sys/power/state     sleep

(swsusp)
# echo 4 > /proc/acpi/sleep          hibernate

(Suspend-to-Disk)
# echo -n disk > /sys/power/state    hibernate

(swsusp2)
# echo > /proc/swsusp/activate
Backup your data before doing this. Run sync before executing one of the commands to have cached data written to disk. First try it outside of X, then with X running, but not logged in.

If you experience kernel panics due to uhci or similar, try to compile USB support as module and unload the modules before sending your laptop to sleep mode.

While the above should be sufficient to get swsusp and Suspend-to-Disk running (I didn't say working), swsusp2 needs special care. The first thing to do is to patch the kernel with the patches provided at http://softwaresuspend.berlios.de/. Afterwards, install the hibernate script from the same page.

Troubleshooting
If things go wrong...

Q: I'm trying to change the CPU frequency, but /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor does not exist.

A: Make sure your processor supports CPU frequency scaling and you chose the right CPUFreq driver for your processor. Here is a list of processors that are supported by cpufreq (kernel 2.6.7): ARM Integrator, ARM-SA1100, ARM-SA1110, AMD Elan - SC400, SC410, AMD mobile K6-2+, AMD mobile K6-3+, AMD mobile Duron, AMD mobile Athlon, AMD Opteron, AMD Athlon 64, Cyrix Media GXm, Intel mobile PIII and Intel mobile PIII-M on certain chipsets, Intel Pentium 4, Intel Xeon, Intel Pentium M (Centrino), National Semiconductors Geode GX, Transmeta Crusoe, VIA Cyrix 3 / C3, UltraSPARC-III, SuperH SH-3, SH-4, several "PowerBook" and "iBook2" and various processors on some ACPI 2.0-compatible systems (only if "ACPI Processor Performance States" are available to the ACPI/BIOS interface).

Q: My laptop supports frequency scaling, but /sys/devices/system/cpu/cpu0/cpufreq/ is empty.

A: Look for ACPI related error messages with dmesg | grep ACPI. Try to update the BIOS, especially if a broken DSDT is reported. You can also try to fix it yourself (which is beyond the scope of this guide).

Q: My laptop supports frequency scaling, but according to /proc/cpuinfo the speed never changes.

A: This seems to be a kernel bug. Run emerge x86info, update your kernel as asked and check the current frequency with x86info -mhz.

Q: I can change the CPU frequency, but the range is not as wide as in another OS.

A: You can combine frequency scaling with ACPI throttling to get a lower minimum frequency. Notice that throttling doesn't save much energy and is mainly used for thermal management (keeping your laptop cool and quiet). You can read the current throttling state with cat /proc/acpi/processor/CPU/throttling and change it with echo -n "0:x" > /proc/acpi/processor/CPU/limit, where x is one of the Tx states listed in /proc/acpi/processor/CPU/throttling.

Q: Battery life time seems to be worse than before.

A: Check your BIOS settings. Maybe you forgot to re-enable some of the settings.

Q: My battery is charged, but KDE reports there would be 0% left and immediately shuts down.

A: Check that battery support is compiled into your kernel. If you use it as a module, make sure the module is loaded.

Q: I have a Dell Inspiron 51XX and I don't get any ACPI events.

A: This seems to be a kernel bug. Read on here.

Q: I just bought a brand new battery, but it only lasts for some minutes! What am I doing wrong?

A: First follow your manufacturer's advice on how to charge the battery correctly.

Q: The above didn't help. What should I do then?

A: Some batteries sold as "new" are in fact old ones. Try the following:

$ grep capacity /proc/acpi/battery/BAT0/info
design capacity:     47520 mWh
last full capacity:  41830 mWh

If the "last full capacity" differs significantly from the design capacity, your battery is probably broken. Try to claim your warranty.