age scaling (such as Intel’s SpeedStep) allows the clock rate of an idle processor to be reduced. Running more slowly provides greater tolerances for the processor, thus reducing the supply voltage. Reducing the clock speed provides a linear reduction in power usage; the simultaneous reduction of voltage allows the power consumption to be reduced quadratically.

As an orthogonal approach, modern processors implement dynamic power management by allowing the operating system to trigger entry into a range of low-power states when there is nothing to be executed. The most basic of these corresponds to the traditional behavior of the HLT instruction, but deeper sleep states allow the processor package to disable parts of itself. In the deepest states the processor can dissociate itself from the memory bus, disable much of the cache, and reach a state where it consumes a negligible quantity of power.

Moving between these low-power states takes time, with the deeper states taking longer to enter and leave. Since parts of the processor have been disabled, there’s no way for code to be executed. The processor must be raised back to the full-power state before it can handle the next instruction.

As a result, deeper sleep states provide their greatest benefits only when the system will spend a significant period of time ( 20 milliseconds or more) truly idle. Most preemptive multitask-ing operating systems implement scheduling by allocating a time slice to running applications and forcibly switching to another task at the end of this time slice. Traditionally this time slice has been on the order of 10 milliseconds, meaning that an interrupt will be fired 100 times a second to enforce

scheduling. This interrupt is fired even if the system is idle, thus waking up the processor. A traditional fixed-tick operating system is therefore unable to obtain the greatest benefits from modern processor power savings.

A new model of scheduling was introduced in version 2. 6. 21 of the Linux kernel. Rather than having a static timer tick, the kernel looks for a list of tasks waiting to run. If the system is idle, it will look for the next expected timer expiry (such as an application that has requested to sleep for 200 milliseconds) and program the timer interrupt to fire at that point. The system will then sleep until either the next interrupt is fired or some external hardware interrupt occurs.

In the best-case scenario, this dynamic tick model allows the processor to be almost entirely shut down until the next time the user interacts with the computer. The real-world scenario is, unsurprisingly, worse. Many software programs set timers, and when these timers expire the processor must wake up to handle the interrupt.

These timers are often unnecessary. Some are simply polling loops that could be replaced by an interrupt-driv-en design. Others are straightforward design flaws—for example, an email client that checks local mailboxes for changes every 100 milliseconds even though the mail download interval is set to five minutes. Removing these loops can have a surprisingly large impact upon power consumption.

Sometimes, however, an application has no choice but to poll. In this case, it makes sense to consolidate as many loops as possible. Because of the latency required when switching into low-power states, a processor that wakes once a second and spends

four milliseconds executing code will actually draw less power than waking twice a second and spending two milliseconds executing code each time. The GLIB library used by GTK (GIMP toolkit) includes a helper function to make this easier. The g_timeout_add_ seconds() function provides a time-out that will fire after a certain number of seconds, but only with second-level granularity. All time-outs scheduled to fire in a given second will be called at once, avoiding the need to add manual synchronization. Even better, this is synchronized across all GLIB-using applications. Using this in all applications on a system can significantly reduce the number of wake-ups per second, providing a drop in power consumption.

Of course, these issues are not limited to user-space code. Device drivers may have the same issues, and for many of the same reasons. The Linux kernel includes a function similar to GLIB’s, allowing unavoidable polling to be synchronized. In some cases, however, the issues can be subtler. For example, hardware may continue sending events even when no information is present, unless it’s told to stop. If the driver is well written, it will handle the case of empty data packets cleanly; thus, the absence of any support for quiescing the hardware may go unnoticed. Driver authors should disable hardware when it’s not doing anything and avoid polling it if nobody is going to use the information.

The combination of processor-fre-quency scaling and idle-power states provides a somewhat surprising result. On almost all modern hardware, if there is code to run, then it is more power efficient to run the processor at full speed. This “race to idle” concept

How to Reduce Power Consumption

˲ Hardware designers: Make sure that your hardware never requires polling. Send interrupts on all status changes. Provide fine-grained control of logical subunits of the hard ware in order to let the operating system power down as much as possible based on the functional

constraints imposed by the user. ˲ Device driver authors: Make sure that your driver doesn’t poll. If nothing is listening to the driver (for example, if nothing is using a Webcam) then quiesce the hardware. Provide a rich interface to the device, allowing user space to

make it clear which functionality
it requires. Leave the device in the
lowest power state that satisfies
these criteria.
˲ Kernel developers: Remove any
dependency on a fixed clock. If
you know that no tasks are wait-
ing to run, don’t wake up hun-

dreds of times a second to check
the run queue.
˲ Application authors: Don’t
poll. Only run timer loops when
absolutely necessarily and make
sure they’re synchronized. Don’t
keep hardware open if you don’t
need it.

References:

Archives