17fe2f639SDominik Brodowski /* cpufreq-bench CPUFreq microbenchmark 27fe2f639SDominik Brodowski * 37fe2f639SDominik Brodowski * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> 47fe2f639SDominik Brodowski * 57fe2f639SDominik Brodowski * This program is free software; you can redistribute it and/or modify 67fe2f639SDominik Brodowski * it under the terms of the GNU General Public License as published by 77fe2f639SDominik Brodowski * the Free Software Foundation; either version 2 of the License, or 87fe2f639SDominik Brodowski * (at your option) any later version. 97fe2f639SDominik Brodowski * 107fe2f639SDominik Brodowski * This program is distributed in the hope that it will be useful, 117fe2f639SDominik Brodowski * but WITHOUT ANY WARRANTY; without even the implied warranty of 127fe2f639SDominik Brodowski * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 137fe2f639SDominik Brodowski * GNU General Public License for more details. 147fe2f639SDominik Brodowski * 157fe2f639SDominik Brodowski * You should have received a copy of the GNU General Public License 167fe2f639SDominik Brodowski * along with this program; if not, write to the Free Software 177fe2f639SDominik Brodowski * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 187fe2f639SDominik Brodowski */ 197fe2f639SDominik Brodowski 207fe2f639SDominik Brodowski #include <stdio.h> 217fe2f639SDominik Brodowski #include <unistd.h> 227fe2f639SDominik Brodowski #include <math.h> 237fe2f639SDominik Brodowski 247fe2f639SDominik Brodowski #include "config.h" 257fe2f639SDominik Brodowski #include "system.h" 267fe2f639SDominik Brodowski #include "benchmark.h" 277fe2f639SDominik Brodowski 287fe2f639SDominik Brodowski /* Print out progress if we log into a file */ 297fe2f639SDominik Brodowski #define show_progress(total_time, progress_time) \ 307fe2f639SDominik Brodowski if (config->output != stdout) { \ 317fe2f639SDominik Brodowski fprintf(stdout, "Progress: %02lu %%\r", \ 327fe2f639SDominik Brodowski (progress_time * 100) / total_time); \ 337fe2f639SDominik Brodowski fflush(stdout); \ 347fe2f639SDominik Brodowski } 357fe2f639SDominik Brodowski 367fe2f639SDominik Brodowski /** 377fe2f639SDominik Brodowski * compute how many rounds of calculation we should do 387fe2f639SDominik Brodowski * to get the given load time 397fe2f639SDominik Brodowski * 4002af3cb5SDominik Brodowski * @param load aimed load time in µs 417fe2f639SDominik Brodowski * 427fe2f639SDominik Brodowski * @retval rounds of calculation 437fe2f639SDominik Brodowski **/ 447fe2f639SDominik Brodowski 457fe2f639SDominik Brodowski unsigned int calculate_timespace(long load, struct config *config) 467fe2f639SDominik Brodowski { 477fe2f639SDominik Brodowski int i; 487fe2f639SDominik Brodowski long long now, then; 497fe2f639SDominik Brodowski unsigned int estimated = GAUGECOUNT; 507fe2f639SDominik Brodowski unsigned int rounds = 0; 517fe2f639SDominik Brodowski unsigned int timed = 0; 527fe2f639SDominik Brodowski 537fe2f639SDominik Brodowski if (config->verbose) 547fe2f639SDominik Brodowski printf("calibrating load of %lius, please wait...\n", load); 557fe2f639SDominik Brodowski 567fe2f639SDominik Brodowski /* get the initial calculation time for a specific number of rounds */ 577fe2f639SDominik Brodowski now = get_time(); 587fe2f639SDominik Brodowski ROUNDS(estimated); 597fe2f639SDominik Brodowski then = get_time(); 607fe2f639SDominik Brodowski 617fe2f639SDominik Brodowski timed = (unsigned int)(then - now); 627fe2f639SDominik Brodowski 637fe2f639SDominik Brodowski /* approximation of the wanted load time by comparing with the 647fe2f639SDominik Brodowski * initial calculation time */ 6502af3cb5SDominik Brodowski for (i = 0; i < 4; i++) { 667fe2f639SDominik Brodowski rounds = (unsigned int)(load * estimated / timed); 677fe2f639SDominik Brodowski dprintf("calibrating with %u rounds\n", rounds); 687fe2f639SDominik Brodowski now = get_time(); 697fe2f639SDominik Brodowski ROUNDS(rounds); 707fe2f639SDominik Brodowski then = get_time(); 717fe2f639SDominik Brodowski 727fe2f639SDominik Brodowski timed = (unsigned int)(then - now); 737fe2f639SDominik Brodowski estimated = rounds; 747fe2f639SDominik Brodowski } 757fe2f639SDominik Brodowski if (config->verbose) 767fe2f639SDominik Brodowski printf("calibration done\n"); 777fe2f639SDominik Brodowski 787fe2f639SDominik Brodowski return estimated; 797fe2f639SDominik Brodowski } 807fe2f639SDominik Brodowski 817fe2f639SDominik Brodowski /** 827fe2f639SDominik Brodowski * benchmark 837fe2f639SDominik Brodowski * generates a specific sleep an load time with the performance 847fe2f639SDominik Brodowski * governor and compares the used time for same calculations done 857fe2f639SDominik Brodowski * with the configured powersave governor 867fe2f639SDominik Brodowski * 877fe2f639SDominik Brodowski * @param config config values for the benchmark 887fe2f639SDominik Brodowski * 897fe2f639SDominik Brodowski **/ 907fe2f639SDominik Brodowski 917fe2f639SDominik Brodowski void start_benchmark(struct config *config) 927fe2f639SDominik Brodowski { 937fe2f639SDominik Brodowski unsigned int _round, cycle; 947fe2f639SDominik Brodowski long long now, then; 957fe2f639SDominik Brodowski long sleep_time = 0, load_time = 0; 967fe2f639SDominik Brodowski long performance_time = 0, powersave_time = 0; 977fe2f639SDominik Brodowski unsigned int calculations; 987fe2f639SDominik Brodowski unsigned long total_time = 0, progress_time = 0; 997fe2f639SDominik Brodowski 1007fe2f639SDominik Brodowski sleep_time = config->sleep; 1017fe2f639SDominik Brodowski load_time = config->load; 1027fe2f639SDominik Brodowski 1037fe2f639SDominik Brodowski /* For the progress bar */ 1047fe2f639SDominik Brodowski for (_round = 1; _round <= config->rounds; _round++) 1057fe2f639SDominik Brodowski total_time += _round * (config->sleep + config->load); 1067fe2f639SDominik Brodowski total_time *= 2; /* powersave and performance cycles */ 1077fe2f639SDominik Brodowski 1087fe2f639SDominik Brodowski for (_round = 0; _round < config->rounds; _round++) { 1097fe2f639SDominik Brodowski performance_time = 0LL; 1107fe2f639SDominik Brodowski powersave_time = 0LL; 1117fe2f639SDominik Brodowski 1127fe2f639SDominik Brodowski show_progress(total_time, progress_time); 1137fe2f639SDominik Brodowski 1147fe2f639SDominik Brodowski /* set the cpufreq governor to "performance" which disables 1157fe2f639SDominik Brodowski * P-State switching. */ 1167fe2f639SDominik Brodowski if (set_cpufreq_governor("performance", config->cpu) != 0) 1177fe2f639SDominik Brodowski return; 1187fe2f639SDominik Brodowski 1197fe2f639SDominik Brodowski /* calibrate the calculation time. the resulting calculation 1207fe2f639SDominik Brodowski * _rounds should produce a load which matches the configured 1217fe2f639SDominik Brodowski * load time */ 1227fe2f639SDominik Brodowski calculations = calculate_timespace(load_time, config); 1237fe2f639SDominik Brodowski 1247fe2f639SDominik Brodowski if (config->verbose) 1257fe2f639SDominik Brodowski printf("_round %i: doing %u cycles with %u calculations" 1267fe2f639SDominik Brodowski " for %lius\n", _round + 1, config->cycles, 1277fe2f639SDominik Brodowski calculations, load_time); 1287fe2f639SDominik Brodowski 1297fe2f639SDominik Brodowski fprintf(config->output, "%u %li %li ", 1307fe2f639SDominik Brodowski _round, load_time, sleep_time); 1317fe2f639SDominik Brodowski 13202af3cb5SDominik Brodowski if (config->verbose) 13302af3cb5SDominik Brodowski printf("avarage: %lius, rps:%li\n", 13402af3cb5SDominik Brodowski load_time / calculations, 13502af3cb5SDominik Brodowski 1000000 * calculations / load_time); 1367fe2f639SDominik Brodowski 1377fe2f639SDominik Brodowski /* do some sleep/load cycles with the performance governor */ 1387fe2f639SDominik Brodowski for (cycle = 0; cycle < config->cycles; cycle++) { 1397fe2f639SDominik Brodowski now = get_time(); 1407fe2f639SDominik Brodowski usleep(sleep_time); 1417fe2f639SDominik Brodowski ROUNDS(calculations); 1427fe2f639SDominik Brodowski then = get_time(); 1437fe2f639SDominik Brodowski performance_time += then - now - sleep_time; 1447fe2f639SDominik Brodowski if (config->verbose) 14502af3cb5SDominik Brodowski printf("performance cycle took %lius, " 14602af3cb5SDominik Brodowski "sleep: %lius, " 14702af3cb5SDominik Brodowski "load: %lius, rounds: %u\n", 14802af3cb5SDominik Brodowski (long)(then - now), sleep_time, 14902af3cb5SDominik Brodowski load_time, calculations); 1507fe2f639SDominik Brodowski } 15102af3cb5SDominik Brodowski fprintf(config->output, "%li ", 15202af3cb5SDominik Brodowski performance_time / config->cycles); 1537fe2f639SDominik Brodowski 1547fe2f639SDominik Brodowski progress_time += sleep_time + load_time; 1557fe2f639SDominik Brodowski show_progress(total_time, progress_time); 1567fe2f639SDominik Brodowski 1577fe2f639SDominik Brodowski /* set the powersave governor which activates P-State switching 1587fe2f639SDominik Brodowski * again */ 1597fe2f639SDominik Brodowski if (set_cpufreq_governor(config->governor, config->cpu) != 0) 1607fe2f639SDominik Brodowski return; 1617fe2f639SDominik Brodowski 16202af3cb5SDominik Brodowski /* again, do some sleep/load cycles with the 16302af3cb5SDominik Brodowski * powersave governor */ 1647fe2f639SDominik Brodowski for (cycle = 0; cycle < config->cycles; cycle++) { 1657fe2f639SDominik Brodowski now = get_time(); 1667fe2f639SDominik Brodowski usleep(sleep_time); 1677fe2f639SDominik Brodowski ROUNDS(calculations); 1687fe2f639SDominik Brodowski then = get_time(); 1697fe2f639SDominik Brodowski powersave_time += then - now - sleep_time; 1707fe2f639SDominik Brodowski if (config->verbose) 17102af3cb5SDominik Brodowski printf("powersave cycle took %lius, " 17202af3cb5SDominik Brodowski "sleep: %lius, " 17302af3cb5SDominik Brodowski "load: %lius, rounds: %u\n", 17402af3cb5SDominik Brodowski (long)(then - now), sleep_time, 17502af3cb5SDominik Brodowski load_time, calculations); 1767fe2f639SDominik Brodowski } 1777fe2f639SDominik Brodowski 1787fe2f639SDominik Brodowski progress_time += sleep_time + load_time; 1797fe2f639SDominik Brodowski 1807fe2f639SDominik Brodowski /* compare the avarage sleep/load cycles */ 18102af3cb5SDominik Brodowski fprintf(config->output, "%li ", 18202af3cb5SDominik Brodowski powersave_time / config->cycles); 18302af3cb5SDominik Brodowski fprintf(config->output, "%.3f\n", 18402af3cb5SDominik Brodowski performance_time * 100.0 / powersave_time); 1857fe2f639SDominik Brodowski fflush(config->output); 1867fe2f639SDominik Brodowski 1877fe2f639SDominik Brodowski if (config->verbose) 18802af3cb5SDominik Brodowski printf("performance is at %.2f%%\n", 18902af3cb5SDominik Brodowski performance_time * 100.0 / powersave_time); 1907fe2f639SDominik Brodowski 1917fe2f639SDominik Brodowski sleep_time += config->sleep_step; 1927fe2f639SDominik Brodowski load_time += config->load_step; 1937fe2f639SDominik Brodowski } 1947fe2f639SDominik Brodowski } 195