On systems without ACPI, query the CPUidle sysfs interface for C-state details. It uses the CPUIdle stateN/usage and stateN/time files for the 'usage' and 'duration' values used for calculations in powertop. For now, if both ACPI and CPUidle are present, it will read data from the ACPI /proc interface instead of CPUidle, but if ACPI is not present, it will fallback to CPUidle. Tested against a CPUidle enabled 2.6.24 non-x86 kernel (TI OMAP3.) Patch against powertop-1.9. Signed-off-by: Kevin Hilman <khilman@xxxxxxxxxx> diff -ruN powertop-1.9/powertop.c powertop-1.9-KJH/powertop.c --- powertop-1.9/powertop.c 2008-01-30 17:24:27.000000000 -0800 +++ powertop-1.9-KJH/powertop.c 2008-01-30 21:02:54.000000000 -0800 @@ -35,6 +35,7 @@ #include <assert.h> #include <locale.h> #include <time.h> +#include <sys/stat.h> #include "powertop.h" @@ -236,7 +237,7 @@ fclose(file); } -static void read_data(uint64_t * usage, uint64_t * duration) +static void read_data_acpi(uint64_t * usage, uint64_t * duration) { DIR *dir; struct dirent *entry; @@ -286,6 +287,97 @@ closedir(dir); } +static void read_data_cpuidle(uint64_t * usage, uint64_t * duration) +{ + DIR *dir; + struct dirent *entry; + FILE *file = NULL; + char line[4096]; + char filename[128], *f; + int len, clevel = 0; + + memset(usage, 0, 64); + memset(duration, 0, 64); + + dir = opendir("/sys/devices/system/cpu"); + if (!dir) + return; + + /* Loop over cpuN entries */ + while ((entry = readdir(dir))) { + if (strlen(entry->d_name) < 3) + continue; + + if (!isdigit(entry->d_name[3])) + continue; + + len = sprintf(filename, "/sys/devices/system/cpu/%s/cpuidle", + entry->d_name); + + dir = opendir(filename); + if (!dir) + return; + + /* For each C-state, there is a stateX directory which + * contains a 'usage' and a 'time' (duration) file */ + while ((entry = readdir(dir))) { + if (strlen(entry->d_name) < 3) + continue; + sprintf(filename + len, "/%s/usage", entry->d_name); + file = fopen(filename, "r"); + if (!file) + continue; + + memset(line, 0, 4096); + f = fgets(line, 4096, file); + fclose(file); + if (f == NULL) + break; + + usage[clevel] += 1+strtoull(line, NULL, 10); + + sprintf(filename + len, "/%s/time", entry->d_name); + file = fopen(filename, "r"); + if (!file) + continue; + + memset(line, 0, 4096); + f = fgets(line, 4096, file); + fclose(file); + if (f == NULL) + break; + + duration[clevel] += 1+strtoull(line, NULL, 10); + + clevel++; + if (clevel > maxcstate) + maxcstate = clevel; + + } + + } + closedir(dir); +} + +static void read_data(uint64_t * usage, uint64_t * duration) +{ + int r; + struct stat s; + + /* First, check for ACPI */ + r = stat("/proc/acpi/processor", &s); + if (!r) { + read_data_acpi(usage, duration); + return; + } + + /* Then check for CPUidle */ + r = stat("/sys/devices/system/cpu/cpuidle", &s); + if (!r) { + read_data_cpuidle(usage, duration); + } +} + void stop_timerstats(void) { FILE *file; @@ -530,7 +622,7 @@ memset(&cstate_lines, 0, sizeof(cstate_lines)); topcstate = -4; if (totalevents == 0 && maxcstate <= 1) { - sprintf(cstate_lines[5],_("< Detailed C-state information is only available on Mobile CPUs (laptops) >\n")); + sprintf(cstate_lines[5],_("< Detailed C-state information is not available.>\n")); } else { double sleept, percentage;; c0 = sysconf(_SC_NPROCESSORS_ONLN) * ticktime * 1000 * FREQ - totalticks; - To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html