Thanks for the info.. Well, all those number look right.. this is just getting bizarre.
I'm attaching a new powernowd.c file.. it has some extra debugging turned on.. would you mind running it? just compile it (gcc -o powernowd powernowd.c) and run it as root.. no need for special flags or anything. On my athlon64 box, by setting the step parameter by hand (which forces it to use the non scalaing_available_freqs path), I see the following, and you should see similar.. I'm particulary interested in the table_size lines.
Sorry to trouble you with this, but i can't seem to figure out what's wrong :/
john. c
[EMAIL PROTECTED] ~/powernowd-0.96 $ sudo ./powernowd -s 133000 -d -vvv PowerNow Daemon v0.96, (c) 2003-2005 John Clemens Settings: verbosity: 3 mode: 1 (AGGRESSIVE) step: 133 MHz (133000 kHz) lowwater: 20 % highwater: 80 % poll interval: 1000 ms Found 1 cpu: -- 1 thread (or core) per physical cpu max_speed = 2000000, min_speed = 800000, step = 133000 1: cpu->table_size = 10 2: cpu->table_size = 11 cpu0: 800Mhz - 2000Mhz (11 steps) step1 : 2000Mhz step2 : 1867Mhz step3 : 1734Mhz step4 : 1601Mhz step5 : 1468Mhz step6 : 1335Mhz step7 : 1202Mhz step8 : 1069Mhz step9 : 936Mhz step10 : 803Mhz step11 : 800Mhz Setting speed to 1867000 Setting speed to 1734000 Setting speed to 1601000 Setting speed to 2000000 Statistics: 4 speed changes in 4 seconds PowerNow Daemon Exiting.
-- John Clemens http://www.deater.net/john john at deater.net "I Hate Quotes" -- Samuel L. Clemens
/* * powernowd.c: (c) 2003-2005 John Clemens <[EMAIL PROTECTED]> * * Released under the GNU General Public License. See the LICENSE file * included with this file. * * * Changelog: * v0.75, initial release. * v0.80, add syslog support, -s,-p,-u,-l options, clean up error reporting * some (still some more work needed), made packaging better, removed * find_mount() code.. /sys is the blessed place, so be it.. no sense * having unnecessary code and the maintenance thereof. fixed bug * where mode was actually defaulting to SINE, not AGGRESSIVE. * v0.85, Minor memory init fixes, add clearer error messages, check for * root, added -b and -n options, add pause support (SIGUSR1/2, -b * option), added #ifdef'd-out code to handle buggy athlons which * might not be necessary anymore, fixed some help text bugs, added * a few more comments. * v0.90, Support drivers that report speed in Mhz instead of Khz. Removed * buggy athlon workaround, as it's not needed. Removed pause/unpause * code. Added sample powernowd init script to show how to emulate * old pause/unpause behavior a cleaner way. Added LEAPS mode and * verbosity patches by Hans Ulrich Niedermann. Cleaned up verbosity * handling more. * v0.95, Added proper HT support, and SMT/CMP infrastructure. Hope it * works. Added scalaing_available_frequencies support and made * default. * v0.96 Fix HT detection code to default to 1 if cpuid gives strange * result (fixes centrinos). Cleaned up error reporting in * read_file(). * * * Contributions from: * Warren Togami <[EMAIL PROTECTED]> * Michael Schreiter <[EMAIL PROTECTED]> * Wolfgang Tremmel <[EMAIL PROTECTED]> * Hans Ulrich Niedermann <[EMAIL PROTECTED]> * -- And many others who have sent me patches over the past 3 years, * some of whom I've never even acknowledged. Just know that your * support is appreciated, even if i didn't merge in your ideas. * Thank you. */
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> #include <syslog.h> #include <errno.h> #include <signal.h> #include <time.h> #define pprintf(level, ...) do { \ if (level <= verbosity) { \ if (daemonize) \ syslog(LOG_INFO, __VA_ARGS__); \ else \ printf(__VA_ARGS__); \ } \ } while(0) typedef struct cpustats { unsigned long long user; unsigned long long mynice; unsigned long long system; unsigned long long idle; unsigned long long iowait; unsigned long long irq; unsigned long long softirq; } cpustats_t; typedef struct cpuinfo { unsigned int cpuid; unsigned int nspeeds; unsigned int max_speed; unsigned int min_speed; unsigned int current_speed; unsigned int speed_index; int fd; char *sysfs_dir; cpustats_t *last_reading; cpustats_t *reading; int in_mhz; /* 0 = speed in kHz, 1 = speed in mHz */ unsigned long *freq_table; int table_size; int threads_per_core; } cpuinfo_t; /* * Global pointer to the beginning of all our info. This is so we can tear * stuff down later in the signal handler. */ cpuinfo_t **cpuinfo; /* idea stolen from procps */ static char buf[1024]; enum function { SINE, AGGRESSIVE, PASSIVE, LEAPS } func = AGGRESSIVE; enum modes { LOWER, SAME, RAISE }; /* for a daemon as simple as this, global data is ok. */ /* settings */ int daemonize = 1; int ignore_nice = 1; int verbosity = 0; unsigned int step = 100000; /* in kHz */ unsigned int poll = 1000; /* in msecs */ unsigned int highwater = 80; unsigned int lowwater = 20; unsigned int max_limit = 0; unsigned int min_limit = 0; unsigned int step_specified = 0; unsigned int t_per_core = 1; unsigned int cores_specified = 0; /* statistics */ unsigned int change_speed_count = 0; time_t start_time = 0; #define SYSFS_TREE "/sys/devices/system/cpu/" #define SYSFS_SETSPEED "scaling_setspeed" #define VERSION "0.96" void help(void) { printf("PowerNow Daemon v%s, (c) 2003-2005 John Clemens\n", VERSION); printf("Daemon to control the speed and voltage of cpus.\n\n"); printf("This is a simple client to the CPUFreq driver, and uses\n"); printf("linux kernel v2.5 sysfs interface. You need a supported\n"); printf("cpu, and a kernel that supports sysfs to run this daemon.\n"); printf("\nAvailable Options:\n"); printf(" -h Print this help message\n"); printf(" -d Don't detach from terminal (default is to\n"); printf(" detach and run in the background)\n"); printf(" -v Increase output verbosity, can be used more than once.\n"); printf(" -q Quiet mode, only emergency output.\n"); printf(" -n Include 'nice'd processes in calculations\n"); printf(" -m # Modes of operation, can be 0, 1, 2, or 3:\n"); printf(" 0 = SINE, 1 = AGGRESSIVE (default),\n"); printf(" 2 = PASSIVE, 3 = LEAPS\n"); printf(" -s # Frequency step in kHz (default = 100000)\n"); printf(" -p # Polling frequency in msecs (default = 1000)\n"); printf(" -c # Specify number of threads per power-managed core\n"); printf(" -u # CPU usage upper limit percentage [0 .. 100, default 80]\n"); printf(" -l # CPU usage lower limit percentage [0 .. 100, default 20]\n"); printf("\n"); return; } /* * Open a file and copy it's first 1024 bytes into the global "buf". * Zero terminate the buffer. */ int read_file(const char *file, int fd, int new) { int n, err; if (new) { if ((fd = open(file, O_RDONLY)) == -1) { err = errno; perror(file); return err; } } lseek(fd, 0, SEEK_SET); if ((n = read(fd, buf, sizeof(buf)-1)) < 0) { err = errno; perror(file); close(fd); return err; } buf[n] = '\0'; if (new) close(fd); return 0; } /* * Reads /proc/stat into buf, and parses the output. * * Format of line: * ... * cpu<id> <user> <nice> <system> <idle> <iowait> <irq> <softirq> */ int get_stat(cpuinfo_t *cpu) { char *p1, *p2, searchfor[10]; int err; if ((err = read_file("/proc/stat", cpu->fd, 0)) != 0) { return err; } sprintf(searchfor, "cpu%d ", cpu->cpuid); p1 = strstr(buf, searchfor); if (p1 == NULL) { perror("Error parsing /proc/stat"); return ENOENT; } p2 = p1+strlen(searchfor); memcpy(cpu->last_reading, cpu->reading, sizeof(cpustats_t)); cpu->reading->user = strtol(p2, &p2, 10); cpu->reading->mynice = strtol(p2, &p2, 10); cpu->reading->system = strtol(p2, &p2, 10); cpu->reading->idle = strtol(p2, &p2, 10); cpu->reading->iowait = strtol(p2, &p2, 10); cpu->reading->irq = strtol(p2, &p2, 10); cpu->reading->softirq = strtol(p2, &p2, 10); return 0; } /* * Once a decision is made, change the speed. */ int change_speed(cpuinfo_t *cpu, enum modes mode) { int fd, len, err; char writestr[100]; if (mode == RAISE) { if ((func == AGGRESSIVE) || (func == LEAPS)) { cpu->speed_index = 0; } else { if (cpu->speed_index != 0) cpu->speed_index--; } } else { if ((func == PASSIVE) || (func == LEAPS)) { cpu->speed_index = (cpu->table_size-1); } else { if (cpu->speed_index != (cpu->table_size-1)) cpu->speed_index++; } } cpu->current_speed = cpu->freq_table[cpu->speed_index]; pprintf(3,"Setting speed to %d\n", cpu->current_speed); change_speed_count++; strncpy(writestr, cpu->sysfs_dir, 50); strncat(writestr, SYSFS_SETSPEED, 20); if ((fd = open(writestr, O_WRONLY)) < 0) { err = errno; perror("Can't open scaling_setspeed"); return err; } lseek(fd, 0, SEEK_CUR); sprintf(writestr, "%d\n", (cpu->in_mhz) ? (cpu->current_speed / 1000) : cpu->current_speed); pprintf(4,"mode=%d, str=%s", mode, writestr); if ((len = write(fd, writestr, strlen(writestr))) < 0) { err = errno; perror("Couldn't write to scaling_setspeed\n"); return err; } if (len != strlen(writestr)) { printf("Could not write scaling_setspeed\n"); close(fd); return EPIPE; } close(fd); return 0; } /* * The heart of the program... decide to raise or lower the speed. */ enum modes inline decide_speed(cpuinfo_t *cpu) { int err; float pct; unsigned long long usage, total; if ((err = get_stat(cpu)) < 0) { perror("Can't get stats"); return err; } total = (cpu->reading->user - cpu->last_reading->user) + (cpu->reading->system - cpu->last_reading->system) + (cpu->reading->mynice - cpu->last_reading->mynice) + (cpu->reading->idle - cpu->last_reading->idle) + (cpu->reading->iowait - cpu->last_reading->iowait) + (cpu->reading->irq - cpu->last_reading->irq) + (cpu->reading->softirq - cpu->last_reading->softirq); if (ignore_nice) { usage = (cpu->reading->user - cpu->last_reading->user) + (cpu->reading->system - cpu->last_reading->system) + (cpu->reading->irq - cpu->last_reading->irq) + (cpu->reading->softirq - cpu->last_reading->softirq); } else { usage = (cpu->reading->user - cpu->last_reading->user) + (cpu->reading->mynice - cpu->last_reading->mynice) + (cpu->reading->system - cpu->last_reading->system) + (cpu->reading->irq - cpu->last_reading->irq) + (cpu->reading->softirq - cpu->last_reading->softirq); } pct = ((float)usage)/((float)total); pprintf(4,"PCT = %f\n", pct); if ((pct > ((float)highwater/100.0)) && (cpu->current_speed != cpu->max_speed)) { /* raise speed to next level */ return RAISE; } else if ((pct < ((float)lowwater/100.0)) && (cpu->current_speed != cpu->min_speed)) { /* lower speed */ return LOWER; } return SAME; } /* * Abuse glibc's qsort. Compare function to sort list of frequencies in * ascending order. */ int faked_compare(const void *a, const void *b) { unsigned long *a1 = (unsigned long *)a; unsigned long *b1 = (unsigned long *)b; if (*a1 < *b1) return 1; if (*a1 > *b1) return -1; return 0; } /* * Allocates and initialises the per-cpu data structures. */ int get_per_cpu_info(cpuinfo_t *cpu, int cpuid) { char cpustr[100], scratch[100], tmp[10], *p1; int fd, err; unsigned long temp; cpu->cpuid = cpuid; cpu->sysfs_dir = (char *)malloc(50*sizeof(char)); if (cpu->sysfs_dir == NULL) { perror("Couldn't allocate per-cpu sysfs_dir"); return ENOMEM; } memset(cpu->sysfs_dir, 0, (50*sizeof(char))); strncpy(cpu->sysfs_dir, SYSFS_TREE, 30); sprintf(cpustr, "cpu%d/cpufreq/", cpuid); strncat(cpu->sysfs_dir, cpustr, 20); strncpy(scratch, cpu->sysfs_dir, 50); strncat(scratch, "cpuinfo_max_freq", 18); if ((err = read_file(scratch, 0, 1)) != 0) { return err; } cpu->max_speed = strtol(buf, NULL, 10); strncpy(scratch, cpu->sysfs_dir, 50); strncat(scratch, "cpuinfo_min_freq", 18); if ((err = read_file(scratch, 0, 1)) != 0) { return err; } cpu->min_speed = strtol(buf, NULL, 10); /* * More error handling, make sure step is not larger than the * difference between max and min speeds. If so, truncate it. */ if (step > (cpu->max_speed - cpu->min_speed)) { step = cpu->max_speed - cpu->min_speed; } /* XXXjc read the real current speed */ cpu->current_speed = cpu->max_speed; cpu->speed_index = 0; strncpy(scratch, cpu->sysfs_dir, 50); strncat(scratch, "scaling_available_frequencies", 50); if (((err = read_file(scratch, 0, 1)) != 0) || (step_specified)) { /* * We don't have scaling_available_frequencies. build the * table from the min, max, and step values. the driver * could ignore these, but we'll represent it this way since * we don't have any other info. */ printf("max_speed = %d, min_speed = %d, step = %d\n", cpu->max_speed, cpu->min_speed, step); cpu->table_size = ((cpu->max_speed-cpu->min_speed)/step) + 1; printf("1: cpu->table_size = %d\n",cpu->table_size); cpu->table_size += ((cpu->max_speed-cpu->min_speed)%step)?1:0; printf("2: cpu->table_size = %d\n",cpu->table_size); cpu->freq_table = (unsigned long *) malloc(cpu->table_size*sizeof(unsigned long)); if (cpu->freq_table == (unsigned long *)NULL) { perror("couldn't allocate cpu->freq_table"); return ENOMEM; } /* populate the table. Start at the top, and subtract step */ for (temp = 0; temp < cpu->table_size; temp++) { cpu->freq_table[temp] = ((cpu->min_speed<(cpu->max_speed-(temp*step))) ? (cpu->max_speed-(temp*step)) : (cpu->min_speed) ); } } else { /* * We do have the file, parse it and build the table from * there. */ /* The format of scaling_available_frequencies (SAF) is: * "number<space>number2<space>...numberN<space>\n", but this * can change. So we're relying on the fact that strtoul will * return 0 if it can't find anything, and that 0 will never * be a real value for the available frequency. */ p1 = buf; temp = strtoul(p1, &p1, 10); while((temp > 0) && (cpu->table_size < 100)) { cpu->table_size++; temp = strtoul(p1, &p1, 10); } cpu->freq_table = (unsigned long *) malloc(cpu->table_size*sizeof(unsigned long)); if (cpu->freq_table == (unsigned long *)NULL) { perror("Couldn't allocate cpu->freq_table\n"); return ENOMEM; } p1 = buf; for (temp = 0; temp < cpu->table_size; temp++) { cpu->freq_table[temp] = strtoul(p1, &p1, 10); } } /* now lets sort the table just to be sure */ qsort(cpu->freq_table, cpu->table_size, sizeof(unsigned long), &faked_compare); strncpy(scratch, cpu->sysfs_dir, 50); strncat(scratch, "scaling_governor", 20); if ((err = read_file(scratch, 0, 1)) != 0) { perror("couldn't open scaling_governors file"); return err; } if (strncmp(buf, "userspace", 9) != 0) { if ((fd = open(scratch, O_RDWR)) < 0) { err = errno; perror("couldn't open govn's file for writing"); return err; } strncpy(tmp, "userspace\n", 11); if (write(fd, tmp, 11*sizeof(char)) < 0) { err = errno; perror("Error writing file governor"); close(fd); return err; } if ((err = read_file(scratch, fd, 0)) != 0) { perror("Error reading back governor file"); close(fd); return err; } close(fd); if (strncmp(buf, "userspace", 9) != 0) { perror("Can't set to userspace governor, exiting"); return EPIPE; } } cpu->last_reading = (cpustats_t *)malloc(sizeof(cpustats_t)); cpu->reading = (cpustats_t *)malloc(sizeof(cpustats_t)); memset(cpu->last_reading, 0, sizeof(cpustats_t)); memset(cpu->reading, 0, sizeof(cpustats_t)); /* * Some cpufreq drivers (longhaul) report speeds in MHz instead * of KHz. Assume for now that any currently supported cpufreq * processor will a) not be faster then 10GHz, and b) not be slower * then 10MHz. Therefore, is the number for max_speed is less than * 10000, assume the driver is reporting speeds in MHz, not KHz, * and adjust accordingly. * * XXXjc the longhaul driver has been fixed (2.6.5ish timeframe) * so this should't be needed anymore. Remove for 1.0? */ cpu->in_mhz = 0; if (cpu->max_speed <= 10000) { cpu->in_mhz = 1; cpu->max_speed *= 1000; cpu->min_speed *= 1000; cpu->current_speed *= 1000; } if ((cpu->fd = open("/proc/stat", O_RDONLY)) < 0) { err = errno; perror("can't open /proc/stat"); return err; } if ((err = get_stat(cpu)) < 0) { perror("can't read /proc/stat"); return err; } return 0; } /* * Signal handler for SIGTERM/SIGINT... clean up after ourselves */ void terminate(int signum) { int ncpus, i; cpuinfo_t *cpu; ncpus = sysconf(_SC_NPROCESSORS_CONF); for(i = ncpus; i > 0; i--) { cpu = cpuinfo[i-1]; /* force ourselves back up to the highest Mhz speed */ func = LEAPS; change_speed(cpu, RAISE); /* close the /proc/stat fd */ close(cpu->fd); /* deallocate everything */ free(cpu->sysfs_dir); free(cpu->last_reading); free(cpu->reading); free(cpu); } time_t duration = time(NULL) - start_time; pprintf(1,"Statistics:\n"); pprintf(1," %d speed changes in %d seconds\n", change_speed_count, (unsigned int) duration); pprintf(0,"PowerNow Daemon Exiting.\n"); closelog(); exit(0); } const char *str_func(void) { switch (func) { case SINE: return "SINE"; case AGGRESSIVE: return "AGGRESSIVE"; case PASSIVE: return "PASSIVE"; case LEAPS: return "LEAPS"; default: return "UNKNOWN"; } } /* Generic x86 cpuid function lifted from kernel sources */ /* * Generic CPUID function */ static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx) { __asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "0" (op)); } /* * a little bit of black magic to try and detect the number of cores per * processor. This will have to be added on to for every architecture, * as we learn how to detect them from userspace. Note: This method * assumes uniform processor/thread ID's. * * you can always override this by using the -c command line option to * specify the number of threads per core. If you do so, it will do a static * mapping, uniform for all real processors in the system. Actually, so * will this one, because there's no way for me to bind to a processor. * (yet. :) */ int determine_threads_per_core(int ncpus) { #ifdef __i386__ /* * XXXjc fix eventually to run on each processor so you * can support mixed multi and single-core cpus. Need to know * how to force ourselves to run on one particular processor. */ int eax,ebx,ecx,edx, num; cpuid(1,&eax,&ebx,&ecx,&edx); /* * Do we support hyperthreading? * AMD's dual-core will masquerade as HT, so this should work * for them too. */ if(edx & 0x08000000) { /* * if so, is it enabled? If so, how many threads * are enabled? Thank you, sandpile.org and the LKML. */ num = (ebx & 0x00FF0000) >> 16; } /* * if num = 0, default to 1. Other non-multiples of cpus will * be taken care of later * XXXjc, rewrite to use sysfs (affected_cpus). */ return ((num)?num:1); #endif /* always default to one thread per core */ return 1; } /* * Main program loop.. parse arguments, sanity chacks, setup signal handlers * and then enter main loop */ int main(int argc, char **argv) { cpuinfo_t *cpu; int ncpus, i, j, err, num_real_cpus, threads_per_core; enum modes change, change2; /* Parse command line args */ while(1) { int c; c = getopt(argc, argv, "dnvqm:s:p:c:u:l:U:L:h"); if (c == -1) break; switch(c) { case 'd': daemonize = 0; break; case 'n': ignore_nice = 0; break; case 'v': verbosity++; if (verbosity > 10) verbosity = 10; break; case 'q': verbosity = -1; break; case 'c': t_per_core = strtol(optarg, NULL, 10); if (t_per_core < 1) { printf("invalid number of cores/proc"); help(); exit(ENOTSUP); } cores_specified = 1; break; case 'm': func = strtol(optarg, NULL, 10); if ((func < 0) || (func > 3)) { printf("Invalid mode specified"); help(); exit(ENOTSUP); } pprintf(2,"Using %s mode.\n", str_func()); break; case 's': step = strtol(optarg, NULL, 10); if (step < 0) { printf("step must be non-negative"); help(); exit(ENOTSUP); } step_specified = 1; pprintf(2,"Using %dHz step.\n", step); break; case 'p': poll = strtol(optarg, NULL, 10); if (poll < 0) { printf("poll must be non-negative"); help(); exit(ENOTSUP); } pprintf(2,"Polling every %d msecs\n", poll); break; case 'u': highwater = strtol(optarg, NULL, 10); if ((highwater < 0) || (highwater > 100)) { printf("upper limit must be between 0 and 100\n"); help(); exit(ENOTSUP); } pprintf(2,"Using upper pct of %d%%\n",highwater); break; case 'l': lowwater = strtol(optarg, NULL, 10); if ((lowwater < 0) || (lowwater > 100)) { printf("lower limit must be between 0 and 100\n"); help(); exit(ENOTSUP); } pprintf(2,"Using lower pct of %d%%\n",lowwater); break; case 'h': default: help(); return 0; } } /* last things to check... */ if (lowwater > highwater) { printf("Invalid: lower pct higher than upper pct!\n"); help(); exit(ENOTSUP); } /* so we don't interfere with anything, including ourself */ nice(5); if (daemonize) openlog("powernowd", LOG_AUTHPRIV|LOG_PERROR, LOG_DAEMON); /* My ego's pretty big... */ pprintf(0,"PowerNow Daemon v%s, (c) 2003-2005 John Clemens\n", VERSION); /* are we root?? */ if (getuid() != 0) { printf("Go away, you are not root. Only root can run me.\n"); exit(EPERM); } pprintf(1,"Settings:\n"); pprintf(1," verbosity: %4d\n", verbosity); pprintf(1," mode: %4d (%s)\n", func, str_func()); pprintf(1," step: %4d MHz (%d kHz)\n", step/1000, step); pprintf(1," lowwater: %4d %%\n", lowwater); pprintf(1," highwater: %4d %%\n", highwater); pprintf(1," poll interval: %4d ms\n", poll); ncpus = sysconf(_SC_NPROCESSORS_CONF); /* Malloc, initialise data structs */ cpu = malloc(sizeof(cpuinfo_t)*ncpus); if (cpu == (cpuinfo_t *)NULL) { perror("Couldn't malloc cpuinfo"); return ENOMEM; } memset(cpu, 0, (sizeof(cpuinfo_t)*ncpus)); cpuinfo = &cpu; if (cores_specified) { if (ncpus < t_per_core) { printf("\nWARNING: bogus # of thread per core, assuming 1\n"); threads_per_core = 1; } else { threads_per_core = t_per_core; } } else { threads_per_core = determine_threads_per_core(ncpus); } /* We don't support mixed configs yet */ if (!ncpus || !threads_per_core || ncpus % threads_per_core) { printf("WARN: ncpus is not a multiple of threads_per_core!\n"); threads_per_core = 1; //help(); //exit(ENOTSUP); } num_real_cpus = ncpus/threads_per_core; for (i=0;i<ncpus;i++) { cpu[i].threads_per_core = threads_per_core; } pprintf(0,"Found %d cpu%s: -- %d thread%s (or core%s) per physical cpu\n", ncpus/threads_per_core, (ncpus>1)?"s":"", threads_per_core, (threads_per_core>1)?"s":"", (threads_per_core>1)?"s":""); for (i=0;i<ncpus;i++) { if ((err = get_per_cpu_info(&cpu[i], i)) != 0) { printf("\n"); goto out; } pprintf(0," cpu%d: %dMhz - %dMhz (%d steps)\n", cpu[i].cpuid, cpu[i].min_speed / 1000, cpu[i].max_speed / 1000, cpu[i].table_size); for(j=0;j<cpu[i].table_size; j++) { pprintf(1, " step%d : %ldMhz\n", j+1, cpu[i].freq_table[j] / 1000); } } /* now that everything's all set up, lets set up a exit handler */ signal(SIGTERM, terminate); signal(SIGINT, terminate); if (daemonize) daemon(0, 0); start_time = time(NULL); /* Now the main program loop */ while(1) { usleep(poll*1000); for(i=0; i<num_real_cpus; i+=j) { change = LOWER; /* handle SMT/CMP here */ for (j=0; j<cpu[i].threads_per_core; j++) { change2 = decide_speed(&cpu[i+j]); if (change2 > change) change = change2; } if (change != SAME) change_speed(&cpu[i], change); } } out: printf("PowerNowd encountered and error and could not start.\n"); printf("Please make sure that:\n"); printf(" - You are running a v2.6.7 kernel or later\n"); printf(" - That you have sysfs mounted /sys\n"); printf(" - That you have the core cpufreq and cpufreq-userspace\n"); printf(" modules loaded into your kernel\n"); printf(" - That you have the cpufreq driver for your cpu loaded,\n"); printf(" and that it works. (check dmesg for errors)\n"); printf("If all of the above are true, and you still have problems,\n"); printf("please email the author: [EMAIL PROTECTED]"); /* should free more here.. will get to that later.... */ /* or we can just be lazy and let the OS do it for us... */ free(cpu); return err; }