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