[PATCH 01/11] cpu/cpufreq: Don't reparse cpu information
Jeremy Kerr
jk at ozlabs.org
Thu May 21 09:34:27 UTC 2015
Currently, we do a whole lot of scanning the /sys/devices/system/cpu
directory to parse cpu information, multiple times.
This change does a parse once on ->init, and populates a structure of
cpu info. The tests then query this structure instead of reparsing /sys.
We remove the unnecessary sched_setaffinity when we change a core's
cpu_frequency.
Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
---
src/cpu/cpufreq/cpufreq.c | 561 +++++++++++++++-----------------------
1 file changed, 226 insertions(+), 335 deletions(-)
diff --git a/src/cpu/cpufreq/cpufreq.c b/src/cpu/cpufreq/cpufreq.c
index ff3d112..9315d18 100644
--- a/src/cpu/cpufreq/cpufreq.c
+++ b/src/cpu/cpufreq/cpufreq.c
@@ -48,17 +48,32 @@ typedef struct {
uint64_t speed;
} fwts_cpu_freq;
+struct cpu {
+ int idx;
+ char sysfs_path[PATH_MAX];
+ bool online;
+
+ int n_freqs;
+ fwts_cpu_freq freqs[MAX_FREQS];
+
+ /* saved state */
+ char *orig_governor;
+ uint64_t orig_frequency;
+};
+
+static struct cpu *cpus;
+static int num_cpus;
static int number_of_speeds = -1;
static int total_tests = 1;
static int performed_tests = 0;
static bool no_cpufreq = false;
static uint64_t top_speed = 0;
-static int num_cpus;
#define GET_PERFORMANCE_MAX (0)
#define GET_PERFORMANCE_MIN (1)
#define GET_PERFORMANCE_AVG (2)
+
#define MAX_ABSOLUTE_ERROR 20.0 /* In Hz */
#define MAX_RELATIVE_ERROR 0.0025 /* as fraction */
@@ -90,65 +105,56 @@ static int hz_almost_equal(const uint64_t a, const uint64_t b)
static inline void cpu_mkpath(
char *const path,
const int len,
- const int cpu,
+ const struct cpu *cpu,
const char *const name)
{
- snprintf(path, len, "%s/cpu%i/cpufreq/%s", FWTS_CPU_PATH, cpu, name);
+ snprintf(path, len, "%s/%s/cpufreq/%s", FWTS_CPU_PATH,
+ cpu->sysfs_path, name);
}
-static void set_governor(fwts_framework *fw, const int cpu)
+static void cpu_set_governor(fwts_framework *fw, struct cpu *cpu,
+ const char *governor)
{
char path[PATH_MAX];
+ int rc;
cpu_mkpath(path, sizeof(path), cpu, "scaling_governor");
-
- if (fwts_set("userspace", path) != FWTS_OK) {
- if (!no_cpufreq) {
- fwts_warning(fw,
- "Cannot set CPU scaling governor to userspace scaling.");
- no_cpufreq = true;
- }
+ rc = fwts_set(governor, path);
+ if (rc != FWTS_OK && !no_cpufreq) {
+ fwts_warning(fw, "Cannot set CPU governor to %s.", governor);
+ no_cpufreq = true;
}
}
-#ifdef FWTS_ARCH_INTEL
-static int cpu_exists(const int cpu)
+static void cpu_set_frequency(fwts_framework *fw, struct cpu *cpu,
+ uint64_t freq_hz)
{
char path[PATH_MAX];
+ char buffer[64];
+ int rc;
- cpu_mkpath(path, sizeof(path), cpu, "scaling_governor");
- return !access(path, R_OK);
+ cpu_mkpath(path, sizeof(path), cpu, "scaling_setspeed");
+ snprintf(buffer, sizeof(buffer), "%" PRIu64 , freq_hz);
+ rc = fwts_set(buffer, path);
+ if (rc != FWTS_OK)
+ fwts_warning(fw, "Cannot set CPU frequency to %s.", buffer);
}
-#endif
-static void set_HZ(fwts_framework *fw, const int cpu, const uint64_t Hz)
+static void cpu_set_lowest_frequency(fwts_framework *fw, struct cpu *cpu)
{
- cpu_set_t mask, oldset;
- char path[PATH_MAX];
- char buffer[64];
-
- /* First, go to the right cpu */
-
- sched_getaffinity(0, sizeof(oldset), &oldset);
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
- sched_setaffinity(0, sizeof(mask), &mask);
-
- set_governor(fw, cpu);
-
- /* then set the speed */
- cpu_mkpath(path, sizeof(path), cpu, "scaling_setspeed");
- snprintf(buffer, sizeof(buffer), "%" PRIu64 , Hz);
- fwts_set(buffer, path);
+ cpu_set_frequency(fw, cpu, cpu->freqs[0].Hz);
+}
- sched_setaffinity(0, sizeof(oldset), &oldset);
+static void cpu_set_highest_frequency(fwts_framework *fw, struct cpu *cpu)
+{
+ cpu_set_frequency(fw, cpu, cpu->freqs[cpu->n_freqs-1].Hz);
}
+
#ifdef FWTS_ARCH_INTEL
static int get_performance_repeat(
fwts_framework *fw,
- const int cpu,
+ struct cpu *cpu,
const int count,
const int type,
uint64_t *retval)
@@ -163,7 +169,7 @@ static int get_performance_repeat(
for (i = 0; i < count; i++) {
uint64_t temp;
- if (fwts_cpu_performance(fw, cpu, &temp) != FWTS_OK)
+ if (fwts_cpu_performance(fw, cpu->idx, &temp) != FWTS_OK)
return FWTS_ERROR;
if (temp) {
@@ -217,7 +223,7 @@ static char *hz_to_human(const uint64_t hz)
}
}
-static uint64_t get_claimed_hz(const int cpu)
+static uint64_t get_claimed_hz(struct cpu *cpu)
{
char path[PATH_MAX];
char *buffer;
@@ -232,7 +238,7 @@ static uint64_t get_claimed_hz(const int cpu)
return value;
}
-static uint64_t get_bios_limit(const int cpu)
+static uint64_t get_bios_limit(struct cpu *cpu)
{
char path[PATH_MAX];
char *buffer;
@@ -247,71 +253,20 @@ static uint64_t get_bios_limit(const int cpu)
return value;
}
-static int cpu_freq_compare(const void *v1, const void *v2)
+static void do_cpu(fwts_framework *fw, struct cpu *cpu)
{
- const fwts_cpu_freq *cpu_freq1 = (fwts_cpu_freq *)v1;
- const fwts_cpu_freq *cpu_freq2 = (fwts_cpu_freq *)v2;
-
- /*
- * Some _PSS states can be the same or very nearly
- * the same when Turbo mode is available,
- * so if they are we also differentiate the two by
- * the speed to get a fully sorted ordering
- */
- if (hz_almost_equal(cpu_freq1->Hz, cpu_freq2->Hz))
- return cpu_freq1->speed - cpu_freq2->speed;
- else
- return cpu_freq1->Hz - cpu_freq2->Hz;
-}
-
-static int read_freqs_available(const int cpu, fwts_cpu_freq *freqs)
-{
- char path[PATH_MAX];
- char line[4096];
- FILE *file;
- char *c, *c2;
- int i = 0;
-
- memset(line, 0, sizeof(line));
- cpu_mkpath(path, sizeof(path), cpu, "scaling_available_frequencies");
- if ((file = fopen(path, "r")) == NULL)
- return 0;
- c = fgets(line, 4095, file);
- fclose(file);
- if (!c)
- return 0;
-
- while ((i < MAX_FREQS) && c && strlen(c) > 1) {
- c2 = strchr(c, ' ');
- if (c2) {
- *c2 = 0;
- c2++;
- } else
- c2 = NULL;
-
- freqs[i].Hz = strtoull(c, NULL, 10);
- c = c2;
- i++;
- }
- return i;
-}
-
-static void do_cpu(fwts_framework *fw, const int cpu)
-{
- fwts_cpu_freq freqs[MAX_FREQS];
- int i, speedcount;
+ int i;
static int warned = 0;
bool warned_PSS = false;
- uint64_t cpu_top_speed = 1;
+ uint64_t cpu_top_perf = 0;
int claimed_hz_too_low = 0;
int bios_limit_too_low = 0;
const uint64_t claimed_hz = get_claimed_hz(cpu);
const uint64_t bios_limit = get_bios_limit(cpu);
- memset(freqs, 0, sizeof(freqs));
- set_governor(fw, cpu);
+ cpu_set_governor(fw, cpu, "userspace");
- if ((speedcount = read_freqs_available(cpu, freqs)) == 0) {
+ if (cpu->n_freqs == 0) {
if (!no_cpufreq) {
char path[PATH_MAX];
char *driver;
@@ -330,30 +285,32 @@ static void do_cpu(fwts_framework *fw, const int cpu)
return;
}
if (total_tests == 1)
- total_tests = ((2 + speedcount) * num_cpus) + 4;
+ total_tests = ((2 + cpu->n_freqs) * num_cpus) + 2;
- for (i = 0; i < speedcount; i++) {
- set_HZ(fw, cpu, freqs[i].Hz);
+ for (i = 0; i < cpu->n_freqs; i++) {
+ cpu_set_frequency(fw, cpu, cpu->freqs[i].Hz);
- if ((claimed_hz != 0) && (claimed_hz < freqs[i].Hz))
+ if ((claimed_hz != 0) && (claimed_hz < cpu->freqs[i].Hz))
claimed_hz_too_low++;
- if ((bios_limit != 0) && (bios_limit < freqs[i].Hz))
+ if ((bios_limit != 0) && (bios_limit < cpu->freqs[i].Hz))
bios_limit_too_low++;
- if (fwts_cpu_performance(fw, cpu, &freqs[i].speed) != FWTS_OK) {
+ if (fwts_cpu_performance(fw, cpu->idx, &cpu->freqs[i].speed)
+ != FWTS_OK) {
fwts_log_error(fw, "Failed to get CPU performance for "
- "CPU frequency %" PRIu64 " Hz.", freqs[i].Hz);
- freqs[i].speed = 0;
+ "CPU frequency %" PRId64 " Hz.",
+ cpu->freqs[i].Hz);
+ cpu->freqs[i].speed = 0;
}
- if (freqs[i].speed > cpu_top_speed)
- cpu_top_speed = freqs[i].speed;
+ if (cpu->freqs[i].speed > cpu_top_perf)
+ cpu_top_perf = cpu->freqs[i].speed;
performed_tests++;
fwts_progress(fw, 100 * performed_tests/total_tests);
}
- if (cpu_top_speed > top_speed)
- top_speed = cpu_top_speed;
+ if (cpu_top_perf > top_speed)
+ top_speed = cpu_top_perf;
if (claimed_hz_too_low) {
char path[PATH_MAX];
@@ -363,7 +320,8 @@ static void do_cpu(fwts_framework *fw, const int cpu)
"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, hz_to_human(claimed_hz), cpu, path);
+ claimed_hz_too_low, hz_to_human(claimed_hz),
+ cpu->idx, path);
}
if (bios_limit_too_low) {
@@ -373,137 +331,72 @@ static void do_cpu(fwts_framework *fw, const int cpu)
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, hz_to_human(bios_limit));
+ path, cpu->idx, hz_to_human(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(fw, "CPU %d: %i CPU frequency steps supported.",
+ cpu->idx, cpu->n_freqs);
fwts_log_info_verbatum(fw, " Frequency | Relative Speed | Bogo loops");
fwts_log_info_verbatum(fw, "-----------+----------------+-----------");
- for (i = 0; i < speedcount; i++) {
+ for (i = 0; i < cpu->n_freqs; i++) {
char *turbo = "";
#ifdef FWTS_ARCH_INTEL
- if ((i == 0) && (speedcount > 1) &&
- (hz_almost_equal(freqs[i].Hz, freqs[i + 1].Hz)))
+ if ((i == 0) && (cpu->n_freqs > 1) &&
+ (hz_almost_equal(cpu->freqs[i].Hz, cpu->freqs[i + 1].Hz)))
turbo = " (Turbo Boost)";
#endif
-
- fwts_log_info_verbatum(fw, "%10s | %5.1f %% | %9" PRIu64 "%s",
- hz_to_human(freqs[i].Hz),
- 100.0 * freqs[i].speed/cpu_top_speed,
- freqs[i].speed,
- turbo);
+ fwts_log_info_verbatum(fw, "%10s | %5.1f %% | %9" PRIu64
+ "%s",
+ hz_to_human(cpu->freqs[i].Hz),
+ 100.0 * cpu->freqs[i].speed / cpu_top_perf,
+ cpu->freqs[i].speed, turbo);
}
if (number_of_speeds == -1)
- number_of_speeds = speedcount;
+ number_of_speeds = cpu->n_freqs;
fwts_log_nl(fw);
- if (number_of_speeds != speedcount)
+ if (number_of_speeds != cpu->n_freqs)
fwts_failed(fw, LOG_LEVEL_MEDIUM,
"CPUFreqPStates",
"Not all processors support the same number of P states.");
- if (speedcount < 2)
+ if (cpu->n_freqs < 2)
return;
- /* Sort the frequencies */
- qsort(freqs, speedcount, sizeof(fwts_cpu_freq), cpu_freq_compare);
-
/* now check for 1) increasing HZ and 2) increasing speed */
- for (i = 0; i < speedcount-1; i++) {
- if (freqs[i].Hz == freqs[i+1].Hz && !warned++)
+ for (i = 0; i < cpu->n_freqs - 1; i++) {
+ if (cpu->freqs[i].Hz == cpu->freqs[i+1].Hz && !warned++)
fwts_failed(fw, LOG_LEVEL_MEDIUM,
"CPUFreqDupFreq",
"Duplicate frequency reported.");
- if (freqs[i].speed > freqs[i+1].speed)
+ if (cpu->freqs[i].speed > cpu->freqs[i+1].speed)
fwts_failed(fw, LOG_LEVEL_MEDIUM,
"CPUFreqSlowerOnCPU",
"Supposedly higher frequency %s is slower (%" PRIu64
" bogo loops) than frequency %s (%" PRIu64
" bogo loops) on CPU %i.",
- hz_to_human(freqs[i+1].Hz), freqs[i+1].speed,
- hz_to_human(freqs[i].Hz), freqs[i].speed,
- cpu);
+ hz_to_human(cpu->freqs[i+1].Hz),
+ cpu->freqs[i+1].speed,
+ hz_to_human(cpu->freqs[i].Hz),
+ cpu->freqs[i].speed,
+ cpu->idx);
- if ((freqs[i].Hz > claimed_hz) && !warned_PSS) {
+ if ((cpu->freqs[i].Hz > claimed_hz) && !warned_PSS) {
warned_PSS = true;
fwts_warning(fw, "Frequency %" PRIu64
- " not achievable; _PSS limit of %" PRIu64 " in effect?",
- freqs[i].Hz, claimed_hz);
+ " not achievable; _PSS limit of %" PRIu64
+ " in effect?",
+ cpu->freqs[i].Hz, claimed_hz);
}
}
}
-static void lowest_speed(fwts_framework *fw, const int cpu)
-{
- char path[PATH_MAX];
- char *line;
- char *c, *c2;
- uint64_t lowspeed = 0;
-
- cpu_mkpath(path, sizeof(path), cpu, "scaling_available_frequencies");
- if ((line = fwts_get(path)) == NULL)
- return;
-
- c = line;
- while (c && strlen(c) > 1) {
- uint64_t Hz;
-
- c2 = strchr(c, ' ');
- if (c2) {
- *c2 = 0;
- c2++;
- } else
- c2 = NULL;
-
- Hz = strtoull(c, NULL, 10);
- if (Hz < lowspeed || lowspeed == 0)
- lowspeed = Hz;
- c = c2;
- }
- free(line);
-
- set_HZ(fw, cpu, lowspeed);
-}
-
-static void highest_speed(fwts_framework *fw, const int cpu)
-{
- char path[PATH_MAX];
- char *line;
- char *c, *c2;
- unsigned long highspeed=0;
-
- cpu_mkpath(path, sizeof(path), cpu, "scaling_available_frequencies");
- if ((line = fwts_get(path)) == NULL)
- return;
-
- c = line;
- while (c && strlen(c) > 1) {
- uint64_t Hz;
-
- c2 = strchr(c, ' ');
- if (c2) {
- *c2=0;
- c2++;
- } else
- c2 = NULL;
-
- Hz = strtoull(c, NULL, 10);
- if (Hz > highspeed || highspeed == 0)
- highspeed = Hz;
- c = c2;
- }
- free(line);
-
- set_HZ(fw, cpu, highspeed);
-}
-
-
#ifdef FWTS_ARCH_INTEL
/*
* 4) Is BIOS wrongly doing Sw_All P-state coordination across cpus
@@ -513,45 +406,22 @@ static void highest_speed(fwts_framework *fw, const int cpu)
*/
static void do_sw_all_test(fwts_framework *fw)
{
- DIR *dir;
- struct dirent *entry;
uint64_t highperf, lowperf;
- int first_cpu_index = -1;
- int cpu;
- int ret;
-
- if ((dir = opendir(FWTS_CPU_PATH)) == NULL) {
- fwts_log_error(fw, "FATAL: cpufreq: sysfs not mounted.");
- return;
- }
-
- while ((entry = readdir(dir)) != NULL) {
- if (entry && strlen(entry->d_name) > 3) {
- cpu = strtoul(entry->d_name + 3, NULL, 10);
- if (first_cpu_index == -1)
- first_cpu_index = cpu;
-
- lowest_speed(fw, cpu);
- }
- }
- closedir(dir);
+ int i;
/* All CPUs at the lowest frequency */
- ret = get_performance_repeat(fw, first_cpu_index, 5, GET_PERFORMANCE_MIN, &lowperf);
- performed_tests++;
- fwts_progress(fw, 100 * performed_tests/total_tests);
- if (ret != FWTS_OK) {
+ for (i = 0; i < num_cpus; i++)
+ cpu_set_lowest_frequency(fw, &cpus[i]);
+
+ if (get_performance_repeat(fw, &cpus[0], 5, GET_PERFORMANCE_MIN, &lowperf) != FWTS_OK) {
fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUFreqSW_ALLGetPerf",
"Failed to get CPU performance.");
return;
}
lowperf = (lowperf * 100) / top_speed;
- highest_speed(fw, first_cpu_index);
- ret = get_performance_repeat(fw, first_cpu_index, 5, GET_PERFORMANCE_MAX, &highperf);
- performed_tests++;
- fwts_progress(fw, 100 * performed_tests/total_tests);
- if (ret != FWTS_OK) {
+ cpu_set_highest_frequency(fw, &cpus[0]);
+ if (get_performance_repeat(fw, &cpus[0], 5, GET_PERFORMANCE_MAX, &highperf) != FWTS_OK) {
fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUFreqSW_ALLGetPerf",
"Failed to get CPU performance.");
return;
@@ -576,57 +446,32 @@ static void do_sw_all_test(fwts_framework *fw)
*/
static void do_sw_any_test(fwts_framework *fw)
{
- DIR *dir;
- struct dirent *entry;
uint64_t highperf, lowperf;
- int first_cpu_index = -1;
- int cpu;
- int ret;
+ int i, rc;
- if ((dir = opendir(FWTS_CPU_PATH)) == NULL) {
- fwts_log_error(fw, "FATAL: cpufreq: sysfs not mounted.");
- return;
- }
-
- while ((entry = readdir(dir)) != NULL) {
- if (entry && strlen(entry->d_name) > 3) {
- cpu = strtoul(entry->d_name + 3, NULL, 10);
- if (first_cpu_index == -1)
- first_cpu_index = cpu;
-
- lowest_speed(fw, cpu);
- }
- }
- rewinddir(dir);
+ for (i = 0; i < num_cpus; i++)
+ cpu_set_lowest_frequency(fw, &cpus[i]);
/* All CPUs at the lowest frequency */
- ret = get_performance_repeat(fw, first_cpu_index, 5, GET_PERFORMANCE_MIN, &lowperf);
- performed_tests++;
- fwts_progress(fw, 100 * performed_tests/total_tests);
- if (ret != FWTS_OK) {
+ rc = get_performance_repeat(fw, &cpus[0], 5,
+ GET_PERFORMANCE_MIN, &lowperf);
+
+ if (rc != FWTS_OK) {
fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUFreqSW_ANYGetPerf",
"Failed to get CPU performance.");
- closedir(dir);
return;
}
+
lowperf = (100 * lowperf) / top_speed;
- highest_speed(fw, first_cpu_index);
+ cpu_set_highest_frequency(fw, &cpus[0]);
- while ((entry = readdir(dir)) != NULL) {
- if (entry && strlen(entry->d_name) > 3) {
- cpu = strtoul(entry->d_name + 3, NULL, 10);
- if (cpu == first_cpu_index)
- continue;
- lowest_speed(fw, cpu);
- }
- }
- closedir(dir);
+ for (i = 0; i < num_cpus; i++)
+ cpu_set_lowest_frequency(fw, &cpus[i]);
- ret = get_performance_repeat(fw, first_cpu_index, 5, GET_PERFORMANCE_MAX, &highperf);
- performed_tests++;
- fwts_progress(fw, 100 * performed_tests/total_tests);
- if (ret != FWTS_OK) {
+ rc = get_performance_repeat(fw, &cpus[0], 5, GET_PERFORMANCE_MAX,
+ &highperf);
+ if (rc != FWTS_OK) {
fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUFreqSW_ANYGetPerf",
"Failed to get CPU performance.");
return;
@@ -643,46 +488,34 @@ static void do_sw_any_test(fwts_framework *fw)
static void check_sw_any(fwts_framework *fw)
{
- DIR *dir;
- struct dirent *entry;
uint64_t low_perf, high_perf, newhigh_perf;
static int once = 0;
- int max_cpu = 0, i, j;
- int cpu;
+ int i, j;
- /* First set all processors to their lowest speed */
- if ((dir = opendir(FWTS_CPU_PATH)) == NULL) {
- fwts_log_error(fw, "FATAL: cpufreq: sysfs not mounted.");
+ /* Single processor machine, no point in checking anything */
+ if (num_cpus < 2)
return;
- }
- while ((entry = readdir(dir)) != NULL) {
- if (entry && strlen(entry->d_name) > 3) {
- cpu = strtoul(entry->d_name + 3, NULL, 10);
- lowest_speed(fw, cpu);
- if (cpu > max_cpu)
- max_cpu = cpu;
- }
- }
- closedir(dir);
-
- if (max_cpu == 0)
- return; /* Single processor machine, no point in checking anything */
+ /* First set all processors to their lowest speed */
+ for (i = 0; i < num_cpus; i++)
+ cpu_set_lowest_frequency(fw, &cpus[i]);
/* assume that all processors have the same low performance */
- if (fwts_cpu_performance(fw, max_cpu, &low_perf) != FWTS_OK) {
+ if (fwts_cpu_performance(fw, cpus[0].idx, &low_perf) != FWTS_OK) {
fwts_failed(fw, LOG_LEVEL_MEDIUM,
"CPUFreqCPsSetToSW_ANYGetPerf",
"Cannot get CPU performance.");
return;
}
- for (i = 0; i <= max_cpu; i++) {
- highest_speed(fw, i);
- if (!cpu_exists(i))
+ for (i = 0; i <= num_cpus; i++) {
+ struct cpu *cpu = &cpus[i];
+
+ cpu_set_highest_frequency(fw, cpu);
+ if (!cpu->online)
continue;
- if (fwts_cpu_performance(fw, i, &high_perf) != FWTS_OK) {
+ if (fwts_cpu_performance(fw, cpu->idx, &high_perf) != FWTS_OK) {
fwts_failed(fw, LOG_LEVEL_MEDIUM,
"CPUFreqCPsSetToSW_ANYGetPerf",
"Cannot get CPU performance.");
@@ -695,10 +528,11 @@ static void check_sw_any(fwts_framework *fw)
* the core in question to now also get the low speed, while
* hardware max will keep the performance
*/
- for (j = 0; j <= max_cpu; j++)
+ for (j = 0; j < num_cpus; j++)
if (i != j)
- lowest_speed(fw, j);
- if (fwts_cpu_performance(fw, i, &newhigh_perf) != FWTS_OK) {
+ cpu_set_lowest_frequency(fw, &cpus[j]);
+ if (fwts_cpu_performance(fw, cpu->idx, &newhigh_perf)
+ != FWTS_OK) {
fwts_failed(fw, LOG_LEVEL_MEDIUM,
"CPUFreqCPsSetToSW_ANYGetPerf",
"Cannot get CPU performance.");
@@ -711,7 +545,7 @@ static void check_sw_any(fwts_framework *fw)
"CPUFreqCPUsSetToSW_ANY",
"Processors are set to SW_ANY.");
once++;
- lowest_speed(fw, i);
+ cpu_set_lowest_frequency(fw, cpu);
}
performed_tests++;
fwts_progress(fw, 100 * performed_tests/total_tests);
@@ -723,9 +557,7 @@ static void check_sw_any(fwts_framework *fw)
static int cpufreq_test1(fwts_framework *fw)
{
- DIR *dir;
- struct dirent *entry;
- int cpu;
+ int i;
#ifdef FWTS_ARCH_INTEL
fwts_log_info(fw,
@@ -750,42 +582,21 @@ static int cpufreq_test1(fwts_framework *fw)
#endif
fwts_log_nl(fw);
- /* First set all processors to their lowest speed */
- if ((dir = opendir(FWTS_CPU_PATH)) == NULL) {
- fwts_log_error(fw, "FATAL: cpufreq: sysfs not mounted\n");
- return FWTS_ERROR;
- }
-
- while ((entry = readdir(dir)) != NULL) {
- if (entry && strlen(entry->d_name) > 3 && isdigit(entry->d_name[3])) {
- cpu = strtoul(entry->d_name + 3, NULL, 10);
- lowest_speed(fw, cpu);
- }
- }
- rewinddir(dir);
+ for (i = 0; i < num_cpus; i++)
+ cpu_set_lowest_frequency(fw, &cpus[i]);
/* then do the benchmark */
-
- while ((entry = readdir(dir)) != NULL) {
- if (entry && strlen(entry->d_name) > 3 && isdigit(entry->d_name[3])) {
- cpu = strtoul(entry->d_name + 3, NULL, 10);
- do_cpu(fw, cpu);
- lowest_speed(fw, cpu);
- if (no_cpufreq)
- break;
- }
+ for (i = 0; i < num_cpus; i++) {
+ do_cpu(fw, &cpus[i]);
+ cpu_set_lowest_frequency(fw, &cpus[i]);
+ if (no_cpufreq)
+ break;
}
- rewinddir(dir);
/* set everything back to the highest speed again */
+ for (i = 0; i < num_cpus; i++)
+ cpu_set_highest_frequency(fw, &cpus[i]);
- while ((entry = readdir(dir)) != NULL) {
- if (entry && strlen(entry->d_name) > 3 && isdigit(entry->d_name[3])) {
- cpu = strtoul(entry->d_name + 3, NULL, 10);
- highest_speed(fw, cpu);
- }
- }
- closedir(dir);
#ifdef FWTS_ARCH_INTEL
if (!no_cpufreq)
@@ -808,12 +619,91 @@ static int cpufreq_test1(fwts_framework *fw)
return FWTS_OK;
}
-static int cpufreq_init(fwts_framework *fw)
+static int cpu_freq_compare(const void *v1, const void *v2)
+{
+ const fwts_cpu_freq *f1 = v1;
+ const fwts_cpu_freq *f2 = v2;
+ return f1->Hz - f2->Hz;
+}
+
+static int parse_cpu_info(struct cpu *cpu, struct dirent *dir)
+{
+ char *end, path[PATH_MAX+1], *str, *tmp, *tok;
+ int i;
+
+ strcpy(cpu->sysfs_path, dir->d_name);
+ cpu->idx = strtoul(cpu->sysfs_path + strlen("cpu"), &end, 10);
+ cpu->online = true;
+
+ cpu_mkpath(path, sizeof(path), cpu, "scaling_governor");
+ cpu->orig_governor = fwts_get(path);
+
+ if (cpu->orig_governor && !strcmp(cpu->orig_governor, "userspace")) {
+ cpu_mkpath(path, sizeof(path), cpu, "scaling_setspeed");
+ tmp = fwts_get(path);
+ cpu->orig_frequency = strtoull(tmp, NULL, 10);
+ free(tmp);
+ }
+
+ /* parse available frequencies */
+ cpu_mkpath(path, sizeof(path), cpu, "scaling_available_frequencies");
+ str = fwts_get(path);
+
+ for (tmp = str, i = 0; ; tmp = NULL) {
+ tok = strtok(tmp, " ");
+ if (!tok)
+ break;
+ if (!isdigit(tok[0]))
+ continue;
+ cpu->freqs[i++].Hz = strtoull(tok, NULL, 10);
+ }
+
+ free(str);
+
+ cpu->n_freqs = i;
+ qsort(cpu->freqs, cpu->n_freqs, sizeof(cpu->freqs[0]),
+ cpu_freq_compare);
+
+ return FWTS_OK;
+}
+
+static int is_cpu_dir(const struct dirent *dir)
{
- if ((num_cpus = fwts_cpu_enumerate()) == FWTS_ERROR) {
- fwts_warning(fw, "Cannot determine number of CPUS, defaulting to 1.");
- num_cpus = 1;
+ return strncmp(dir->d_name, "cpu", 3) == 0 &&
+ isdigit(dir->d_name[3]);
+}
+
+static int cpufreq_init(fwts_framework *fw __attribute__((unused)))
+{
+ struct dirent **dirs;
+ int i;
+
+ num_cpus = scandir(FWTS_CPU_PATH, &dirs, is_cpu_dir, versionsort);
+ cpus = calloc(num_cpus, sizeof(*cpus));
+
+ for (i = 0; i < num_cpus; i++)
+ parse_cpu_info(&cpus[i], dirs[i]);
+
+ return FWTS_OK;
+}
+
+static int cpufreq_deinit(fwts_framework *fw)
+{
+ int i;
+
+ for (i = 0; i < num_cpus; i++) {
+ struct cpu *cpu = &cpus[i];
+
+ if (cpu->orig_governor) {
+ cpu_set_governor(fw, cpu, cpu->orig_governor);
+ free(cpu->orig_governor);
+ }
+
+ if (cpu->orig_frequency)
+ cpu_set_frequency(fw, cpu, cpu->orig_frequency);
}
+ free(cpus);
+
return FWTS_OK;
}
@@ -828,6 +718,7 @@ static fwts_framework_minor_test cpufreq_tests[] = {
static fwts_framework_ops cpufreq_ops = {
.init = cpufreq_init,
+ .deinit = cpufreq_deinit,
.description = "CPU frequency scaling tests.",
.minor_tests = cpufreq_tests
};
More information about the fwts-devel
mailing list