Boulder Unified Frequency/Voltage Scaling Interface (BUFScale)

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.

Interface Definition

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:

Frequency 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.

Voltage Functions

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.

Usage

For simple speed incrementing up or down simply:

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);

For more complex speed setting:

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]);

 

Platforms with Frequency and/or Voltage Scaling

Strong Arm SA1100

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)

Intel XScale 80200

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)

80200 Dev Manual Errata (PDF)

Migrating from SA1100 to 80200 (PDF)

XScale Magazine Article (PDF)

XScale Microarchitectural Description (PDF)

 

AMD Mobile K6-II+ with Power NOW!

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 -

PowerNOW! Overview (PDF)

PowerNOW! Design Guide (PDF)

Intel Pentium III Mobile with SpeedStep

Only two levels of frequency (and associated voltage).  Looks like this is NDA, and will be released with ACPI 2.0.

References -

Transmeta Crusoe with LongRun

Sony Picturebook with a Crusoe processor -

4 levels of Frequency and associated Voltage

References -

Configurable using a free utility for linux:

longrun_0.9.orig.tar.gz