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.