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