Browse Source

Merge branch 'pm-tools'

* pm-tools:
  cpupower: IvyBridge (0x3a and 0x3e models) support
  cpupower: Provide -c param for cpupower monitor to schedule process on all cores
  cpupower tools: Fix warning and a bug with the cpu package count
  cpupower tools: Fix malloc of cpu_info structure
  cpupower tools: Fix issues with sysfs_topology_read_file
  cpupower tools: Fix minor warnings
  cpupower tools: Update .gitignore for files created in the debug directories
  cpupower tools: Remove brace expansion from clean target
Rafael J. Wysocki 12 years ago
parent
commit
ad063fbbdd

+ 7 - 0
tools/power/cpupower/.gitignore

@@ -20,3 +20,10 @@ utils/cpufreq-set.o
 utils/cpufreq-aperf.o
 cpupower
 bench/cpufreq-bench
+debug/kernel/Module.symvers
+debug/i386/centrino-decode
+debug/i386/dump_psb
+debug/i386/intel_gsic
+debug/i386/powernow-k8-decode
+debug/x86_64/centrino-decode
+debug/x86_64/powernow-k8-decode

+ 2 - 1
tools/power/cpupower/Makefile

@@ -253,7 +253,8 @@ clean:
 	 | xargs rm -f
 	-rm -f $(OUTPUT)cpupower
 	-rm -f $(OUTPUT)libcpupower.so*
-	-rm -rf $(OUTPUT)po/*.{gmo,pot}
+	-rm -rf $(OUTPUT)po/*.gmo
+	-rm -rf $(OUTPUT)po/*.pot
 	$(MAKE) -C bench O=$(OUTPUT) clean
 
 

+ 4 - 1
tools/power/cpupower/debug/i386/Makefile

@@ -26,7 +26,10 @@ $(OUTPUT)powernow-k8-decode: powernow-k8-decode.c
 all: $(OUTPUT)centrino-decode $(OUTPUT)dump_psb $(OUTPUT)intel_gsic $(OUTPUT)powernow-k8-decode
 
 clean:
-	rm -rf $(OUTPUT){centrino-decode,dump_psb,intel_gsic,powernow-k8-decode}
+	rm -rf $(OUTPUT)centrino-decode
+	rm -rf $(OUTPUT)dump_psb
+	rm -rf $(OUTPUT)intel_gsic
+	rm -rf $(OUTPUT)powernow-k8-decode
 
 install:
 	$(INSTALL) -d $(DESTDIR)${bindir}

+ 13 - 2
tools/power/cpupower/man/cpupower-monitor.1

@@ -7,11 +7,11 @@ cpupower\-monitor \- Report processor frequency and idle statistics
 .RB "\-l"
 
 .B cpupower monitor
-.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
+.RB [ -c ] [ "\-m <mon1>," [ "<mon2>,..." ] ]
 .RB [ "\-i seconds" ]
 .br
 .B cpupower monitor
-.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
+.RB [ -c ][ "\-m <mon1>," [ "<mon2>,..." ] ]
 .RB command
 .br
 .SH DESCRIPTION
@@ -64,6 +64,17 @@ Only display specific monitors. Use the monitor string(s) provided by \-l option
 Measure intervall.
 .RE
 .PP
+\-c
+.RS 4
+Schedule the process on every core before starting and ending measuring.
+This could be needed for the Idle_Stats monitor when no other MSR based
+monitor (has to be run on the core that is measured) is run in parallel.
+This is to wake up the processors from deeper sleep states and let the
+kernel re
+-account its cpuidle (C-state) information before reading the
+cpuidle timings from sysfs.
+.RE
+.PP
 command
 .RS 4
 Measure idle and frequency characteristics of an arbitrary command/workload.

+ 2 - 0
tools/power/cpupower/utils/helpers/cpuid.c

@@ -158,6 +158,8 @@ out:
 				cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
 			case 0x2A:	/* SNB */
 			case 0x2D:	/* SNB Xeon */
+			case 0x3A:	/* IVB */
+			case 0x3E:	/* IVB Xeon */
 				cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
 				cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
 				break;

+ 10 - 8
tools/power/cpupower/utils/helpers/helpers.h

@@ -92,6 +92,14 @@ extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info);
 extern struct cpupower_cpu_info cpupower_cpu_info;
 /* cpuid and cpuinfo helpers  **************************/
 
+struct cpuid_core_info {
+	int pkg;
+	int core;
+	int cpu;
+
+	/* flags */
+	unsigned int is_online:1;
+};
 
 /* CPU topology/hierarchy parsing ******************/
 struct cpupower_topology {
@@ -101,18 +109,12 @@ struct cpupower_topology {
 	unsigned int threads; /* per core */
 
 	/* Array gets mallocated with cores entries, holding per core info */
-	struct {
-		int pkg;
-		int core;
-		int cpu;
-
-		/* flags */
-		unsigned int is_online:1;
-	} *core_info;
+	struct cpuid_core_info *core_info;
 };
 
 extern int get_cpu_topology(struct cpupower_topology *cpu_top);
 extern void cpu_topology_release(struct cpupower_topology cpu_top);
+
 /* CPU topology/hierarchy parsing ******************/
 
 /* X86 ONLY ****************************************/

+ 0 - 19
tools/power/cpupower/utils/helpers/sysfs.c

@@ -37,25 +37,6 @@ unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
 	return (unsigned int) numread;
 }
 
-static unsigned int sysfs_write_file(const char *path,
-				     const char *value, size_t len)
-{
-	int fd;
-	ssize_t numwrite;
-
-	fd = open(path, O_WRONLY);
-	if (fd == -1)
-		return 0;
-
-	numwrite = write(fd, value, len);
-	if (numwrite < 1) {
-		close(fd);
-		return 0;
-	}
-	close(fd);
-	return (unsigned int) numwrite;
-}
-
 /*
  * Detect whether a CPU is online
  *

+ 29 - 24
tools/power/cpupower/utils/helpers/topology.c

@@ -20,9 +20,8 @@
 #include <helpers/sysfs.h>
 
 /* returns -1 on failure, 0 on success */
-int sysfs_topology_read_file(unsigned int cpu, const char *fname)
+static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result)
 {
-	unsigned long value;
 	char linebuf[MAX_LINE_LEN];
 	char *endp;
 	char path[SYSFS_PATH_MAX];
@@ -31,20 +30,12 @@ int sysfs_topology_read_file(unsigned int cpu, const char *fname)
 			 cpu, fname);
 	if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
 		return -1;
-	value = strtoul(linebuf, &endp, 0);
+	*result = strtol(linebuf, &endp, 0);
 	if (endp == linebuf || errno == ERANGE)
 		return -1;
-	return value;
+	return 0;
 }
 
-struct cpuid_core_info {
-	unsigned int pkg;
-	unsigned int thread;
-	unsigned int cpu;
-	/* flags */
-	unsigned int is_online:1;
-};
-
 static int __compare(const void *t1, const void *t2)
 {
 	struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
@@ -53,9 +44,9 @@ static int __compare(const void *t1, const void *t2)
 		return -1;
 	else if (top1->pkg > top2->pkg)
 		return 1;
-	else if (top1->thread < top2->thread)
+	else if (top1->core < top2->core)
 		return -1;
-	else if (top1->thread > top2->thread)
+	else if (top1->core > top2->core)
 		return 1;
 	else if (top1->cpu < top2->cpu)
 		return -1;
@@ -73,28 +64,42 @@ static int __compare(const void *t1, const void *t2)
  */
 int get_cpu_topology(struct cpupower_topology *cpu_top)
 {
-	int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF);
+	int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
 
-	cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus);
+	cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
 	if (cpu_top->core_info == NULL)
 		return -ENOMEM;
 	cpu_top->pkgs = cpu_top->cores = 0;
 	for (cpu = 0; cpu < cpus; cpu++) {
 		cpu_top->core_info[cpu].cpu = cpu;
 		cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
-		cpu_top->core_info[cpu].pkg =
-			sysfs_topology_read_file(cpu, "physical_package_id");
-		if ((int)cpu_top->core_info[cpu].pkg != -1 &&
-		    cpu_top->core_info[cpu].pkg > cpu_top->pkgs)
-			cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
-		cpu_top->core_info[cpu].core =
-			sysfs_topology_read_file(cpu, "core_id");
+		if(sysfs_topology_read_file(
+			cpu,
+			"physical_package_id",
+			&(cpu_top->core_info[cpu].pkg)) < 0)
+			return -1;
+		if(sysfs_topology_read_file(
+			cpu,
+			"core_id",
+			&(cpu_top->core_info[cpu].core)) < 0)
+			return -1;
 	}
-	cpu_top->pkgs++;
 
 	qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
 	      __compare);
 
+	/* Count the number of distinct pkgs values. This works
+	   because the primary sort of the core_info struct was just
+	   done by pkg value. */
+	last_pkg = cpu_top->core_info[0].pkg;
+	for(cpu = 1; cpu < cpus; cpu++) {
+		if(cpu_top->core_info[cpu].pkg != last_pkg) {
+			last_pkg = cpu_top->core_info[cpu].pkg;
+			cpu_top->pkgs++;
+		}
+	}
+	cpu_top->pkgs++;
+
 	/* Intel's cores count is not consecutively numbered, there may
 	 * be a core_id of 3, but none of 2. Assume there always is 0
 	 * Get amount of cores by counting duplicates in a package

+ 18 - 3
tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c

@@ -39,6 +39,7 @@ static int mode;
 static int interval = 1;
 static char *show_monitors_param;
 static struct cpupower_topology cpu_top;
+static unsigned int wake_cpus;
 
 /* ToDo: Document this in the manpage */
 static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
@@ -84,7 +85,7 @@ int fill_string_with_spaces(char *s, int n)
 void print_header(int topology_depth)
 {
 	int unsigned mon;
-	int state, need_len, pr_mon_len;
+	int state, need_len;
 	cstate_t s;
 	char buf[128] = "";
 	int percent_width = 4;
@@ -93,7 +94,6 @@ void print_header(int topology_depth)
 	printf("%s|", buf);
 
 	for (mon = 0; mon < avail_monitors; mon++) {
-		pr_mon_len = 0;
 		need_len = monitors[mon]->hw_states_num * (percent_width + 3)
 			- 1;
 		if (mon != 0) {
@@ -315,16 +315,28 @@ int fork_it(char **argv)
 int do_interval_measure(int i)
 {
 	unsigned int num;
+	int cpu;
+
+	if (wake_cpus)
+		for (cpu = 0; cpu < cpu_count; cpu++)
+			bind_cpu(cpu);
 
 	for (num = 0; num < avail_monitors; num++) {
 		dprint("HW C-state residency monitor: %s - States: %d\n",
 		       monitors[num]->name, monitors[num]->hw_states_num);
 		monitors[num]->start();
 	}
+
 	sleep(i);
+
+	if (wake_cpus)
+		for (cpu = 0; cpu < cpu_count; cpu++)
+			bind_cpu(cpu);
+
 	for (num = 0; num < avail_monitors; num++)
 		monitors[num]->stop();
 
+
 	return 0;
 }
 
@@ -333,7 +345,7 @@ static void cmdline(int argc, char *argv[])
 	int opt;
 	progname = basename(argv[0]);
 
-	while ((opt = getopt(argc, argv, "+li:m:")) != -1) {
+	while ((opt = getopt(argc, argv, "+lci:m:")) != -1) {
 		switch (opt) {
 		case 'l':
 			if (mode)
@@ -352,6 +364,9 @@ static void cmdline(int argc, char *argv[])
 			mode = show;
 			show_monitors_param = optarg;
 			break;
+		case 'c':
+			wake_cpus = 1;
+			break;
 		default:
 			print_wrong_arg_exit();
 		}

+ 17 - 0
tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h

@@ -65,4 +65,21 @@ extern long long timespec_diff_us(struct timespec start, struct timespec end);
 				"could be inaccurate\n"), mes, ov);		\
 }
 
+
+/* Taken over from x86info project sources  -> return 0 on success */
+#include <sched.h>
+#include <sys/types.h>
+#include <unistd.h>
+static inline int bind_cpu(int cpu)
+{
+	cpu_set_t set;
+
+	if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) {
+		CPU_ZERO(&set);
+		CPU_SET(cpu, &set);
+		return sched_setaffinity(getpid(), sizeof(set), &set);
+	}
+	return 1;
+}
+
 #endif /* __CPUIDLE_INFO_HW__ */

+ 8 - 2
tools/power/cpupower/utils/idle_monitor/snb_idle.c

@@ -150,9 +150,15 @@ static struct cpuidle_monitor *snb_register(void)
 	    || cpupower_cpu_info.family != 6)
 		return NULL;
 
-	if (cpupower_cpu_info.model != 0x2A
-	    && cpupower_cpu_info.model != 0x2D)
+	switch (cpupower_cpu_info.model) {
+	case 0x2A: /* SNB */
+	case 0x2D: /* SNB Xeon */
+	case 0x3A: /* IVB */
+	case 0x3E: /* IVB Xeon */
+		break;
+	default:
 		return NULL;
+	}
 
 	is_valid = calloc(cpu_count, sizeof(int));
 	for (num = 0; num < SNB_CSTATE_COUNT; num++) {