[PATCH/RFC] powertop non-ACPI: use CPUidle for C-state details

Pallipadi, Venkatesh venkatesh.pallipadi at intel.com
Thu Jan 31 15:06:47 PST 2008



Nice timing for the patch. I am working on cpuidle patches that will add
things like
C1 idle residency time in /sysfs and was asking Arjan about switching
powertop to
use cpuidle interfaces :-).

One major comment is that with the patch C-state timing in powertop
seems to be off,
Due to different units of time in /proc/acpi and sysfs cpuidle.
/proc/acpi C-state
timings are in ACPI PM timer ticks and cpuidle exports it in
micro-seconds.

Thanks,
Venki

>-----Original Message-----
>From: Kevin Hilman [mailto:khilman at mvista.com] 
>Sent: Thursday, January 31, 2008 10:31 AM
>To: power at bughost.org
>Cc: Adam Belay; Pallipadi, Venkatesh
>Subject: [PATCH/RFC] powertop non-ACPI: use CPUidle for C-state details
>
>[ resend to power at bughost.org instead of discuss at lesswatts.org ]
>
>On systems without ACPI, query the CPUidle sysfs interface for C-state
>usage/duration 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 at mvista.com>
>
>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;
>



More information about the Power mailing list