Get A Spiny Norman Shirt Get A Shameless42 Shirt Get A Tux Shirt
top pipe
Get Firefox!

Fun with PowerNow! (Cool n' Quiet) and Linux

Direct control of CPU frequency from a simple C program.

Introduction:

I've always been a little curious when it comes to low-level control of a CPU. I guess that's just my hardware roots. When I saw the PowerNow technology that was available for Athlons, I just had to investigate. My initial dabbling is the subject of a post that can be found at: http://shamelessgeeks.com/shameless/powernow.shtml. If you haven't checked that page out before, you probably should do so before continuing. This post is just a continuation of what I was playing with there. In addition, that post contains basic instruction about how to make sure that the powerno-k8 driver is running and that you have it enabled.

This page will show you a very simple C demo program that can be used to control the power usage of your CPU. It has been tested on an Athlon X2 3800+, and is known to have worked on an Athlon64 3200+ in a past incarnation. The code is available in source format only. I won't be making it available in binary form. In my opinion, if you're not capable of following the simple instructions necessary to compile a small C program, you probably have no business playing with your CPU's basic settings.

Prerequisites:

You'll need root access to a machine that contains the following things:

  1. A working development environment
  2. A suitable AMD Athlon CPU chip. Check the AMD web site for verification.
  3. A BIOS with Cool n' Quiet (PowerNow!) support enabled.
  4. A kernel configured with the powernow-k8 driver.
In addition, it's best if you have at least *some* experience with C programming. I intend to explain how the program works, but not how to write it in C.

The Concept:

While setting up Cool n' Quiet (CnQ) on my new system, I became curious about how easy it would be to write my own control for the CPU. It turns out that it is much easier than it looks. Mostly, this is because Linux and the powernow-k8 driver provide an easy-to-use high-level interface to the chip statistics and settings. I decided to take advantage of these. In the end, I developed a program that could be contained in a single source file, requires no external libraries, and only uses a few basic system headers.

The Source Code:

The source file I ended up with can be found at: http://www.shamelessgeeks.com/code/cnq.tar.gz. It's an extremely simple, single-source implementation that should compile on any Linux 2.6 kernel with a valid development environment. Compilation instructions are included in the README.txt file. If you understand C programming, and you have no desire to understand exactly how the program works, just download the source and follow the instructions. No need to read any further.

How It All Works:

If you check out the top of the file, you'll see a few file pathnames in a set of #define lines. These are the most important parts of the file, since they contain the names of the system files that we will use to do all of the work.

The first file, identified by the following line:

#define SETTINGS_FILENAME "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies"

contains a list of all possible frequency settings. If you look at the contents of this file, you will see something similar to this:

2000000 1800000 1000000

These are all of the possible values for the CPU frequency in KHz. Based on that, you can tell that the sample line above shows a CPU capable of 2.0GHz, 1.8GHz, and 1.0GHz settings.

The next file of interest is:

#define CURRENT_SETTING_FILENAME "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq"

which contains the current frequency of the CPU. Any time you change the frequency, you should be able to see the change reflected in this file. This file, though listed here, isn't actually used in the program. I used it for initial debug and testing, but removed references to it to help performance. It has been left here intentionally as an aid to any future debugging.

The third file of interest is:

#define SET_FILENAME "/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"

which is the file you write to when you wish to change the frequency. Writing to this file requires root access, which is the reason why this application must be run as root. As with the other files discussed so far, all values written to this file are in KHz. You should also take care that you only write values to this file that are contained in scaling_available_frequencies. I have actually written values that were between the frequencies and the driver rounded off the settings to a reasonable value, but I wouldn't recommend doing so.

The last file of interest is:

#define STAT_FILENAME "/proc/stat"

and is the source of all of the processor usage statistics. The parsing of data from this file is the bulk of the processing done by the application. Luckily, it isn't too difficult, and most programmers will have little trouble understanding what is going on.

I derived the definition of the values found in /proc/stat directly from the Linux man pages. When you read the file, you should see a group of lines that look like this:

cpu  593139 9367 392256 29106036
cpu0 271777 4322 225835 14548465
cpu1 321362 5045 166421 14557571

The first row contains the totals for all CPUs, the remaining rows contain statistics for each CPU. The definitions for each column are as follows:

main():

Program operation is pretty easy to deduce from what I've explained so far. It's spelled out plainly in the main() function at the bottom of the file.

First, the program goes through an initialization sequence that consists of the following steps:

From then on, the program performs the following steps in an endless loop:

The current default values that the program uses are:

100ms sleep time per loop
> 30.0% CPU usage triggers an increase in frequency.
< 10.0% CPU usage triggers a decrease in frequency.

Dual Core / Single Core / Multi-CPU:

This program works very well with dual-core CPU's. This version was actually developed on one. An earlier incarnation of this program was developed for a single core 3200+, but was lost due to a mixup. The key reason why this works on either type of CPU is that the system only has one setting for speed/voltage available, so the cpu1 directory is a symbolic link to cpu0. This may not be true of systems with multiple physical CPU chips. Unfortunately, I have no way of testing it. If you get the chance to, please let me know what the results are.

Normal Operation:

Compile the program using the instructions in the README.txt file. To run the program, you will need to open a shell, cd to the directory containing the binary, su to root, then type the line:

./cnq

Thats all. You should see a few opening lines printed out that show what the possible settings are, followed by a line that is printed every time the CPU frequency is changed. This line will start with a ^ symbol if the new frequency is a shift upward or a v symbol if it is a step downward. The next value you will see is the frequency the CPU is set to, followed by the usage percent that triggered the change in parentheses.

Further development:

I may add features to this program from time to time if I feel inspired to. Since it is mostly an exercise in discovery, and not intended as an actual product, you shouldn't get your hopes up. However, if you use the code, please find some way to link to it or my website. I can always use the press. If you have something to add to the code, please feed changes back to me so that I can spread them around. You can contact me here: webmaster@shamelessgeeks.com.

JJS (a.k.a. Shameless, a.k.a. COJones)


Please Leave a Comment for the Author: