In our research on Power Aware Computing, we have studied work from several different authors regarding their methodology for dynamically scaling CPU clock and voltage. In particular, we have noticed that there is no consistent API for clock scaling programmers to use. Most initial work skirts the issue altogether, simply indicating what services the operating system must provide for scaling algorithms to make their calculations. Some more concrete work details a scaling interface, but there is nothing consistent about the different interfaces other than that they change the clock frequency.
We have begun work on a standardized Application Programming Interface to dynamic clock and voltage scaling. We believe that this, easy to understand and utilize, interface can abstract hardware implementation differences away from the clock scaling programmer, allowing them to focus on their algorithm for clock scaling, instead of the particular implementation on a hardware platform.
This document is in three parts:
The Interface Definition - Where the API is laid out
Usage information - Where a couple of examples are given
Platform Support - Platforms that we are aware of that frequency/voltage scale. Screenshots of implementation on these platforms.
The API consists of simple functions in the kernel that can be called from within the kernel, or exported via ioctls to the dev filesystem entries and thus to userspace.
The model is to expose architecturally neutral speed steps to the programmer in the form of fractional speeds. The range of values of fractional speed are on a scale from 0 to 100. The speed setting is done using these speeds. The actual Mhz frequency is exposed as well for informational purposes. Additionally, for future compatibility, an optional parameter of cpuid may be passed to the relevant functions to get the value for that cpu. If it is not passed in, then it is assumed to be for the current CPU, and setting is assumed to operate on all CPUs.
Functions:
unsigned int getScalingSteps() - Returns the number of frequency scaling steps this platform is capable of.
void getFractionalValues(unsigned int[]) - Takes an allocated array which better be big enough to hold getScalingSteps() unsigned ints and fills it up with the architecturally neutral scaling step values, starting at the slowest frequency and ending with the highest frequency. (In other words, mySpeeds[0] is the slowest and mySpeeds[size-1] is the fastest.)
unsigned int getMhz(unsigned int aFractional) - Returns the MHz value for a specified fractional speed
unsigned int getCurrentFractional(unsigned int cpuid = SCALE_CURRENT_CPU) - Returns the current architecturally neutral speed the CPU is running at.
unsigned int getCurrentFractionalStep(unsigned int cpuid = SCALE_CURRENT_CPU) - Returns an index into the array of architecturally neutral speed steps representing the current step.
unsigned int faster(unsigned int aFractional) - Takes a fractional speed and returns the next faster speed or the top speed if the input is the top speed.
unsigned int slower(unsigned int aFractional) - Takes a fractional speed and returns the next slower speed or the bottom speed if the input is the bottom speed.
void setScaledClock(unsigned int newFractional, unsigned int cpuid = SCALE_ALL_CPUS) - Takes a fractional speed and sets the CPU frequency to the corresponding speed step. DOES NOT SCALE VOLTAGE. (For normal operation, use setScaledSpeed below.)
void setScaledSpeed (unsigned int newFractional, unsigned int cpuid = SCALE_ALL_CPUS) - Takes a fractional speed, and sets the CPU frequency to the corresponding speed step, and (if the platform supports it), scales the voltage to match that speed step.
NOTE: If you are using setScaledSpeed, these functions are informational only. Voltage setting should not be done lightly, as it can fry your CPU or hang your machine. When in doubt, simply use the setScaledSpeed for automatic voltage control.
unsigned int getCurrentVoltage(unsigned int cpuid = SCALE_CURRENT_CPU) - Returns the current operating voltage of the CPU multiplied by 100 and rounded to the nearest integer. (i.e. 1.25 V = 125)
unsigned int getVoltageSteps() - Returns the number of voltage scaling steps this platform is capable of.
unsigned int getCurrentVoltageStep(unsigned int cpuid = SCALE_CURRENT_CPU) - Returns an index into the array of voltage values for the current operating voltage.
void getVoltageValues(unsigned int[]) - analagous to getFractionalValues. Takes an allocated array of at least sizeof(unsigned int)*getVoltageSteps() and fills it with the voltage step values for this platform.
void setVoltage(unsigned int newVoltage, unsigned int cpuid = SCALE_ALL_CPUS) - Takes a voltage (multiplied by 100) and sets the CPU voltage to that voltage.
unsigned int current = 0;
unsigned int nextSpeed = 0;
current = getCurrentFractional();
nextSpeed = faster(current); (or if you want the next step slower, call slower here)
setScaledSpeed(nextSpeed);
unsigned int numberOfSteps = getScalingSteps();
unsigned int stepValues[] = malloc(sizeof(unsigned int)*numberOfSteps);
Then to peg the CPU up call setScaledSpeed(stepValues[numberOfSteps-1]) or to "double" the CPU (jump up the number of steps equal to the current setting) execute:
unsigned int currentStep = 0;
unsigned int nextStep = 0;
currentStep = getCurrentFractionalStep();
nextStep = currentStep*2;
if (nextStep >= numberOfSteps) nextStep = numberOfSteps-1;
setScaledSpeed(stepValues[nextStep]);
The test platform for mobile computing. Used in the Compaq WRL Itsy, as well as the Compaq Ipaq. Various other test boards, some of which have voltage scaling exist as well.
Levels of frequency scaling -
Voltage Scaling - Some Platforms
References -
SA1100 Developers Manual (PDF)
Brand new processor designed with frequency and voltage scaling in mind.
Levels of frequency scaling -
Voltage Scaling - Yes
References -
XScale Developer's Manual (PDF)
80200 Developer's Manual (PDF)
Migrating from SA1100 to 80200 (PDF)
XScale Microarchitectural Description (PDF)
Compaq has a laptop with frequency and voltage scaling integrated. Sony has a laptop with frequency scaling.
Levels of frequency scaling - 8
Voltage Scaling - Available
AMD K6-III 550Mhz at 550Mhz (92/100 fractional speed) with no load
AMD K6-III 550Mhz at 550Mhz (92/100) Playing MPEG2 video
AMD K6-III 550Mhz at 200Mhz (33/100) Playing MPEG2 video
AMD K6-III 550 Mhz at 400Mhz (67/100) Playing MPEG2 video
AMD K6-III 550 Mhz with a PID controller Playing MPEG2 video
AMD K6-III Module insertion and removal for dynamic clock setting
References -
Only two levels of frequency (and associated voltage). Looks like this is NDA, and will be released with ACPI 2.0.
References -
Sony Picturebook with a Crusoe processor -
4 levels of Frequency and associated Voltage
References -
Configurable using a free utility for linux: