11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
27fe2f639SDominik Brodowski /*  cpufreq-bench CPUFreq microbenchmark
37fe2f639SDominik Brodowski  *
47fe2f639SDominik Brodowski  *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
57fe2f639SDominik Brodowski  */
67fe2f639SDominik Brodowski 
77fe2f639SDominik Brodowski #include <stdio.h>
87fe2f639SDominik Brodowski #include <unistd.h>
97fe2f639SDominik Brodowski #include <math.h>
107fe2f639SDominik Brodowski 
117fe2f639SDominik Brodowski #include "config.h"
127fe2f639SDominik Brodowski #include "system.h"
137fe2f639SDominik Brodowski #include "benchmark.h"
147fe2f639SDominik Brodowski 
157fe2f639SDominik Brodowski /* Print out progress if we log into a file */
167fe2f639SDominik Brodowski #define show_progress(total_time, progress_time)	\
177fe2f639SDominik Brodowski if (config->output != stdout) {				\
187fe2f639SDominik Brodowski 	fprintf(stdout, "Progress: %02lu %%\r",		\
197fe2f639SDominik Brodowski 		(progress_time * 100) / total_time);	\
207fe2f639SDominik Brodowski 	fflush(stdout);					\
217fe2f639SDominik Brodowski }
227fe2f639SDominik Brodowski 
237fe2f639SDominik Brodowski /**
247fe2f639SDominik Brodowski  * compute how many rounds of calculation we should do
257fe2f639SDominik Brodowski  * to get the given load time
267fe2f639SDominik Brodowski  *
2702af3cb5SDominik Brodowski  * @param load aimed load time in µs
287fe2f639SDominik Brodowski  *
297fe2f639SDominik Brodowski  * @retval rounds of calculation
307fe2f639SDominik Brodowski  **/
317fe2f639SDominik Brodowski 
calculate_timespace(long load,struct config * config)327fe2f639SDominik Brodowski unsigned int calculate_timespace(long load, struct config *config)
337fe2f639SDominik Brodowski {
347fe2f639SDominik Brodowski 	int i;
357fe2f639SDominik Brodowski 	long long now, then;
367fe2f639SDominik Brodowski 	unsigned int estimated = GAUGECOUNT;
377fe2f639SDominik Brodowski 	unsigned int rounds = 0;
387fe2f639SDominik Brodowski 	unsigned int timed = 0;
397fe2f639SDominik Brodowski 
407fe2f639SDominik Brodowski 	if (config->verbose)
417fe2f639SDominik Brodowski 		printf("calibrating load of %lius, please wait...\n", load);
427fe2f639SDominik Brodowski 
437fe2f639SDominik Brodowski 	/* get the initial calculation time for a specific number of rounds */
447fe2f639SDominik Brodowski 	now = get_time();
457fe2f639SDominik Brodowski 	ROUNDS(estimated);
467fe2f639SDominik Brodowski 	then = get_time();
477fe2f639SDominik Brodowski 
487fe2f639SDominik Brodowski 	timed = (unsigned int)(then - now);
497fe2f639SDominik Brodowski 
507fe2f639SDominik Brodowski 	/* approximation of the wanted load time by comparing with the
517fe2f639SDominik Brodowski 	 * initial calculation time */
5202af3cb5SDominik Brodowski 	for (i = 0; i < 4; i++) {
537fe2f639SDominik Brodowski 		rounds = (unsigned int)(load * estimated / timed);
547fe2f639SDominik Brodowski 		dprintf("calibrating with %u rounds\n", rounds);
557fe2f639SDominik Brodowski 		now = get_time();
567fe2f639SDominik Brodowski 		ROUNDS(rounds);
577fe2f639SDominik Brodowski 		then = get_time();
587fe2f639SDominik Brodowski 
597fe2f639SDominik Brodowski 		timed = (unsigned int)(then - now);
607fe2f639SDominik Brodowski 		estimated = rounds;
617fe2f639SDominik Brodowski 	}
627fe2f639SDominik Brodowski 	if (config->verbose)
637fe2f639SDominik Brodowski 		printf("calibration done\n");
647fe2f639SDominik Brodowski 
657fe2f639SDominik Brodowski 	return estimated;
667fe2f639SDominik Brodowski }
677fe2f639SDominik Brodowski 
687fe2f639SDominik Brodowski /**
697fe2f639SDominik Brodowski  * benchmark
707fe2f639SDominik Brodowski  * generates a specific sleep an load time with the performance
717fe2f639SDominik Brodowski  * governor and compares the used time for same calculations done
727fe2f639SDominik Brodowski  * with the configured powersave governor
737fe2f639SDominik Brodowski  *
747fe2f639SDominik Brodowski  * @param config config values for the benchmark
757fe2f639SDominik Brodowski  *
767fe2f639SDominik Brodowski  **/
777fe2f639SDominik Brodowski 
start_benchmark(struct config * config)787fe2f639SDominik Brodowski void start_benchmark(struct config *config)
797fe2f639SDominik Brodowski {
807fe2f639SDominik Brodowski 	unsigned int _round, cycle;
817fe2f639SDominik Brodowski 	long long now, then;
827fe2f639SDominik Brodowski 	long sleep_time = 0, load_time = 0;
837fe2f639SDominik Brodowski 	long performance_time = 0, powersave_time = 0;
847fe2f639SDominik Brodowski 	unsigned int calculations;
857fe2f639SDominik Brodowski 	unsigned long total_time = 0, progress_time = 0;
867fe2f639SDominik Brodowski 
877fe2f639SDominik Brodowski 	sleep_time = config->sleep;
887fe2f639SDominik Brodowski 	load_time = config->load;
897fe2f639SDominik Brodowski 
907fe2f639SDominik Brodowski 	/* For the progress bar */
917fe2f639SDominik Brodowski 	for (_round = 1; _round <= config->rounds; _round++)
927fe2f639SDominik Brodowski 		total_time += _round * (config->sleep + config->load);
937fe2f639SDominik Brodowski 	total_time *= 2; /* powersave and performance cycles */
947fe2f639SDominik Brodowski 
957fe2f639SDominik Brodowski 	for (_round = 0; _round < config->rounds; _round++) {
967fe2f639SDominik Brodowski 		performance_time = 0LL;
977fe2f639SDominik Brodowski 		powersave_time = 0LL;
987fe2f639SDominik Brodowski 
997fe2f639SDominik Brodowski 		show_progress(total_time, progress_time);
1007fe2f639SDominik Brodowski 
1017fe2f639SDominik Brodowski 		/* set the cpufreq governor to "performance" which disables
1027fe2f639SDominik Brodowski 		 * P-State switching. */
1037fe2f639SDominik Brodowski 		if (set_cpufreq_governor("performance", config->cpu) != 0)
1047fe2f639SDominik Brodowski 			return;
1057fe2f639SDominik Brodowski 
1067fe2f639SDominik Brodowski 		/* calibrate the calculation time. the resulting calculation
1077fe2f639SDominik Brodowski 		 * _rounds should produce a load which matches the configured
1087fe2f639SDominik Brodowski 		 * load time */
1097fe2f639SDominik Brodowski 		calculations = calculate_timespace(load_time, config);
1107fe2f639SDominik Brodowski 
1117fe2f639SDominik Brodowski 		if (config->verbose)
1127fe2f639SDominik Brodowski 			printf("_round %i: doing %u cycles with %u calculations"
1137fe2f639SDominik Brodowski 			       " for %lius\n", _round + 1, config->cycles,
1147fe2f639SDominik Brodowski 			       calculations, load_time);
1157fe2f639SDominik Brodowski 
1167fe2f639SDominik Brodowski 		fprintf(config->output, "%u %li %li ",
1177fe2f639SDominik Brodowski 			_round, load_time, sleep_time);
1187fe2f639SDominik Brodowski 
11902af3cb5SDominik Brodowski 		if (config->verbose)
120fe7656a8SColin Ian King 			printf("average: %lius, rps:%li\n",
12102af3cb5SDominik Brodowski 				load_time / calculations,
12202af3cb5SDominik Brodowski 				1000000 * calculations / load_time);
1237fe2f639SDominik Brodowski 
1247fe2f639SDominik Brodowski 		/* do some sleep/load cycles with the performance governor */
1257fe2f639SDominik Brodowski 		for (cycle = 0; cycle < config->cycles; cycle++) {
1267fe2f639SDominik Brodowski 			now = get_time();
1277fe2f639SDominik Brodowski 			usleep(sleep_time);
1287fe2f639SDominik Brodowski 			ROUNDS(calculations);
1297fe2f639SDominik Brodowski 			then = get_time();
1307fe2f639SDominik Brodowski 			performance_time += then - now - sleep_time;
1317fe2f639SDominik Brodowski 			if (config->verbose)
13202af3cb5SDominik Brodowski 				printf("performance cycle took %lius, "
13302af3cb5SDominik Brodowski 					"sleep: %lius, "
13402af3cb5SDominik Brodowski 					"load: %lius, rounds: %u\n",
13502af3cb5SDominik Brodowski 					(long)(then - now), sleep_time,
13602af3cb5SDominik Brodowski 					load_time, calculations);
1377fe2f639SDominik Brodowski 		}
13802af3cb5SDominik Brodowski 		fprintf(config->output, "%li ",
13902af3cb5SDominik Brodowski 			performance_time / config->cycles);
1407fe2f639SDominik Brodowski 
1417fe2f639SDominik Brodowski 		progress_time += sleep_time + load_time;
1427fe2f639SDominik Brodowski 		show_progress(total_time, progress_time);
1437fe2f639SDominik Brodowski 
1447fe2f639SDominik Brodowski 		/* set the powersave governor which activates P-State switching
1457fe2f639SDominik Brodowski 		 * again */
1467fe2f639SDominik Brodowski 		if (set_cpufreq_governor(config->governor, config->cpu) != 0)
1477fe2f639SDominik Brodowski 			return;
1487fe2f639SDominik Brodowski 
14902af3cb5SDominik Brodowski 		/* again, do some sleep/load cycles with the
15002af3cb5SDominik Brodowski 		 * powersave governor */
1517fe2f639SDominik Brodowski 		for (cycle = 0; cycle < config->cycles; cycle++) {
1527fe2f639SDominik Brodowski 			now = get_time();
1537fe2f639SDominik Brodowski 			usleep(sleep_time);
1547fe2f639SDominik Brodowski 			ROUNDS(calculations);
1557fe2f639SDominik Brodowski 			then = get_time();
1567fe2f639SDominik Brodowski 			powersave_time += then - now - sleep_time;
1577fe2f639SDominik Brodowski 			if (config->verbose)
15802af3cb5SDominik Brodowski 				printf("powersave cycle took %lius, "
15902af3cb5SDominik Brodowski 					"sleep: %lius, "
16002af3cb5SDominik Brodowski 					"load: %lius, rounds: %u\n",
16102af3cb5SDominik Brodowski 					(long)(then - now), sleep_time,
16202af3cb5SDominik Brodowski 					load_time, calculations);
1637fe2f639SDominik Brodowski 		}
1647fe2f639SDominik Brodowski 
1657fe2f639SDominik Brodowski 		progress_time += sleep_time + load_time;
1667fe2f639SDominik Brodowski 
167fe7656a8SColin Ian King 		/* compare the average sleep/load cycles  */
16802af3cb5SDominik Brodowski 		fprintf(config->output, "%li ",
16902af3cb5SDominik Brodowski 			powersave_time / config->cycles);
17002af3cb5SDominik Brodowski 		fprintf(config->output, "%.3f\n",
17102af3cb5SDominik Brodowski 			performance_time * 100.0 / powersave_time);
1727fe2f639SDominik Brodowski 		fflush(config->output);
1737fe2f639SDominik Brodowski 
1747fe2f639SDominik Brodowski 		if (config->verbose)
17502af3cb5SDominik Brodowski 			printf("performance is at %.2f%%\n",
17602af3cb5SDominik Brodowski 				performance_time * 100.0 / powersave_time);
1777fe2f639SDominik Brodowski 
1787fe2f639SDominik Brodowski 		sleep_time += config->sleep_step;
1797fe2f639SDominik Brodowski 		load_time += config->load_step;
1807fe2f639SDominik Brodowski 	}
1817fe2f639SDominik Brodowski }
182