18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* cpufreq-bench CPUFreq microbenchmark 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <stdio.h> 88c2ecf20Sopenharmony_ci#include <unistd.h> 98c2ecf20Sopenharmony_ci#include <math.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "config.h" 128c2ecf20Sopenharmony_ci#include "system.h" 138c2ecf20Sopenharmony_ci#include "benchmark.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* Print out progress if we log into a file */ 168c2ecf20Sopenharmony_ci#define show_progress(total_time, progress_time) \ 178c2ecf20Sopenharmony_ciif (config->output != stdout) { \ 188c2ecf20Sopenharmony_ci fprintf(stdout, "Progress: %02lu %%\r", \ 198c2ecf20Sopenharmony_ci (progress_time * 100) / total_time); \ 208c2ecf20Sopenharmony_ci fflush(stdout); \ 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/** 248c2ecf20Sopenharmony_ci * compute how many rounds of calculation we should do 258c2ecf20Sopenharmony_ci * to get the given load time 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * @param load aimed load time in µs 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * @retval rounds of calculation 308c2ecf20Sopenharmony_ci **/ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciunsigned int calculate_timespace(long load, struct config *config) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci int i; 358c2ecf20Sopenharmony_ci long long now, then; 368c2ecf20Sopenharmony_ci unsigned int estimated = GAUGECOUNT; 378c2ecf20Sopenharmony_ci unsigned int rounds = 0; 388c2ecf20Sopenharmony_ci unsigned int timed = 0; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (config->verbose) 418c2ecf20Sopenharmony_ci printf("calibrating load of %lius, please wait...\n", load); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* get the initial calculation time for a specific number of rounds */ 448c2ecf20Sopenharmony_ci now = get_time(); 458c2ecf20Sopenharmony_ci ROUNDS(estimated); 468c2ecf20Sopenharmony_ci then = get_time(); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci timed = (unsigned int)(then - now); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* approximation of the wanted load time by comparing with the 518c2ecf20Sopenharmony_ci * initial calculation time */ 528c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 538c2ecf20Sopenharmony_ci rounds = (unsigned int)(load * estimated / timed); 548c2ecf20Sopenharmony_ci dprintf("calibrating with %u rounds\n", rounds); 558c2ecf20Sopenharmony_ci now = get_time(); 568c2ecf20Sopenharmony_ci ROUNDS(rounds); 578c2ecf20Sopenharmony_ci then = get_time(); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci timed = (unsigned int)(then - now); 608c2ecf20Sopenharmony_ci estimated = rounds; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci if (config->verbose) 638c2ecf20Sopenharmony_ci printf("calibration done\n"); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return estimated; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/** 698c2ecf20Sopenharmony_ci * benchmark 708c2ecf20Sopenharmony_ci * generates a specific sleep an load time with the performance 718c2ecf20Sopenharmony_ci * governor and compares the used time for same calculations done 728c2ecf20Sopenharmony_ci * with the configured powersave governor 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * @param config config values for the benchmark 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci **/ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid start_benchmark(struct config *config) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci unsigned int _round, cycle; 818c2ecf20Sopenharmony_ci long long now, then; 828c2ecf20Sopenharmony_ci long sleep_time = 0, load_time = 0; 838c2ecf20Sopenharmony_ci long performance_time = 0, powersave_time = 0; 848c2ecf20Sopenharmony_ci unsigned int calculations; 858c2ecf20Sopenharmony_ci unsigned long total_time = 0, progress_time = 0; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci sleep_time = config->sleep; 888c2ecf20Sopenharmony_ci load_time = config->load; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* For the progress bar */ 918c2ecf20Sopenharmony_ci for (_round = 1; _round <= config->rounds; _round++) 928c2ecf20Sopenharmony_ci total_time += _round * (config->sleep + config->load); 938c2ecf20Sopenharmony_ci total_time *= 2; /* powersave and performance cycles */ 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci for (_round = 0; _round < config->rounds; _round++) { 968c2ecf20Sopenharmony_ci performance_time = 0LL; 978c2ecf20Sopenharmony_ci powersave_time = 0LL; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci show_progress(total_time, progress_time); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* set the cpufreq governor to "performance" which disables 1028c2ecf20Sopenharmony_ci * P-State switching. */ 1038c2ecf20Sopenharmony_ci if (set_cpufreq_governor("performance", config->cpu) != 0) 1048c2ecf20Sopenharmony_ci return; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* calibrate the calculation time. the resulting calculation 1078c2ecf20Sopenharmony_ci * _rounds should produce a load which matches the configured 1088c2ecf20Sopenharmony_ci * load time */ 1098c2ecf20Sopenharmony_ci calculations = calculate_timespace(load_time, config); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (config->verbose) 1128c2ecf20Sopenharmony_ci printf("_round %i: doing %u cycles with %u calculations" 1138c2ecf20Sopenharmony_ci " for %lius\n", _round + 1, config->cycles, 1148c2ecf20Sopenharmony_ci calculations, load_time); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci fprintf(config->output, "%u %li %li ", 1178c2ecf20Sopenharmony_ci _round, load_time, sleep_time); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (config->verbose) 1208c2ecf20Sopenharmony_ci printf("average: %lius, rps:%li\n", 1218c2ecf20Sopenharmony_ci load_time / calculations, 1228c2ecf20Sopenharmony_ci 1000000 * calculations / load_time); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* do some sleep/load cycles with the performance governor */ 1258c2ecf20Sopenharmony_ci for (cycle = 0; cycle < config->cycles; cycle++) { 1268c2ecf20Sopenharmony_ci now = get_time(); 1278c2ecf20Sopenharmony_ci usleep(sleep_time); 1288c2ecf20Sopenharmony_ci ROUNDS(calculations); 1298c2ecf20Sopenharmony_ci then = get_time(); 1308c2ecf20Sopenharmony_ci performance_time += then - now - sleep_time; 1318c2ecf20Sopenharmony_ci if (config->verbose) 1328c2ecf20Sopenharmony_ci printf("performance cycle took %lius, " 1338c2ecf20Sopenharmony_ci "sleep: %lius, " 1348c2ecf20Sopenharmony_ci "load: %lius, rounds: %u\n", 1358c2ecf20Sopenharmony_ci (long)(then - now), sleep_time, 1368c2ecf20Sopenharmony_ci load_time, calculations); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci fprintf(config->output, "%li ", 1398c2ecf20Sopenharmony_ci performance_time / config->cycles); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci progress_time += sleep_time + load_time; 1428c2ecf20Sopenharmony_ci show_progress(total_time, progress_time); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* set the powersave governor which activates P-State switching 1458c2ecf20Sopenharmony_ci * again */ 1468c2ecf20Sopenharmony_ci if (set_cpufreq_governor(config->governor, config->cpu) != 0) 1478c2ecf20Sopenharmony_ci return; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* again, do some sleep/load cycles with the 1508c2ecf20Sopenharmony_ci * powersave governor */ 1518c2ecf20Sopenharmony_ci for (cycle = 0; cycle < config->cycles; cycle++) { 1528c2ecf20Sopenharmony_ci now = get_time(); 1538c2ecf20Sopenharmony_ci usleep(sleep_time); 1548c2ecf20Sopenharmony_ci ROUNDS(calculations); 1558c2ecf20Sopenharmony_ci then = get_time(); 1568c2ecf20Sopenharmony_ci powersave_time += then - now - sleep_time; 1578c2ecf20Sopenharmony_ci if (config->verbose) 1588c2ecf20Sopenharmony_ci printf("powersave cycle took %lius, " 1598c2ecf20Sopenharmony_ci "sleep: %lius, " 1608c2ecf20Sopenharmony_ci "load: %lius, rounds: %u\n", 1618c2ecf20Sopenharmony_ci (long)(then - now), sleep_time, 1628c2ecf20Sopenharmony_ci load_time, calculations); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci progress_time += sleep_time + load_time; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* compare the average sleep/load cycles */ 1688c2ecf20Sopenharmony_ci fprintf(config->output, "%li ", 1698c2ecf20Sopenharmony_ci powersave_time / config->cycles); 1708c2ecf20Sopenharmony_ci fprintf(config->output, "%.3f\n", 1718c2ecf20Sopenharmony_ci performance_time * 100.0 / powersave_time); 1728c2ecf20Sopenharmony_ci fflush(config->output); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (config->verbose) 1758c2ecf20Sopenharmony_ci printf("performance is at %.2f%%\n", 1768c2ecf20Sopenharmony_ci performance_time * 100.0 / powersave_time); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci sleep_time += config->sleep_step; 1798c2ecf20Sopenharmony_ci load_time += config->load_step; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci} 182