| 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(format: "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(format: "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(governor: "performance" , cpu: 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: load_time, config); |
| 110 | |
| 111 | if (config->verbose) |
| 112 | printf(format: "_round %i: doing %u cycles with %u calculations" |
| 113 | " for %lius\n" , _round + 1, config->cycles, |
| 114 | calculations, load_time); |
| 115 | |
| 116 | fprintf(stream: config->output, format: "%u %li %li " , |
| 117 | _round, load_time, sleep_time); |
| 118 | |
| 119 | if (config->verbose) |
| 120 | printf(format: "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(useconds: sleep_time); |
| 128 | ROUNDS(calculations); |
| 129 | then = get_time(); |
| 130 | performance_time += then - now - sleep_time; |
| 131 | if (config->verbose) |
| 132 | printf(format: "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(stream: config->output, format: "%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(governor: config->governor, cpu: 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(useconds: sleep_time); |
| 154 | ROUNDS(calculations); |
| 155 | then = get_time(); |
| 156 | powersave_time += then - now - sleep_time; |
| 157 | if (config->verbose) |
| 158 | printf(format: "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(stream: config->output, format: "%li " , |
| 169 | powersave_time / config->cycles); |
| 170 | fprintf(stream: config->output, format: "%.3f\n" , |
| 171 | performance_time * 100.0 / powersave_time); |
| 172 | fflush(stream: config->output); |
| 173 | |
| 174 | if (config->verbose) |
| 175 | printf(format: "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 | |