Power Management Guide Dennis Nienhüser Power Management is the key to extending battery run time on mobile systems like laptops. This guide helps you setting it up on your laptop. 1.10 26 May 2004 Introduction
Why Power Management?

Capacity and lifetime of laptop batteries have improved much over the years. On the other hand, modern processors consume exponentially more energy than older generations. Expanding displays and integration of more components lets power consumption raise even more. That's why Power Management is more important than ever. Increasing battery run time doesn't necessarily mean getting another battery. Much can be achieved applying intelligent Power Management policies.

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.

Power Budget for each component

Nearly every component can operate in different states - off, sleep, idle, active and sometimes more - 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 in 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. ACPI-patches need to be included, so the plain vanilla-sources (or development-sources in 2.6 terms) are a bad choice here if you don't want to patch manually. gentoo-dev-sources and mm-sources both contain the necessary patches, the same goes for most of the 2.4 series.

In kernel config, activate at least these options (kernel 2.6):

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 haven't compiled it into the kernel and start acpid with /etc/init.d/acpid start. Run rc-update add acpid default to make sure it gets loaded 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
Try it out: 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. One could 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"

So prepared you can activate Power Management policies for individual devices.

CPU Power Management
Setting the frequency manually

Decreasing CPU speed 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.

To get comfortable with the CPU frequency scaling interface to the kernel, first do some manual speed modifications. To set another CPU speed, use

cat /proc/cpuinfo | grep "cpu MHz"
cd /sys/devices/system/cpu/cpu0/cpufreq/
echo -n userspace > scaling_governor
echo -n 1000000 > scaling_setspeed
cat /proc/cpuinfo | grep "cpu MHz"
The first line informs you about the current CPU frequency. Writing "userspace" to scaling_governor tells the kernel to use the userspace governor and a file scaling_setspeed appears you can write the desired new frequency to. Verify with the last command that your change applied. 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 neccessariliy 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. Two daemons will take control over CPU speed: cpufreqd and cpudynd or cpufreqd and speedfreq. cpufreq applies CPU speed policies based on rules and is a handsome tool to put the CPU frequeny between two boundaries. You are able to define own rules and policies mixed with kernel policies. cpudynd and speedfreq dynamically de- or increase CPU speed based on the current system load. With this combination, CPU speed can neither get higher than you want it, nor does it stay on an unnecessary high level. Last not least, sys-apps/powernowd is another possible choice for AMD CPU's.

Which one to choose? speedfreq is for kernel 2.6 only and contains a nice client/server interface that is useful for monitoring its activities and applying policy changes dynamically, while cpudynd can also put your hard drives to sleep when not needed. You can leave out cpufreq if you don't want to limit the "top speed". If you don't know which one to choose (and run a 2.6 kernel), first try speedfreq and nothing else.

Let's get our hands dirty. First get cpufreqd, cpudynd respectively speedfreq.

// if you want cpufreq
emerge cpufreqd
rc-update add cpufreqd battery

// to get speedfreq
emerge speedfreq
rc-update add speedfreq battery

// only if you prefer cpudyn
emerge cpudyn
rc-update add cpudyn battery
Decide which ones you want to use. Running all of them in parallel is a bad idea.

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

For cpudyn, check that /etc/conf.d/cpudyn fits your needs. speedfreq can be configured by editing /etc/conf.d/speedfreq. Having done your changes, start the needed daemons.

/etc/init.d/cpufreqd start
/etc/init.d/cpudyn start
/etc/init.d/speedfreq start

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). That makes it 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

The idea is, as always, to 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 to use 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 -B128 -q -S12 /dev/hda
	eend $?
}

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

# vim:ts=4
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

Andrew Mortons's kernel (or mm-sources in Gentoo) provides an even better playground for Disk Power Management. The laptop_mode patch minimizes the number of times your hard disk has to spin up, saving noticeable more energy. To get this feature, you either need a running mm-sources kernel or patch it by hand. To do the latter, get the patch at kernel.org. It looks like laptop-mode made it's way into the 2.6.6 kernel. In case you neither want to patch your kernel yourself nor want to use mm-sources, but still want to use the laptop-mode, make sure to use a 2.6.6 or later one.

Once your laptop-mode supporting kernel is running, you need a script for starting/stopping laptop mode. Don't forget to add it to your battery runlevel.


mkdir -p /etc/portage
echo "~app-laptop/laptop-mode-20040403 ~x86" >> /etc/portage/package.keywords
emerge laptop-mode
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 lose at least 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.
Not every program can be configured not to write "unnecessary" data. It's still possible to minimize disk access in this case 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 use tmpfs at all. 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 $?
}

# vim:ts=4
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. Try it first 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 another package.
emerge swsusp2
Edit /etc/suspend.conf and try swsusp2 by running hibernate. See the warning above on how to test it for the first time. If all goes well, you can setup sudo to give other users the ability to hibernate, too.

Troubleshooting
If things go wrong...

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'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.

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: 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: 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.