[PATCH] cpu: cpufreq: check CPU freq max limits (LP: #1253047)

Colin King colin.king at canonical.com
Wed Nov 20 14:46:41 UTC 2013


From: Colin Ian King <colin.king at canonical.com>

This patch adds more checking to see if the CPU frequencies have
not been limited by users tweaking scaling_max_freq or the
firmware has a low bios_limit setting.

The patch also tidies up the code and now consitently uses uint32_t
for CPU frequencies.

Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 src/cpu/cpufreq/cpufreq.c | 98 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 75 insertions(+), 23 deletions(-)

diff --git a/src/cpu/cpufreq/cpufreq.c b/src/cpu/cpufreq/cpufreq.c
index f22205c..8c6d16c 100644
--- a/src/cpu/cpufreq/cpufreq.c
+++ b/src/cpu/cpufreq/cpufreq.c
@@ -31,6 +31,7 @@
 #include <limits.h>
 #include <dirent.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <sched.h>
 #include <time.h>
 #include <math.h>
@@ -57,8 +58,11 @@ static int num_cpus;
 #define GET_PERFORMANCE_MIN (1)
 #define GET_PERFORMANCE_AVG (2)
 
-static void cpu_mkpath(char *path, const int len,
-	const int cpu, const char *name)
+static void cpu_mkpath(
+	char *const path,
+	const int len,
+	const int cpu,
+	const char *const name)
 {
 	snprintf(path, len, "%s/cpu%i/cpufreq/%s", FWTS_CPU_PATH, cpu, name);
 }
@@ -87,7 +91,7 @@ static void set_governor(fwts_framework *fw, const int cpu)
 
 	if (fwts_set("userspace", path) != FWTS_OK) {
 		if (!no_cpufreq) {
-			fwts_log_warning(fw,
+			fwts_warning(fw,
 				"Frequency scaling not supported.");
 			no_cpufreq = 1;
 		}
@@ -95,7 +99,7 @@ static void set_governor(fwts_framework *fw, const int cpu)
 }
 
 #ifdef FWTS_ARCH_INTEL
-static int cpu_exists(int cpu)
+static int cpu_exists(const int cpu)
 {
 	char path[PATH_MAX];
 
@@ -104,7 +108,7 @@ static int cpu_exists(int cpu)
 }
 #endif
 
-static void set_HZ(fwts_framework *fw, const int cpu, const unsigned long Hz)
+static void set_HZ(fwts_framework *fw, const int cpu, const uint32_t Hz)
 {
 	cpu_set_t mask, oldset;
 	char path[PATH_MAX];
@@ -122,7 +126,7 @@ static void set_HZ(fwts_framework *fw, const int cpu, const unsigned long Hz)
 
 	/* then set the speed */
 	cpu_mkpath(path, sizeof(path), cpu, "scaling_setspeed");
-	snprintf(buffer, sizeof(buffer), "%lu", Hz);
+	snprintf(buffer, sizeof(buffer), "%" PRIu32 , Hz);
 	fwts_set(buffer, path);
 
 	sched_setaffinity(0, sizeof(oldset), &oldset);
@@ -183,7 +187,7 @@ static int get_performance_repeat(
 }
 #endif
 
-static char *HzToHuman(unsigned long hz)
+static char *HzToHuman(const uint32_t hz)
 {
 	static char buffer[32];
 	unsigned long long Hz;
@@ -191,15 +195,15 @@ static char *HzToHuman(unsigned long hz)
 	Hz = hz;
 
 	if (Hz > 1500000) {
-		snprintf(buffer, sizeof(buffer), "%6.2f GHz",
+		snprintf(buffer, sizeof(buffer), "%.2f GHz",
 			(Hz+50000.0) / 1000000);
 		return buffer;
 	} else if (Hz > 1000) {
-		snprintf(buffer, sizeof(buffer), "%6lli MHz",
+		snprintf(buffer, sizeof(buffer), "%lli MHz",
 			(Hz+500) / 1000);
 		return buffer;
 	} else {
-		snprintf(buffer, sizeof(buffer), "%9lli", Hz);
+		snprintf(buffer, sizeof(buffer), "%lli", Hz);
 		return buffer;
 	}
 }
@@ -219,6 +223,21 @@ static uint32_t get_claimed_hz(const int cpu)
 	return value;
 }
 
+static uint32_t get_bios_limit(const int cpu)
+{
+	char path[PATH_MAX];
+	char *buffer;
+	uint32_t value = 0;
+
+	cpu_mkpath(path, sizeof(path), cpu, "bios_limit");
+
+	if ((buffer = fwts_get(path)) != NULL) {
+		value = strtoul(buffer, NULL, 10);
+		free(buffer);
+	}
+	return value;
+}
+
 static int cpu_freq_compare(const void *v1, const void *v2)
 {
 	const fwts_cpu_freq *cpu_freq1 = (fwts_cpu_freq *)v1;
@@ -227,7 +246,7 @@ static int cpu_freq_compare(const void *v1, const void *v2)
 	return cpu_freq1->Hz - cpu_freq2->Hz;
 }
 
-static void do_cpu(fwts_framework *fw, int cpu)
+static void do_cpu(fwts_framework *fw, const int cpu)
 {
 	char path[PATH_MAX];
 	char line[4096];
@@ -236,9 +255,13 @@ static void do_cpu(fwts_framework *fw, int cpu)
 	char *c, *c2;
 	int i;
 	int speedcount;
-	static int warned=0;
-	int warned_PSS = 0;
+	static int warned = 0;
+	bool warned_PSS = false;
 	uint64_t cpu_top_speed = 0;
+	int claimed_hz_too_low = 0;
+	int bios_limit_too_low = 0;
+	const uint32_t claimed_hz = get_claimed_hz(cpu);
+	const uint32_t bios_limit = get_bios_limit(cpu);
 
 	memset(freqs, 0, sizeof(freqs));
 	memset(line, 0, sizeof(line));
@@ -248,7 +271,7 @@ static void do_cpu(fwts_framework *fw, int cpu)
 	cpu_mkpath(path, sizeof(path), cpu, "scaling_available_frequencies");
 	if ((file = fopen(path, "r")) == NULL) {
 		if (!no_cpufreq) {
-			fwts_log_warning(fw, "Frequency scaling not supported.");
+			fwts_warning(fw, "Frequency scaling not supported.");
 			no_cpufreq = 1;
 		}
 		return;
@@ -260,7 +283,7 @@ static void do_cpu(fwts_framework *fw, int cpu)
 	fclose(file);
 
 	if (total_tests == 1)
-		total_tests = (2+count_ints(line)) *
+		total_tests = (2 + count_ints(line)) *
 			num_cpus + 2;
 
 	c = line;
@@ -276,6 +299,11 @@ static void do_cpu(fwts_framework *fw, int cpu)
 		freqs[i].Hz = strtoull(c, NULL, 10);
 		set_HZ(fw, cpu, freqs[i].Hz);
 
+		if ((claimed_hz != 0) && (claimed_hz < freqs[i].Hz))
+			claimed_hz_too_low++;
+		if ((bios_limit != 0) && (bios_limit < freqs[i].Hz))
+			bios_limit_too_low++;
+
 		if (fwts_cpu_performance(fw, cpu, &freqs[i].speed) != FWTS_OK) {
 			fwts_log_error(fw, "Failed to get CPU performance for "
 				"CPU frequency %" PRIu32 " Hz.", freqs[i].Hz);
@@ -295,11 +323,35 @@ static void do_cpu(fwts_framework *fw, int cpu)
 	if (cpu_top_speed > top_speed)
 		top_speed = cpu_top_speed;
 
+	if (claimed_hz_too_low) {
+		char path[PATH_MAX];
+
+		cpu_mkpath(path, sizeof(path), cpu, "scaling_max_freq");
+		fwts_warning(fw,
+			"There were %d CPU frequencies larger than the _PSS "
+			"maximum CPU frequency of %s for CPU %d. Has %s "
+			"been set too low?",
+			claimed_hz_too_low, HzToHuman(claimed_hz), cpu, path);
+	}
+
+	if (bios_limit_too_low) {
+		char path[PATH_MAX];
+
+		cpu_mkpath(path, sizeof(path), cpu, "bios_limit");
+		fwts_warning(fw,
+			"The CPU frequency BIOS limit %s for CPU %d was set to %s "
+			"which is lower than some of the ACPI scaling frequencies.",
+			path, cpu, HzToHuman(bios_limit));
+	}
+
+	if (claimed_hz_too_low || bios_limit_too_low)
+		fwts_log_nl(fw);
+
 	fwts_log_info(fw, "CPU %d: %i CPU frequency steps supported.", cpu, speedcount);
 	fwts_log_info_verbatum(fw, " Frequency | Relative Speed | Bogo loops");
 	fwts_log_info_verbatum(fw, "-----------+----------------+-----------");
 	for (i = 0; i < speedcount; i++)
-		fwts_log_info_verbatum(fw, "%9s |     %5.1f %%    | %9" PRIu64,
+		fwts_log_info_verbatum(fw, "%10s |     %5.1f %%    | %9" PRIu64,
 			HzToHuman(freqs[i].Hz),
 			100.0 * freqs[i].speed/cpu_top_speed,
 			freqs[i].speed);
@@ -314,7 +366,7 @@ static void do_cpu(fwts_framework *fw, int cpu)
 			"CPUFreqPStates",
 			"Not all processors support the same number of P states.");
 
-	if (speedcount<2)
+	if (speedcount < 2)
 		return;
 
 	/* Sort the frequencies */
@@ -335,11 +387,12 @@ static void do_cpu(fwts_framework *fw, int cpu)
 				HzToHuman(freqs[i+1].Hz), freqs[i+1].speed,
 				HzToHuman(freqs[i].Hz), freqs[i].speed,
 				cpu);
-		if (freqs[i].Hz > get_claimed_hz(cpu) && !warned_PSS) {
-			warned_PSS = 1;
+
+		if ((freqs[i].Hz > claimed_hz) && !warned_PSS) {
+			warned_PSS = true;
 			fwts_warning(fw, "Frequency %" PRIu32
 				" not achievable; _PSS limit of %" PRIu32 " in effect?",
-				freqs[i].Hz, get_claimed_hz(cpu));
+				freqs[i].Hz, claimed_hz);
 		}
 	}
 }
@@ -349,9 +402,8 @@ static void lowest_speed(fwts_framework *fw, const int cpu)
 {
 	char path[PATH_MAX];
 	char *line;
-	unsigned long Hz;
 	char *c, *c2;
-	unsigned long lowspeed=0;
+	uint32_t Hz, lowspeed = 0;
 
 	cpu_mkpath(path, sizeof(path), cpu, "scaling_available_frequencies");
 	if ((line = fwts_get(path)) == NULL)
@@ -705,7 +757,7 @@ static int cpufreq_test1(fwts_framework *fw)
 static int cpufreq_init(fwts_framework *fw)
 {
 	if ((num_cpus = fwts_cpu_enumerate()) == FWTS_ERROR) {
-		fwts_log_warning(fw, "Cannot determine number of CPUS, defaulting to 1.");
+		fwts_warning(fw, "Cannot determine number of CPUS, defaulting to 1.");
 		num_cpus = 1;
 	}
 	return FWTS_OK;
-- 
1.8.3.2




More information about the fwts-devel mailing list