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 { 67 rounds = (unsigned int)(load * estimated / timed); 68 dprintf("calibrating with %u rounds\n", rounds); 69 now = get_time(); 70 ROUNDS(rounds); 71 then = get_time(); 72 73 timed = (unsigned int)(then - now); 74 estimated = rounds; 75 } 76 if (config->verbose) 77 printf("calibration done\n"); 78 79 return estimated; 80 } 81 82 /** 83 * benchmark 84 * generates a specific sleep an load time with the performance 85 * governor and compares the used time for same calculations done 86 * with the configured powersave governor 87 * 88 * @param config config values for the benchmark 89 * 90 **/ 91 92 void start_benchmark(struct config *config) 93 { 94 unsigned int _round, cycle; 95 long long now, then; 96 long sleep_time = 0, load_time = 0; 97 long performance_time = 0, powersave_time = 0; 98 unsigned int calculations; 99 unsigned long total_time = 0, progress_time = 0; 100 101 sleep_time = config->sleep; 102 load_time = config->load; 103 104 /* For the progress bar */ 105 for (_round=1; _round <= config->rounds; _round++) 106 total_time += _round * (config->sleep + config->load); 107 total_time *= 2; /* powersave and performance cycles */ 108 109 for (_round=0; _round < config->rounds; _round++) { 110 performance_time = 0LL; 111 powersave_time = 0LL; 112 113 show_progress(total_time, progress_time); 114 115 /* set the cpufreq governor to "performance" which disables 116 * P-State switching. */ 117 if (set_cpufreq_governor("performance", config->cpu) != 0) 118 return; 119 120 /* calibrate the calculation time. the resulting calculation 121 * _rounds should produce a load which matches the configured 122 * load time */ 123 calculations = calculate_timespace(load_time, config); 124 125 if (config->verbose) 126 printf("_round %i: doing %u cycles with %u calculations" 127 " for %lius\n", _round + 1, config->cycles, 128 calculations, load_time); 129 130 fprintf(config->output, "%u %li %li ", 131 _round, load_time, sleep_time); 132 133 if (config->verbose) { 134 printf("avarage: %lius, rps:%li\n", load_time / calculations, 1000000 * calculations / load_time); 135 } 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, sleep: %lius, load: %lius, rounds: %u\n", 146 (long)(then - now), sleep_time, load_time, calculations); 147 } 148 fprintf(config->output, "%li ", performance_time / config->cycles); 149 150 progress_time += sleep_time + load_time; 151 show_progress(total_time, progress_time); 152 153 /* set the powersave governor which activates P-State switching 154 * again */ 155 if (set_cpufreq_governor(config->governor, config->cpu) != 0) 156 return; 157 158 /* again, do some sleep/load cycles with the powersave governor */ 159 for (cycle = 0; cycle < config->cycles; cycle++) { 160 now = get_time(); 161 usleep(sleep_time); 162 ROUNDS(calculations); 163 then = get_time(); 164 powersave_time += then - now - sleep_time; 165 if (config->verbose) 166 printf("powersave cycle took %lius, sleep: %lius, load: %lius, rounds: %u\n", 167 (long)(then - now), sleep_time, load_time, calculations); 168 } 169 170 progress_time += sleep_time + load_time; 171 172 /* compare the avarage sleep/load cycles */ 173 fprintf(config->output, "%li ", powersave_time / config->cycles); 174 fprintf(config->output, "%.3f\n", performance_time * 100.0 / powersave_time); 175 fflush(config->output); 176 177 if (config->verbose) 178 printf("performance is at %.2f%%\n", performance_time * 100.0 / powersave_time); 179 180 sleep_time += config->sleep_step; 181 load_time += config->load_step; 182 } 183 } 184 185