[PATCH 11/11] cpu/cpufreq: Only run performance tests on master threads

Jeremy Kerr jk at ozlabs.org
Thu May 21 09:34:27 UTC 2015


On a (single-socket) openpower machine, the cpufreq tests take nearly an
hour:

  $ time sudo ./src/fwts cpufreq
  Running 1 tests, results appended to results.log
  Test: CPU frequency scaling tests.
    CPU frequency performance tests.                        1 passed

  real	58m43.334s
  user	58m40.118s
  sys	0m0.366s

This is because we have 44 possible frequencies:

  $ wc -w scaling_available_frequencies
  44 scaling_available_frequencies

on 80 cpus:

  $ getconf _NPROCESSORS_ONLN
  80

That's a total of 3520 individual benchmarks, at one second per test.

However, those 80 cpus that linux reports are acually threads: 8 threads
per core, on a 10 core system. Because each of these threads is on the
same core, they share the same cpufreq control:

  $ ls -ld cpu{0..7}/cpufreq
  drwxr-xr-x 3 root root 0 May 21 03:06 cpu0/cpufreq
  lrwxrwxrwx 1 root root 0 May 21 01:29 cpu1/cpufreq -> ../cpu0/cpufreq
  lrwxrwxrwx 1 root root 0 May 21 01:29 cpu2/cpufreq -> ../cpu0/cpufreq
  lrwxrwxrwx 1 root root 0 May 21 01:29 cpu3/cpufreq -> ../cpu0/cpufreq
  lrwxrwxrwx 1 root root 0 May 21 01:29 cpu4/cpufreq -> ../cpu0/cpufreq
  lrwxrwxrwx 1 root root 0 May 21 01:29 cpu5/cpufreq -> ../cpu0/cpufreq
  lrwxrwxrwx 1 root root 0 May 21 01:29 cpu6/cpufreq -> ../cpu0/cpufreq
  lrwxrwxrwx 1 root root 0 May 21 01:29 cpu7/cpufreq -> ../cpu0/cpufreq

So, rather than running the exact same test 8 times over on each core,
this change only runs the cpufreq test on the 'master' threads.

Signed-off-by: Jeremy Kerr <jk at ozlabs.org>

---
 src/cpu/cpufreq/cpufreq.c |   43 +++++++++++++++++++++++++++-----------
 1 file changed, 31 insertions(+), 12 deletions(-)

diff --git a/src/cpu/cpufreq/cpufreq.c b/src/cpu/cpufreq/cpufreq.c
index e409375..c6d6a9d 100644
--- a/src/cpu/cpufreq/cpufreq.c
+++ b/src/cpu/cpufreq/cpufreq.c
@@ -29,6 +29,7 @@
 #include <stdbool.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <limits.h>
 #include <dirent.h>
 #include <stdint.h>
@@ -52,6 +53,7 @@ struct cpu {
 	int		idx;
 	char		sysfs_path[PATH_MAX];
 	bool		online;
+	bool		master;
 
 	int		n_freqs;
 	fwts_cpu_freq	freqs[MAX_FREQS];
@@ -79,8 +81,10 @@ static inline void cpu_mkpath(
 	const struct cpu *cpu,
 	const char *const name)
 {
-	snprintf(path, len, "%s/%s/cpufreq/%s", FWTS_CPU_PATH,
-			cpu->sysfs_path, name);
+	snprintf(path, len, "%s/%s/cpufreq%s%s", FWTS_CPU_PATH,
+			cpu->sysfs_path,
+			name ? "/" : "",
+			name ?: "");
 }
 
 static int cpu_set_governor(fwts_framework *fw, struct cpu *cpu,
@@ -348,15 +352,16 @@ static int test_one_cpu_performance(fwts_framework *fw, struct cpu *cpu,
 
 static int cpufreq_test_cpu_performance(fwts_framework *fw)
 {
-	int n_online_cpus, i, c, rc;
+	int n_master_cpus, i, c, rc;
 	bool ok = true;
 
-	n_online_cpus = 0;
+	n_master_cpus = 0;
 
 
 	for (i = 0; cpufreq_settable && i < num_cpus; i++) {
-		if (cpus[i].online)
-			n_online_cpus++;
+		if (!(cpus[i].online && cpus[i].master))
+			continue;
+		n_master_cpus++;
 		rc = cpu_set_lowest_frequency(fw, &cpus[i]);
 		if (rc != FWTS_OK)
 			cpufreq_settable = false;
@@ -371,10 +376,10 @@ static int cpufreq_test_cpu_performance(fwts_framework *fw)
 
 	/* then do the benchmark */
 	for (i = 0, c = 0; i < num_cpus; i++) {
-		if (!cpus[i].online)
+		if (!(cpus[i].online && cpus[i].master))
 			continue;
 
-		rc = test_one_cpu_performance(fw, &cpus[i], c++, n_online_cpus);
+		rc = test_one_cpu_performance(fw, &cpus[i], c++, n_master_cpus);
 		if (rc != FWTS_OK)
 			ok = false;
 
@@ -738,15 +743,29 @@ static int cpu_freq_compare(const void *v1, const void *v2)
 	return f1->Hz - f2->Hz;
 }
 
-static int parse_cpu_info(struct cpu *cpu, struct dirent *dir)
+static int parse_cpu_info(fwts_framework *fw,
+		struct cpu *cpu, struct dirent *dir)
 {
 	char *end, path[PATH_MAX+1], *str, *tmp, *tok;
-	int i;
+	struct stat statbuf;
+	int i, rc;
 
 	strcpy(cpu->sysfs_path, dir->d_name);
 	cpu->idx = strtoul(cpu->sysfs_path + strlen("cpu"), &end, 10);
 	cpu->online = true;
 
+	/* check if this is the master of a group of CPUs; we only
+	 * need to do perf checks on those that are the master */
+	cpu_mkpath(path, sizeof(path), cpu, NULL);
+	rc = lstat(path, &statbuf);
+	if (rc) {
+		fwts_log_warning(fw, "Can't stat cpufreq info!");
+		return FWTS_ERROR;
+	}
+
+	/* non-master CPUs will have a link, not a dir */
+	cpu->master = S_ISDIR(statbuf.st_mode);
+
 	cpu_mkpath(path, sizeof(path), cpu, "scaling_governor");
 	cpu->orig_governor = fwts_get(path);
 
@@ -785,7 +804,7 @@ static int is_cpu_dir(const struct dirent *dir)
 		isdigit(dir->d_name[3]);
 }
 
-static int cpufreq_init(fwts_framework *fw __attribute__((unused)))
+static int cpufreq_init(fwts_framework *fw)
 {
 	struct dirent **dirs;
 	int i, rc;
@@ -794,7 +813,7 @@ static int cpufreq_init(fwts_framework *fw __attribute__((unused)))
 	cpus = calloc(num_cpus, sizeof(*cpus));
 
 	for (i = 0; i < num_cpus; i++)
-		parse_cpu_info(&cpus[i], dirs[i]);
+		parse_cpu_info(fw, &cpus[i], dirs[i]);
 
 	/* all test require a userspace governor */
 	for (i = 0; i < num_cpus; i++) {



More information about the fwts-devel mailing list