Power Management

Peripheral device power management is usually handled by device drivers and the operating system. If a device isn't in use, the driver automatically keeps that device in its lowest power state.

App behaviour drives power consumption. If app code is uses a peripheral device when it doesn't need to, power will be wasted. Power is also wasted if app code runs busy-wait loops or periodically polls for events.

To conserve power, apps should register call-back functions only triggered when events occur. This way app code only runs when an event occurs, rather than waking up to check for events that haven't happened. Every CPU cycle uses power, so when a power-sensitive app is woken up, it should execute as few instructions as possible before going back to sleep.

When all threads are sleeping, the O/S will reduce the CPU power state automatically. When an event handler function returns back to the Legato event loop, it puts the thread to sleep (unless there's another event waiting). If your thread isn't running the Legato event loop, block your thread to put it to sleep when it's not working through poll(), select(), read(), write(), recv(), etc.

If you use a periodic timer (like Timer API) to wake up your app, it will consume power. Set the timer period as long possible to conserve power, and let the O/S go into deeper sleep states.

To maximize power savings, the system can use the Linux auto-sleep feature. Unless the system is busy processing a non-deferrable event, this feature puts the hardware into a SUSPEND state where all peripherals and the CPU are placed into low-power mode. Apps with the appropriate credentials have the option to control the system power state while performing critical operations.

Use Legato's Power Manager to control the system's wake-up (powered) state. Operations needing fast response times or those resulting in high interrupt rates may benefit from keeping the system awake. This provides better performance, but worse power efficiency.

Techniques

Legato uses Linux power management techniques to minimize device power consumption:

  • SUSPEND: system saves its state in memory, places all peripherals in low power mode, and puts the app processor into its deepest idle state.
  • CPUIDLE: system estimates how long the app processor would be idle and puts it into appropriate low power state.
  • CPUFREQ: system estimates how much the app processor is loaded and tunes the CPU frequency and voltage as necessary.

While CPUIDLE and CPUFREQ seamlessly run in the O/S background, Legato apps have significant impact on the efficiency of system SUSPEND functionality.

Wakeup Sources

Legato uses Linux wakeup sources (called wake locks in Android) to control the system power state. If a component with appropriate privileges wants to prevent the system from entering SUSPEND state, it acquires a wakeup source.

If a component with appropriate privileges has no interest in keeping the system powered, it releases a wakeup source. Linux auto-sleep component monitors the use of all system-wide wakeup sources and triggers entry into SUSPEND state when none of the wakeup sources are held.

Wakeup sources can roughly be classified as:

  • Kernel wakeup sources are hard-coded in kernel components and can only be acquired and released by kernel, module and driver code.
  • User-space wakeup sources are created on-demand, acquired and released by privileged app components. User apps write the wakeup source name to file /sys/power/wake_lock to create and acquire wakeup source, and write the same name to file /sys/power/wake_unlock to release the wakeup source.

The Legato Power Manager is the only Legato component with the privilege to write to /sys/power/wake_lock and /sys/power/wake_unlock files. Other components that need control over system power state must have the Linux CAP_BLOCK_SUSPEND capability assigned, and perform the following Legato calls to request service from the Power Manager:

le_pm_NewWakeupSource() create a wakeup source with a particular tag,

le_pm_StayAwake() acquire a wakeup source, and

le_pm_Relax() release a wakeup source.

When the Power Manager receives a request from another component via le_pm_NewWakeupSource(), it'll prefix the requested tag with string legato_ and post-fix it with the requestor’s process ID resulting in the wakeup source name format

legato_<tag>_<process-id>

This name format allows for easy traceability of wakeup sources. The process ID refers to a particular Legato app and the tag refers to a particular wakeup source within that app.

A wakeup source using this name is then created on behalf of the requesting component and a reference to the wakeup source is passed back to the requestor to use it in le_pm_StayAwake() and le_pm_Relax() calls.

Stale wakeup sources are automatically released by the Power Manager when their requestor exits and/or disconnects from the Power Manager.

Wakeup & Deferrable Events

Legato apps run in an event-driven model so the app remains idle until there's an event to be processed. Once an event occurs, Legato detects it and dispatches it to one of its threads for processing.

From a power management aspect, there's no reason for the system to stay powered while it's idle. Also, events may not have the same processing importance, so Legato classifies them like this:

  • Wakeup events: require immediate attention so the system to must be powered.
  • Deferrable events: can wait to be processed until the system is powered for another reason.

These event types are defined in the fdMonitor object. To classify the fdMonitor event as wakeup or deferrable, the app should call le_fdMonitor_SetDeferrable() with the appropriate ‘isDeferrable’ flag. By default, if le_fdMonitor_SetDeferrable() is not called; all events on that object will be assumed to be wakeup events.

The underlying Linux mechanism of waiting for wakeup events from fdMonitor’s file descriptor uses epoll_wait() in conjunction with EPOLLWAKEUP flag. When an epoll_wait() event occurs on a file descriptor that has this flag is set, epoll_wait() will unblock the caller and an eventpoll kernel wakeup source will be signaled. This causes the system to stay awake until one of these conditions are met:

  • another epoll_wait() call is made with the same file descriptor in the event list.

or

  • the file descriptor is closed.

This way, callbacks for this fdMonitor event will be executed while eventpoll wakeup source is held. This guarantees the system stays awake until all callbacks are executed. If a Legato component needs to keep the system powered beyond the scope of a Legato callback, it should acquire its own wakeup source.

This diagram shows a simple Legato app with process ID 25 that needs to keep the system powered between two Legato events using wakeup source tagged lock. Wakeup sources are handed off to achieve this functionality. The system remains powered from the moment the first event occurs until the second event is fully processed.

conceptsPwrMgmt_wakeupSources.png

App components that subscribe to wakeup events must have CAP_BLOCK_SUSPEND Linux capability assigned. If not, all events will be assumed deferrable and calling le_fdMonitor_SetDeferrable() will have no effect.

Power Manager Clients

Using wakeup sources and EPOLLWAKEUP provides a simple programming model to write Power Manager clients. Here are some guidelines:

  • Make sure that CAP_BLOCK_SUSPEND capability is assigned to the client. Client components usually run sandboxed and unless this capability is not explicitly assigned, they will not be able to control system power state.
  • Don't acquire wakeup sources if you just need to process an event callback. In this callback, the system will stay powered due to the eventpoll wakeup source.
  • Acquire a wakeup source if system processing occurs outside a Legato callback. A typical use case is e.g. composing and sending a text message: a Legato callback won't be invoked until the message is submitted and hence the message composition operation may be interrupted by system sleep if unprotected by a wakeup source.
  • Acquire a wakeup source if the system needs to stay awake monitoring a state transition. State transition events may typically be handled in a callback, but if the system needs to stay powered across multiple states, a wakeup source is required.

Troubleshooting

Problem

System doesn't suspend.

Probable cause

A wakeup source is being held

Test

Dump contents of /sys/kernel/debug/wakeup_sources to find the fields that have a non-zero active_since field. Also dump contents of /sys/power/wake_lock to find active user-space wakeup sources.

Command

 cat /sys/kernel/debug/wakeup_sources |sed -e s/"^       "/"unnamed"/ | awk '{print $6 "\t" $1}' | grep -v "^0" |sort -n
 cat /sys/power/wake_lock

Problem

System perpetually suspends and resumes.

Probable cause

Interrupt is constantly triggered.

Test

Dump contents of /proc/interrupts to find the IRQ that's constantly incrementing.

Command

cat /proc/interrupts

Problem

System doesn't resume.

Probable cause

Wakeup interrupts aren't configured.

Test

Dump contents of all

/sys/devices/*/power/wakeup 

files and check which devices have wakeup interrupts enabled.

Command

find /sys/devices --name wakeup --exec cat “{}” “;” -print