1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* cpufreq-bench CPUFreq microbenchmark 3 * 4 * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> 5 */ 6 7 #include <stdio.h> 8 #include <unistd.h> 9 #include <math.h> 10 11 #include "config.h" 12 #include "system.h" 13 #include "benchmark.h" 14 15 /* Print out progress if we log into a file */ 16 #define show_progress(total_time, progress_time) \ 17 if (config->output != stdout) { \ 18 fprintf(stdout, "Progress: %02lu %%\r", \ 19 (progress_time * 100) / total_time); \ 20 fflush(stdout); \ 21 } 22 23 /** 24 * compute how many rounds of calculation we should do 25 * to get the given load time 26 * 27 * @param load aimed load time in µs 28 * 29 * @retval rounds of calculation 30 **/ 31 32 unsigned int calculate_timespace(long load, struct config *config) 33 { 34 int i; 35 long long now, then; 36 unsigned int estimated = GAUGECOUNT; 37 unsigned int rounds = 0; 38 unsigned int timed = 0; 39 40 if (config->verbose) 41 printf("calibrating load of %lius, please wait...\n", load); 42 43 /* get the initial calculation time for a specific number of rounds */ 44 now = get_time(); 45 ROUNDS(estimated); 46 then = get_time(); 47 48 timed = (unsigned int)(then - now); 49 50 /* approximation of the wanted load time by comparing with the 51 * initial calculation time */ 52 for (i = 0; i < 4; i++) { 53 rounds = (unsigned int)(load * estimated / timed); 54 dprintf("calibrating with %u rounds\n", rounds); 55 now = get_time(); 56 ROUNDS(rounds); 57 then = get_time(); 58 59 timed = (unsigned int)(then - now); 60 estimated = rounds; 61 } 62 if (config->verbose) 63 printf("calibration done\n"); 64 65 return estimated; 66 } 67 68 /** 69 * benchmark 70 * generates a specific sleep an load time with the performance 71 * governor and compares the used time for same calculations done 72 * with the configured powersave governor 73 * 74 * @param config config values for the benchmark 75 * 76 **/ 77 78 void start_benchmark(struct config *config) 79 { 80 unsigned int _round, cycle; 81 long long now, then; 82 long sleep_time = 0, load_time = 0; 83 long performance_time = 0, powersave_time = 0; 84 unsigned int calculations; 85 unsigned long total_time = 0, progress_time = 0; 86 87 sleep_time = config->sleep; 88 load_time = config->load; 89 90 /* For the progress bar */ 91 for (_round = 1; _round <= config->rounds; _round++) 92 total_time += _round * (config->sleep + config->load); 93 total_time *= 2; /* powersave and performance cycles */ 94 95 for (_round = 0; _round < config->rounds; _round++) { 96 performance_time = 0LL; 97 powersave_time = 0LL; 98 99 show_progress(total_time, progress_time); 100 101 /* set the cpufreq governor to "performance" which disables 102 * P-State switching. */ 103 if (set_cpufreq_governor("performance", config->cpu) != 0) 104 return; 105 106 /* calibrate the calculation time. the resulting calculation 107 * _rounds should produce a load which matches the configured 108 * load time */ 109 calculations = calculate_timespace(load_time, config); 110 111 if (config->verbose) 112 printf("_round %i: doing %u cycles with %u calculations" 113 " for %lius\n", _round + 1, config->cycles, 114 calculations, load_time); 115 116 fprintf(config->output, "%u %li %li ", 117 _round, load_time, sleep_time); 118 119 if (config->verbose) 120 printf("average: %lius, rps:%li\n", 121 load_time / calculations, 122 1000000 * calculations / load_time); 123 124 /* do some sleep/load cycles with the performance governor */ 125 for (cycle = 0; cycle < config->cycles; cycle++) { 126 now = get_time(); 127 usleep(sleep_time); 128 ROUNDS(calculations); 129 then = get_time(); 130 performance_time += then - now - sleep_time; 131 if (config->verbose) 132 printf("performance cycle took %lius, " 133 "sleep: %lius, " 134 "load: %lius, rounds: %u\n", 135 (long)(then - now), sleep_time, 136 load_time, calculations); 137 } 138 fprintf(config->output, "%li ", 139 performance_time / config->cycles); 140 141 progress_time += sleep_time + load_time; 142 show_progress(total_time, progress_time); 143 144 /* set the powersave governor which activates P-State switching 145 * again */ 146 if (set_cpufreq_governor(config->governor, config->cpu) != 0) 147 return; 148 149 /* again, do some sleep/load cycles with the 150 * powersave governor */ 151 for (cycle = 0; cycle < config->cycles; cycle++) { 152 now = get_time(); 153 usleep(sleep_time); 154 ROUNDS(calculations); 155 then = get_time(); 156 powersave_time += then - now - sleep_time; 157 if (config->verbose) 158 printf("powersave cycle took %lius, " 159 "sleep: %lius, " 160 "load: %lius, rounds: %u\n", 161 (long)(then - now), sleep_time, 162 load_time, calculations); 163 } 164 165 progress_time += sleep_time + load_time; 166 167 /* compare the average sleep/load cycles */ 168 fprintf(config->output, "%li ", 169 powersave_time / config->cycles); 170 fprintf(config->output, "%.3f\n", 171 performance_time * 100.0 / powersave_time); 172 fflush(config->output); 173 174 if (config->verbose) 175 printf("performance is at %.2f%%\n", 176 performance_time * 100.0 / powersave_time); 177 178 sleep_time += config->sleep_step; 179 load_time += config->load_step; 180 } 181 } 182