Understanding Power Management In Ubuntu

Overview

There are several situations where power management plays its important role:

The power management within Ubuntu involves many components/packages, and the exact implementation depends on the GUI system used, e.g. power management in Gnome and KDE have different implementations. This article will focus on Gnome only.

Below is a big picture of those components/packages involved, ignoring the relationship between each of these components:

images/power-management-related-components.png

Components involved in power management.

This article tries to explain how these components work together for power management. And please note this only depicts the current situation as of this writing (i.e. Ubuntu 12.04), as you can see from above, things could actually be improved and simplified, and there are many changes on-going, e.g. some function has been moved from gnome-session to systemd, and some is being moved from gnome-settings-daemon to upower.

Idle

Idle here is assumed to be a state where there is no explicit user activities. Note this is different from CPU idle when there is no more work for the CPU to perform. When idle state persists for a while, it's reasonably to assume that the user might have moved his focus to somewhere else, and that something can be done to the system to reduce the power consumption a bit, e.g. dim the backlight of the LCD screen or the keyboard, harddrive spinoff, and so on. However, there are cases where these actions are not desired when being idle, e.g. when someone is reading or browsing for a while but leaving mouse and keyboard untouched, in these cases, it is not pleasant to dim the brightness of the LCD screen at least. There is a mechanism in gnome session manager called Inhibitor, which maintains a mask of whether it's OK to go into states of idle, suspend, user switch or logout (see [4]).

Idle Detection

In a Linux desktop system, the X server is where all events are processed including those user activity related, and thus knows exactly if the system is in a idle state or not. This information is kept in a X server internal counter called IDLETIME. Whenever it is detected that there is no explicit user activity, e.g. no mouse movement and no keyboard clicks, the counter will be incremented, and if any user activity is detected, the counter will be reset. (for more information on how IDLETIME counter works and other problems, please refer to [2]). This counter can be retreived by clients through XSync API([1]).

Idle detection is done in gnome-session within it's Presense Manager, where the idea is to provide a central resource for applications to query when interested in user's presence status in the current desktop session (see [3]). The code to track the IDLETIME counter is in the source file:

gnome-session/gnome-session/gs-idle-monitor.c

Idle detection is also done independently in gnome-settings-daemon power manager plugin (note this could be due to the problems mentioned in [2]). The IDLETIME counter is being tracked by gnome-settings-daemon in its power manager plugin:

gnome-settings-daemon/plugins/power/gsd-power-manager.c

Generally, to make use the IDLETIME counter to detect the idle state, there are several steps:

  1. the first step is to iterate all counters and find it by name:

    counters = XSyncListSystemCounters (monitor->priv->display, &ncounters);
    for (i = 0; i < ncounters; i++) {
            if (counters[i].name != NULL
                && strcmp (counters[i].name, "IDLETIME") == 0) {
                    monitor->priv->counter = counters[i].counter;
                    break;
            }
    }
    
  2. and to create an alarm with a wait interval, so an event will be triggered once the is idle state persists for a specified time:

    flags = XSyncCACounter
            | XSyncCAValueType
            | XSyncCATestType
            | XSyncCAValue
            | XSyncCADelta
            | XSyncCAEvents;
    
    XSyncIntToValue (&delta, 0);
    attr.trigger.counter = idle_counter;
    attr.trigger.value_type = XSyncAbsolute;
    attr.trigger.wait_value = interval;
    attr.delta = delta;
    attr.events = TRUE;
    
    xalarm = XSyncCreateAlarm(display, flags, &attr);
    
  3. add a event filter and handle the XSyncAlarmNotify event:

    xevent_filter(XEvent *xev, ...)
    {
            if (xev->xany.type != XSyncAlarmNotify)
                    return GDK_FILTER_CONTINUE;
    
            return handle_alarm_notify_event(monitor, xev);
    }
    
    ...
    
    gdk_window_add_filter(xevnet_filter, monitor);
    

One of the important parameter here is the wait interval before an alarm event is emitted, this parameter basically decides when the system thinks it's in a steady idle state. This interval in gnome-session is kept in the GSettings schemas/key below:

schema key
org.gnome.desktop.session idle-delay

The wait time in gnome-settings-daemon power plugin will be described in detail later.

This key is configured in the "Screen and Lock" panel of system settings:

images/brightness-and-lock-screen-off-time-highlighted.png

Wait interval for idle state

Note this "Turn off screen when inactive for" parameter also changes the values of two other GSettings keys below:

schema key
org.gnome.settings-daemon.plugins.power sleep-display-ac
sleep-display-battery

These two keys are used by gnome-settings-daemon power plugin, which are used for turning off the screen instead (they will be described in detail later).

gnome-screensaver

gnome-screensaver will be auto started along with the session, and monitors the presence status change maintained by gnome-session. Whenever the presence status changes to idle, the screensaver will be activated. The activation has two steps:

  • first, it fades the screen out
  • then 10 seconds later (hardcoded) activates the screen saver (go blank by default) and starts the lock timer

The lock screen will be enabled after the lock timer expired, i.e. whenever there are any requests to bring back the screen, i.e. user activities, or to show some messages, the lock screen will be shown. The lock screen is actually implemented in a separate program called gnome-screensaver-dialog. gnome-screensaver will talk to gnome-screensaver-dialog to know if it has been unlocked, or the failed to unlock, or timed out.

The interval for this lock timer is being kept in the GSettings key below:

schema key
org.gnome.desktop.screensaver lock-delay

and can be configured by the "Screen and Lock" panel of the gnome-control-center as below:

images/brightness-and-lock-lock-screen-after-highlighted.png

Time to wait before locking screen

"Screen turns off" means to enable the lock screen immediately (i.e. lock-delay = 0).

For other detailed information about gnome-screen, please refer to https://live.gnome.org/GnomeScreensaver/ [5].

gnome-settings-daemon power plugin

The power manager plugin within gnome-settings-daemon monitors the IDLETIME counter of the X server by itself, using the same technique as described in previous section "Idle Detection". Related code can be referenced by:

gnome-settings-daemon/plugin/power/gpm-idletime.c

There are two signals related to this counter:

  • alarm-expired - this signal is emitted after a given period of time while idle persists
  • reset - this signal is emitted if IDLETIME counter reset is detected, i.e. the X window detects there is user activities

The wait interval for alarm-expired signal is specified by the GSettings key below:

schema key
org.gnome.settings-daemon.plugins.power idle-dim-time

This key defaults to 30 seconds, and there is currently no UI where this can be changed unless by gsettings command line or dconf tool.

In gsd-power-manager.c, there are four different idle states defined:

  • GSD_POWER_IDLE_MODE_NORMAL - this is defined to be the normal running mode when there are constant user activities, screen backlight and keyboard backlight are at a normal level

GSD_POWER_IDLE_MODE_DIM

This is defined to be the mode when there is no user activities for a certain period of time. The value for this time is specified in a key named 'idle-time-dim' as described previously. In this mode, the system will try to bring down the backlight brightness of the LCD and keyboard to save some power but still keep the system responsive enough, i.e. to bring the system out of this mode involves only restoration of the brightness.

GSD_POWER_IDLE_MODE_BLANK

This is defined to be the mode when idle keeps a bit longer in GSD_POWER_IDLE_MODE_DIM, and the period for this additional idle time is specified in GSettings keys 'sleep-display-battery' and 'sleep-display-ac' as below, depending on whether the system is on a battery or on an AC supply:

schema key
org.gnome.settings-daemon.plugins.power sleep-display-ac
sleep-display-battery

These two parameters are adjustable in the "Screen and Lock" panel of gnome-control-center, and they are sharing this same adjustment with the 'idle-delay' key in gnome-screensaver.

With this mode, the screen will be turned off by using DPMS extension.

GSD_POWER_IDLE_MODE_SUSPEND

This is defined to be the mode when idle persists for quite a long time in GSD_POWER_IDLE_MODE_DIM, and the period for this additional idle time is specified in GSettings keys 'sleep-inactive-battery' and 'sleep-inactive-ac', depending on whether the system is on a battery or on an AC supply:

schema key
org.gnome.settings-daemon.plugins.power sleep-inactive-ac
sleep-inactive-battery

The values for these two keys can be configured in the "Power" panel of gnome-control-center as below:

images/power-panel-sleep-inactive.png

Configure time to suspend when inactive

With this mode, the system will try to suspend to keep power consumption to minimum.

Transition between idle modes

images/idle-states-in-ubuntu-gnome-settings-daemon.png

Diagram of transition between idle modes.

Idle timeline

images/idle-timeline-gnome-power-plugin-and-screensaver.png

Idle timeline of gnome-settings-daemon power plugin and screensaver