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