1 /*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <fenv.h>
18 #include <math.h>
19
20 #include <benchmark/benchmark.h>
21 #include "util.h"
22
23 static const double values[] = { 1234.0, nan(""), HUGE_VAL, 0.0 };
24 static const char* names[] = { "1234.0", "nan", "HUGE_VAL", "0.0" };
25
SetLabel(benchmark::State & state)26 static void SetLabel(benchmark::State& state) {
27 state.SetLabel(names[state.range(0)]);
28 }
29
30 // Avoid optimization.
31 volatile double d;
32 volatile double v;
33 volatile float f;
34
35 static float zero = 0.0f;
36 static double zerod = 0.0f;
37
BM_math_sqrt(benchmark::State & state)38 static void BM_math_sqrt(benchmark::State& state) {
39 d = 0.0;
40 v = 2.0;
41 while (state.KeepRunning()) {
42 d += sqrt(v);
43 }
44 }
45 BIONIC_BENCHMARK(BM_math_sqrt);
46
BM_math_log10(benchmark::State & state)47 static void BM_math_log10(benchmark::State& state) {
48 d = 0.0;
49 v = 1234.0;
50 while (state.KeepRunning()) {
51 d += log10(v);
52 }
53 }
54 BIONIC_BENCHMARK(BM_math_log10);
55
BM_math_logb(benchmark::State & state)56 static void BM_math_logb(benchmark::State& state) {
57 d = 0.0;
58 v = 1234.0;
59 while (state.KeepRunning()) {
60 d += logb(v);
61 }
62 }
63 BIONIC_BENCHMARK(BM_math_logb);
64
BM_math_isfinite_macro(benchmark::State & state)65 static void BM_math_isfinite_macro(benchmark::State& state) {
66 d = 0.0;
67 v = values[state.range(0)];
68 while (state.KeepRunning()) {
69 d += isfinite(v);
70 }
71 SetLabel(state);
72 }
73 BIONIC_BENCHMARK_WITH_ARG(BM_math_isfinite_macro, "MATH_COMMON");
74
BM_math_isfinite(benchmark::State & state)75 static void BM_math_isfinite(benchmark::State& state) {
76 d = 0.0;
77 v = values[state.range(0)];
78 while (state.KeepRunning()) {
79 d += isfinite(v);
80 }
81 SetLabel(state);
82 }
83 BIONIC_BENCHMARK_WITH_ARG(BM_math_isfinite, "MATH_COMMON");
84
BM_math_isinf_macro(benchmark::State & state)85 static void BM_math_isinf_macro(benchmark::State& state) {
86 d = 0.0;
87 v = values[state.range(0)];
88 while (state.KeepRunning()) {
89 d += isinf(v);
90 }
91 SetLabel(state);
92 }
93 BIONIC_BENCHMARK_WITH_ARG(BM_math_isinf_macro, "MATH_COMMON");
94
BM_math_isinf(benchmark::State & state)95 static void BM_math_isinf(benchmark::State& state) {
96 d = 0.0;
97 v = values[state.range(0)];
98 while (state.KeepRunning()) {
99 d += (isinf)(v);
100 }
101 SetLabel(state);
102 }
103 BIONIC_BENCHMARK_WITH_ARG(BM_math_isinf, "MATH_COMMON");
104
BM_math_isnan_macro(benchmark::State & state)105 static void BM_math_isnan_macro(benchmark::State& state) {
106 d = 0.0;
107 v = values[state.range(0)];
108 while (state.KeepRunning()) {
109 d += isnan(v);
110 }
111 SetLabel(state);
112 }
113 BIONIC_BENCHMARK_WITH_ARG(BM_math_isnan_macro, "MATH_COMMON");
114
BM_math_isnan(benchmark::State & state)115 static void BM_math_isnan(benchmark::State& state) {
116 d = 0.0;
117 v = values[state.range(0)];
118 while (state.KeepRunning()) {
119 d += (isnan)(v);
120 }
121 SetLabel(state);
122 }
123 BIONIC_BENCHMARK_WITH_ARG(BM_math_isnan, "MATH_COMMON");
124
BM_math_isnormal_macro(benchmark::State & state)125 static void BM_math_isnormal_macro(benchmark::State& state) {
126 d = 0.0;
127 v = values[state.range(0)];
128 while (state.KeepRunning()) {
129 d += isnormal(v);
130 }
131 SetLabel(state);
132 }
133 BIONIC_BENCHMARK_WITH_ARG(BM_math_isnormal_macro, "MATH_COMMON");
134
BM_math_isnormal(benchmark::State & state)135 static void BM_math_isnormal(benchmark::State& state) {
136 d = 0.0;
137 v = values[state.range(0)];
138 while (state.KeepRunning()) {
139 d += isnormal(v);
140 }
141 SetLabel(state);
142 }
143 BIONIC_BENCHMARK_WITH_ARG(BM_math_isnormal, "MATH_COMMON");
144
BM_math_sin_fast(benchmark::State & state)145 static void BM_math_sin_fast(benchmark::State& state) {
146 d = 1.0;
147 while (state.KeepRunning()) {
148 d += sin(d);
149 }
150 }
151 BIONIC_BENCHMARK(BM_math_sin_fast);
152
BM_math_sin_feupdateenv(benchmark::State & state)153 static void BM_math_sin_feupdateenv(benchmark::State& state) {
154 d = 1.0;
155 while (state.KeepRunning()) {
156 fenv_t __libc_save_rm;
157 feholdexcept(&__libc_save_rm);
158 fesetround(FE_TONEAREST);
159 d += sin(d);
160 feupdateenv(&__libc_save_rm);
161 }
162 }
163 BIONIC_BENCHMARK(BM_math_sin_feupdateenv);
164
BM_math_sin_fesetenv(benchmark::State & state)165 static void BM_math_sin_fesetenv(benchmark::State& state) {
166 d = 1.0;
167 while (state.KeepRunning()) {
168 fenv_t __libc_save_rm;
169 feholdexcept(&__libc_save_rm);
170 fesetround(FE_TONEAREST);
171 d += sin(d);
172 fesetenv(&__libc_save_rm);
173 }
174 }
175 BIONIC_BENCHMARK(BM_math_sin_fesetenv);
176
BM_math_fpclassify(benchmark::State & state)177 static void BM_math_fpclassify(benchmark::State& state) {
178 d = 0.0;
179 v = values[state.range(0)];
180 while (state.KeepRunning()) {
181 d += fpclassify(v);
182 }
183 SetLabel(state);
184 }
185 BIONIC_BENCHMARK_WITH_ARG(BM_math_fpclassify, "MATH_COMMON");
186
BM_math_signbit_macro(benchmark::State & state)187 static void BM_math_signbit_macro(benchmark::State& state) {
188 d = 0.0;
189 v = values[state.range(0)];
190 while (state.KeepRunning()) {
191 d += signbit(v);
192 }
193 SetLabel(state);
194 }
195 BIONIC_BENCHMARK_WITH_ARG(BM_math_signbit_macro, "MATH_COMMON");
196
BM_math_signbit(benchmark::State & state)197 static void BM_math_signbit(benchmark::State& state) {
198 d = 0.0;
199 v = values[state.range(0)];
200 while (state.KeepRunning()) {
201 d += signbit(v);
202 }
203 SetLabel(state);
204 }
205 BIONIC_BENCHMARK_WITH_ARG(BM_math_signbit, "MATH_COMMON");
206
BM_math_fabs_macro(benchmark::State & state)207 static void BM_math_fabs_macro(benchmark::State& state) {
208 d = 0.0;
209 v = values[state.range(0)];
210 while (state.KeepRunning()) {
211 d += fabs(v);
212 }
213 SetLabel(state);
214 }
215 BIONIC_BENCHMARK_WITH_ARG(BM_math_fabs_macro, "MATH_COMMON");
216
BM_math_fabs(benchmark::State & state)217 static void BM_math_fabs(benchmark::State& state) {
218 d = 0.0;
219 v = values[state.range(0)];
220 while (state.KeepRunning()) {
221 d += (fabs)(v);
222 }
223 SetLabel(state);
224 }
225 BIONIC_BENCHMARK_WITH_ARG(BM_math_fabs, "MATH_COMMON");
226
BM_math_sincos(benchmark::State & state)227 static void BM_math_sincos(benchmark::State& state) {
228 d = 1.0;
229 while (state.KeepRunning()) {
230 double s, c;
231 sincos(d, &s, &c);
232 d += s + c;
233 }
234 }
235 BIONIC_BENCHMARK(BM_math_sincos);
236
237 #include "expf_input.cpp"
238
BM_math_expf_speccpu2017(benchmark::State & state)239 static void BM_math_expf_speccpu2017(benchmark::State& state) {
240 f = 0.0;
241 auto cin = expf_input.cbegin();
242 for (auto _ : state) {
243 f = expf(*cin);
244 if (++cin == expf_input.cend())
245 cin = expf_input.cbegin();
246 }
247 }
248 BIONIC_BENCHMARK(BM_math_expf_speccpu2017);
249
BM_math_expf_speccpu2017_latency(benchmark::State & state)250 static void BM_math_expf_speccpu2017_latency(benchmark::State& state) {
251 f = 0.0;
252 auto cin = expf_input.cbegin();
253 for (auto _ : state) {
254 f = expf(f * zero + *cin);
255 if (++cin == expf_input.cend())
256 cin = expf_input.cbegin();
257 }
258 }
259 BIONIC_BENCHMARK(BM_math_expf_speccpu2017_latency);
260
261 // Create a double version of expf_input to avoid overhead of float to
262 // double conversion.
263 static const std::vector<double> exp_input (expf_input.begin(),
264 expf_input.end());
265
BM_math_exp_speccpu2017(benchmark::State & state)266 static void BM_math_exp_speccpu2017(benchmark::State& state) {
267 d = 0.0;
268 auto cin = exp_input.cbegin();
269 for (auto _ : state) {
270 d = exp(*cin);
271 if (++cin == exp_input.cend())
272 cin = exp_input.cbegin();
273 }
274 }
275 BIONIC_BENCHMARK(BM_math_exp_speccpu2017);
276
BM_math_exp_speccpu2017_latency(benchmark::State & state)277 static void BM_math_exp_speccpu2017_latency(benchmark::State& state) {
278 d = 0.0;
279 auto cin = exp_input.cbegin();
280 for (auto _ : state) {
281 d = exp(d * zerod + *cin);
282 if (++cin == exp_input.cend())
283 cin = exp_input.cbegin();
284 }
285 }
286 BIONIC_BENCHMARK(BM_math_exp_speccpu2017_latency);
287
BM_math_exp2f_speccpu2017(benchmark::State & state)288 static void BM_math_exp2f_speccpu2017(benchmark::State& state) {
289 f = 0.0;
290 auto cin = expf_input.cbegin();
291 for (auto _ : state) {
292 f = exp2f(*cin);
293 if (++cin == expf_input.cend())
294 cin = expf_input.cbegin();
295 }
296 }
297 BIONIC_BENCHMARK(BM_math_exp2f_speccpu2017);
298
BM_math_exp2f_speccpu2017_latency(benchmark::State & state)299 static void BM_math_exp2f_speccpu2017_latency(benchmark::State& state) {
300 f = 0.0;
301 auto cin = expf_input.cbegin();
302 for (auto _ : state) {
303 f = exp2f(f * zero + *cin);
304 if (++cin == expf_input.cend())
305 cin = expf_input.cbegin();
306 }
307 }
308 BIONIC_BENCHMARK(BM_math_exp2f_speccpu2017_latency);
309
BM_math_exp2_speccpu2017(benchmark::State & state)310 static void BM_math_exp2_speccpu2017(benchmark::State& state) {
311 d = 0.0;
312 auto cin = exp_input.cbegin();
313 for (auto _ : state) {
314 f = exp2(*cin);
315 if (++cin == exp_input.cend())
316 cin = exp_input.cbegin();
317 }
318 }
319 BIONIC_BENCHMARK(BM_math_exp2_speccpu2017);
320
BM_math_exp2_speccpu2017_latency(benchmark::State & state)321 static void BM_math_exp2_speccpu2017_latency(benchmark::State& state) {
322 d = 0.0;
323 auto cin = exp_input.cbegin();
324 for (auto _ : state) {
325 f = exp2(d * zero + *cin);
326 if (++cin == exp_input.cend())
327 cin = exp_input.cbegin();
328 }
329 }
330 BIONIC_BENCHMARK(BM_math_exp2_speccpu2017_latency);
331
332 #include "powf_input.cpp"
333
334 static const std::vector<std::pair<double, double>> pow_input
335 (powf_input.begin(), powf_input.end());
336
BM_math_powf_speccpu2006(benchmark::State & state)337 static void BM_math_powf_speccpu2006(benchmark::State& state) {
338 f = 0.0;
339 auto cin = powf_input.cbegin();
340 for (auto _ : state) {
341 f = powf(cin->first, cin->second);
342 if (++cin == powf_input.cend())
343 cin = powf_input.cbegin();
344 }
345 }
346 BIONIC_BENCHMARK(BM_math_powf_speccpu2006);
347
BM_math_powf_speccpu2017_latency(benchmark::State & state)348 static void BM_math_powf_speccpu2017_latency(benchmark::State& state) {
349 f = 0.0;
350 auto cin = powf_input.cbegin();
351 for (auto _ : state) {
352 f = powf(f * zero + cin->first, cin->second);
353 if (++cin == powf_input.cend())
354 cin = powf_input.cbegin();
355 }
356 }
357 BIONIC_BENCHMARK(BM_math_powf_speccpu2017_latency);
358
BM_math_pow_speccpu2006(benchmark::State & state)359 static void BM_math_pow_speccpu2006(benchmark::State& state) {
360 d = 0.0;
361 auto cin = pow_input.cbegin();
362 for (auto _ : state) {
363 f = pow(cin->first, cin->second);
364 if (++cin == pow_input.cend())
365 cin = pow_input.cbegin();
366 }
367 }
368 BIONIC_BENCHMARK(BM_math_pow_speccpu2006);
369
BM_math_pow_speccpu2017_latency(benchmark::State & state)370 static void BM_math_pow_speccpu2017_latency(benchmark::State& state) {
371 d = 0.0;
372 auto cin = pow_input.cbegin();
373 for (auto _ : state) {
374 d = powf(d * zero + cin->first, cin->second);
375 if (++cin == pow_input.cend())
376 cin = pow_input.cbegin();
377 }
378 }
379 BIONIC_BENCHMARK(BM_math_pow_speccpu2017_latency);
380
381 #include "logf_input.cpp"
382
383 static const std::vector<double> log_input (logf_input.begin(),
384 logf_input.end());
385
BM_math_logf_speccpu2017(benchmark::State & state)386 static void BM_math_logf_speccpu2017(benchmark::State& state) {
387 f = 0.0;
388 auto cin = logf_input.cbegin();
389 for (auto _ : state) {
390 f = logf(*cin);
391 if (++cin == logf_input.cend())
392 cin = logf_input.cbegin();
393 }
394 }
395 BIONIC_BENCHMARK(BM_math_logf_speccpu2017);
396
BM_math_logf_speccpu2017_latency(benchmark::State & state)397 static void BM_math_logf_speccpu2017_latency(benchmark::State& state) {
398 f = 0.0;
399 auto cin = logf_input.cbegin();
400 for (auto _ : state) {
401 f = logf(f * zero + *cin);
402 if (++cin == logf_input.cend())
403 cin = logf_input.cbegin();
404 }
405 }
406 BIONIC_BENCHMARK(BM_math_logf_speccpu2017_latency);
407
BM_math_log_speccpu2017(benchmark::State & state)408 static void BM_math_log_speccpu2017(benchmark::State& state) {
409 d = 0.0;
410 auto cin = log_input.cbegin();
411 for (auto _ : state) {
412 d = log(*cin);
413 if (++cin == log_input.cend())
414 cin = log_input.cbegin();
415 }
416 }
417 BIONIC_BENCHMARK(BM_math_log_speccpu2017);
418
BM_math_log_speccpu2017_latency(benchmark::State & state)419 static void BM_math_log_speccpu2017_latency(benchmark::State& state) {
420 d = 0.0;
421 auto cin = log_input.cbegin();
422 for (auto _ : state) {
423 d = log(d * zerod + *cin);
424 if (++cin == log_input.cend())
425 cin = log_input.cbegin();
426 }
427 }
428 BIONIC_BENCHMARK(BM_math_log_speccpu2017_latency);
429
BM_math_log2f_speccpu2017(benchmark::State & state)430 static void BM_math_log2f_speccpu2017(benchmark::State& state) {
431 f = 0.0;
432 auto cin = logf_input.cbegin();
433 for (auto _ : state) {
434 f = log2f(*cin);
435 if (++cin == logf_input.cend())
436 cin = logf_input.cbegin();
437 }
438 }
439 BIONIC_BENCHMARK(BM_math_log2f_speccpu2017);
440
BM_math_log2_speccpu2017_latency(benchmark::State & state)441 static void BM_math_log2_speccpu2017_latency(benchmark::State& state) {
442 d = 0.0;
443 auto cin = log_input.cbegin();
444 for (auto _ : state) {
445 d = log2(d * zerod + *cin);
446 if (++cin == log_input.cend())
447 cin = log_input.cbegin();
448 }
449 }
450 BIONIC_BENCHMARK(BM_math_log2_speccpu2017_latency);
451
BM_math_log2_speccpu2017(benchmark::State & state)452 static void BM_math_log2_speccpu2017(benchmark::State& state) {
453 d = 0.0;
454 auto cin = log_input.cbegin();
455 for (auto _ : state) {
456 d = log2(*cin);
457 if (++cin == log_input.cend())
458 cin = log_input.cbegin();
459 }
460 }
461 BIONIC_BENCHMARK(BM_math_log2_speccpu2017);
462
BM_math_log2f_speccpu2017_latency(benchmark::State & state)463 static void BM_math_log2f_speccpu2017_latency(benchmark::State& state) {
464 f = 0.0;
465 auto cin = logf_input.cbegin();
466 for (auto _ : state) {
467 f = log2f(f * zero + *cin);
468 if (++cin == logf_input.cend())
469 cin = logf_input.cbegin();
470 }
471 }
472 BIONIC_BENCHMARK(BM_math_log2f_speccpu2017_latency);
473
474 // Four ranges of values are checked:
475 // * 0.0 <= x < 0.1
476 // * 0.1 <= x < 0.7
477 // * 0.7 <= x < 3.1
478 // * -3.1 <= x < 3.1
479 // * 3.3 <= x < 33.3
480 // * 100.0 <= x < 1000.0
481 // * 1e6 <= x < 1e32
482 // * 1e32 < x < FLT_MAX
483
484 #include "sincosf_input.cpp"
485
BM_math_sinf(benchmark::State & state)486 static void BM_math_sinf(benchmark::State& state) {
487 auto range = sincosf_input[state.range(0)];
488 auto cin = range.values.cbegin();
489 f = 0.0;
490 for (auto _ : state) {
491 f = sinf(*cin);
492 if (++cin == range.values.cend())
493 cin = range.values.cbegin();
494 }
495 state.SetLabel(range.label);
496 }
497 BIONIC_BENCHMARK_WITH_ARG(BM_math_sinf, "MATH_SINCOS_COMMON");
498
BM_math_sinf_latency(benchmark::State & state)499 static void BM_math_sinf_latency(benchmark::State& state) {
500 auto range = sincosf_input[state.range(0)];
501 auto cin = range.values.cbegin();
502 f = 0.0;
503 for (auto _ : state) {
504 f = sinf(f * zero + *cin);
505 if (++cin == range.values.cend())
506 cin = range.values.cbegin();
507 }
508 state.SetLabel(range.label);
509 }
510 BIONIC_BENCHMARK_WITH_ARG(BM_math_sinf_latency, "MATH_SINCOS_COMMON");
511
BM_math_cosf(benchmark::State & state)512 static void BM_math_cosf(benchmark::State& state) {
513 auto range = sincosf_input[state.range(0)];
514 auto cin = range.values.cbegin();
515 f = 0.0;
516 for (auto _ : state) {
517 f = cosf(*cin);
518 if (++cin == range.values.cend())
519 cin = range.values.cbegin();
520 }
521 state.SetLabel(range.label);
522 }
523 BIONIC_BENCHMARK_WITH_ARG(BM_math_cosf, "MATH_SINCOS_COMMON");
524
BM_math_cosf_latency(benchmark::State & state)525 static void BM_math_cosf_latency(benchmark::State& state) {
526 auto range = sincosf_input[state.range(0)];
527 auto cin = range.values.cbegin();
528 f = 0.0;
529 for (auto _ : state) {
530 f = cosf(f * zero + *cin);
531 if (++cin == range.values.cend())
532 cin = range.values.cbegin();
533 }
534 state.SetLabel(range.label);
535 }
536 BIONIC_BENCHMARK_WITH_ARG(BM_math_cosf_latency, "MATH_SINCOS_COMMON");
537
BM_math_sincosf(benchmark::State & state)538 static void BM_math_sincosf(benchmark::State& state) {
539 auto range = sincosf_input[state.range(0)];
540 auto cin = range.values.cbegin();
541 f = 0.0;
542 for (auto _ : state) {
543 float s, c;
544 sincosf(*cin, &s, &c);
545 f += s;
546 if (++cin == range.values.cend())
547 cin = range.values.cbegin();
548 }
549 state.SetLabel(range.label);
550 }
551 BIONIC_BENCHMARK_WITH_ARG(BM_math_sincosf, "MATH_SINCOS_COMMON");
552
BM_math_sincosf_latency(benchmark::State & state)553 static void BM_math_sincosf_latency(benchmark::State& state) {
554 auto range = sincosf_input[state.range(0)];
555 auto cin = range.values.cbegin();
556 f = 0.0;
557 for (auto _ : state) {
558 float s, c;
559 sincosf(f * zero + *cin, &s, &c);
560 f += s;
561 if (++cin == range.values.cend())
562 cin = range.values.cbegin();
563 }
564 state.SetLabel(range.label);
565 }
566 BIONIC_BENCHMARK_WITH_ARG(BM_math_sincosf_latency, "MATH_SINCOS_COMMON");
567