CPUSpeed 1.2.1 released!
CPUSpeed 1.2.1 has, at long last, been released. There are many, many new features in this release including even greater efficiency and full multi-processor support. You can grab it at http://carlthompson.net/software/cpuspeed .
Some of the current features include:
* Dynamically adjusts CPU speed and voltage based on demand for CPU (idle/work ratio threshold is user-configurable)
* Automatically detects available processor speeds
* For normal operation, no configuration or options are necessary. Just run it!
* Full multiprocessor support (each CPU separately run-time configurable)
* One binary works on both Linux 2.4 with the 'proc' interface and Linux 2.6 with the 'sysfs' interface. No need to recompile if you switch kernels! (proc interface deprecated)
* Configurable minimum and maximum allowed speeds
* Can reduce CPU speed and voltage if AC power is disconnected from the computer (requires ACPI)
* Can maximize CPU speed if AC power is connected to the computer (requires ACPI)
* Can reduce CPU speed and voltage if CPU temperature gets too high (Requires ACPI, temperature is user-configurable)
* Can be told to lock CPU at minimum or maximum frequency via signals
* "nice()'d" processes and those waiting for I/O will not increase CPU speed
* Polling interval for CPUs, temperature and AC adapter configurable separately
* Crash-proof frequency switching even if you have an outdated version of CPUFreq and a very temperamental CPU (some AMD mobile Athlons in particular)
* Handles strange processors with lots of little speed steps
* More that I am forgetting...
CHANGELOG:
Version 1.2.1
* Can now better handle processors with a large number of speed steps (>20)
* Configurable maximum and minimum CPU speeds
* Option to maximize speed when AC adapter connected
* Option to NOT minimize speed when AC adapter disconnected
* Consider I/O wait time as idle time
* Option to restore previous speed on program exit
* Can set polling interval for CPU idle, AC adapter and temperature separately
* Better Red Hat / Fedora Core / SuSE script integration
* More efficient startup sequence (fewer speed changes necessary)
* Full multi-processor support
* Try to load default list of drivers if none specified
Version 1.1
* One binary works on both 2.4 and 2.5+ kernels
* Updated to work with latest sysfs directory structure (tested with 2.5.75)
* Now the program is even better at making sure temperamental Athlons don't
* crash no matter what state the CPU is in on startup
* Simplified things by having just one threshold level instead of two
* Replaced floating point math with integer
Remember, you can grab it at http://carlthompson.net/software/cpuspeed .
As always, feedback is welcome.
Carl Thompson
Quoted 4 lines · Carl Thompson
CPUSpeed 1.2.1 has, at long last, been released. There are many, many new features in this release including even greater efficiency and full multi-processor support. You can grab it at
http://carlthompson.net/software/cpuspeed .
You'll need this bit..
cpuspeed.cc renamed from cpuspeed.cc~ +1 -1
@@ -769,7 +769,7 @@ main(unsigned argc, char * argv[]) "Author:\n" " Carl Thompson - cet [at] carlthompson.net (copyright 2002 - 2005)\n" "\n" - , NAME, VERSION, NAME, NAME + , NAME, VERSION, NAME ); exit(0); }
Otherwise you see..
gcc -Wall -fno-exceptions -c -O2 cpuspeed.cc cpuspeed.cc: In function `int main(unsigned int, char**)':
cpuspeed.cc:773: warning: too many arguments for format
Dave
Hi Carl,
Quoted 1 line
As always, feedback is welcome.
Could you merge this patch (or an adaption if you want to preserve the direct interface) to CPUSpeed? I haven't re-diffed it to the new version, but as I already had sent it earlier... I'm willing to re-diff, of course, but want your feedback first.
Thanks,
Dominik
cpuspeed.cc +44 -80
@@ -15,6 +15,7 @@ Contributors: Enrico Tassi <[email protected]> + Dominik Brodowski <[email protected]> This program is only for computers with Linux kernels compiled with CPUFreq. You must have a CPU that supports frequency and/or voltage
@@ -35,6 +36,7 @@ #include <stdarg.h> #include <time.h> #include <sys/utsname.h> +#include <cpufreq.h> #ifndef NAME # define NAME "cpuspeed"
@@ -52,42 +54,6 @@ # define errprintf(A...) #endif -#define SYSFS_MIN_SPEED_FILE \ - "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq" - -#define SYSFS_MAX_SPEED_FILE \ - "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" - -#define SYSFS_CURRENT_SPEED_FILE \ - "/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed" - -#define SYSFS_GOVERNOR_FILE \ - "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" - -#define SYSFS_USERSPACE \ - "userspace" - -#define PROC_MIN_SPEED_FILE \ - "/proc/sys/cpu/0/speed-min" - -#define PROC_MAX_SPEED_FILE \ - "/proc/sys/cpu/0/speed-max" - -#define PROC_CURRENT_SPEED_FILE \ - "/proc/sys/cpu/0/speed" - -#define PROC_GOVERNOR_FILE \ - "/proc/cpufreq" - -#define PROC_USERSPACE \ - "0%0%100%userspace" - -char * MIN_SPEED_FILE; -char * MAX_SPEED_FILE; -char * CURRENT_SPEED_FILE; -char * GOVERNOR_FILE; -char * USERSPACE; - // defines what info we care about for each speed step struct {
@@ -128,22 +94,6 @@ fclose(fp); } -// write a line to a file -void -write_line(const char * filename, const char *fmt, ...) -{ - FILE * fp = fopen(filename, "w+"); - if (!fp) - die(true, "Could not open file for writing: %s", filename); - va_list ap; - // get variable argument list passed - va_start(ap, fmt); - if (vfprintf(fp, fmt, ap) < 0) - die(true, "Could not write to file: %s", filename); - va_end(ap); - fclose(fp); -} - // read an integer value from a file unsigned read_value(const char * filename)
@@ -156,14 +106,14 @@ // get the current CPU speed unsigned get_speed() { - return read_value(CURRENT_SPEED_FILE); + return cpufreq_get_freq_kernel(0); } // set the current CPU speed void set_speed(unsigned value) { errprintf("Setting speed to: %uKHz\n", value); - write_line(CURRENT_SPEED_FILE, "%u\n", value); + cpufreq_set_frequency(0, value); // give CPU / chipset voltage time to settle down usleep(10000); }
@@ -191,9 +141,42 @@ void get_supported_speeds() { - unsigned min = read_value(MIN_SPEED_FILE); - unsigned max = read_value(MAX_SPEED_FILE); + unsigned long min; + unsigned long max; const unsigned step = 25000; + struct cpufreq_available_frequencies *freqs, *tmp; + unsigned current_speed = 0; + int ret; + + freqs = cpufreq_get_available_frequencies(0); + if (freqs) { + unsigned int count = 0; + /* these may be unsorted */ + tmp = freqs; + while (tmp) { + count++; + tmp = tmp->next; + } + if (count > (MAX_SPEEDS - 1)) + count = (MAX_SPEEDS - 1); + max = 20000000; + for (current_speed = 0; (current_speed < count); current_speed++) { + min = 0; + tmp = freqs; + while (tmp) { + if ((tmp->frequency < max) && (tmp->frequency > min)) + min = freqs->frequency; + tmp = tmp->next; + } + speeds[current_speed].khz = min; + max = min; + } + speeds[count].khz = 0; + cpufreq_put_available_frequencies(freqs); + return; + } + + ret = cpufreq_get_hardware_limits(0, &min, &max); // Go to max speed if we are not already there for (unsigned current = get_speed(); current < max; current += step)
@@ -203,7 +186,6 @@ // CPU by looping from the maximum speed to the minimum speed and trying // to set every possible speed divisible by step! speeds[0].khz = max; - unsigned current_speed = 0; for (unsigned current = max - step; current > min - step; current -= step) { set_speed(current);
@@ -421,26 +403,8 @@ int main(unsigned argc, char * argv[]) { - struct utsname un; - uname(&un); - if (!strncmp(un.release, "2.4", 3)) - { - MIN_SPEED_FILE = PROC_MIN_SPEED_FILE; - MAX_SPEED_FILE = PROC_MAX_SPEED_FILE; - CURRENT_SPEED_FILE = PROC_CURRENT_SPEED_FILE; - GOVERNOR_FILE = PROC_GOVERNOR_FILE; - USERSPACE = PROC_USERSPACE; - } - else - { - MIN_SPEED_FILE = SYSFS_MIN_SPEED_FILE; - MAX_SPEED_FILE = SYSFS_MAX_SPEED_FILE; - CURRENT_SPEED_FILE = SYSFS_CURRENT_SPEED_FILE; - GOVERNOR_FILE = SYSFS_GOVERNOR_FILE; - USERSPACE = SYSFS_USERSPACE; - } - unsigned interval = 20; // 2 seconds + int ret; bool daemonize = false; // parse argv
@@ -546,11 +510,11 @@ } } + // use the userspace governor - write_line(GOVERNOR_FILE, "%s\n", USERSPACE); - - if (access(CURRENT_SPEED_FILE, W_OK) < 0) - die(true, "Cannot write to speed control file: %s", CURRENT_SPEED_FILE); + ret = cpufreq_modify_policy_governor(0, "userspace"); + if (ret) + return -ENODEV; // run in background if requested if (daemonize)
Makefile +2 -2
@@ -10,13 +10,13 @@ $(TARGET): cpuspeed.cc $(CC) -c $(COPTS) -DNAME=\"$(TARGET)\" cpuspeed.cc - $(CC) cpuspeed.o -o $(TARGET) + $(CC) -lcpufreq -L/usr/lib/ cpuspeed.o -o $(TARGET) strip $(TARGET) # Debug targets $(DEBUG_TARGET): cpuspeed.cc $(CC) -c -g -DDEBUG -DNAME=\"$(DEBUG_TARGET)\" -o cpuspeed_debug.o cpuspeed.cc - $(CC) cpuspeed_debug.o -o $(DEBUG_TARGET) + $(CC) -lcpufreq cpuspeed_debug.o -o $(DEBUG_TARGET) install: $(TARGET) cp -f $(TARGET) /sbin