ACK: ACK: [PATCH 01/11] cpu/cpufreq: Don't reparse cpu information
Alex Hung
alex.hung at canonical.com
Tue Jun 2 03:09:31 UTC 2015
On 05/26/2015 05:19 PM, Colin Ian King wrote:
> On 21/05/15 10:34, Jeremy Kerr wrote:
>> 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
>> };
>>
> Acked-by: Colin Ian King <colin.king at canonical.com>
>
Acked-by: Alex Hung <alex.hung at canaonical.com>
More information about the fwts-devel
mailing list