ACK: [PATCH 01/11] cpu/cpufreq: Don't reparse cpu information

Colin Ian King colin.king at canonical.com
Tue May 26 09:19:28 UTC 2015


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>



More information about the fwts-devel mailing list