1//===-- Common utility class for differential analysis --------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "src/__support/FPUtil/FPBits.h"
10#include "test/src/math/performance_testing/Timer.h"
11
12#include <fstream>
13
14namespace LIBC_NAMESPACE {
15namespace testing {
16
17template <typename T> class SingleInputSingleOutputPerf {
18 using FPBits = fputil::FPBits<T>;
19 using StorageType = typename FPBits::StorageType;
20 static constexpr StorageType UIntMax =
21 cpp::numeric_limits<StorageType>::max();
22
23public:
24 typedef T Func(T);
25
26 static void runPerfInRange(Func myFunc, Func otherFunc,
27 StorageType startingBit, StorageType endingBit,
28 std::ofstream &log) {
29 auto runner = [=](Func func) {
30 constexpr StorageType N = 10'010'001;
31 StorageType step = (endingBit - startingBit) / N;
32 if (step == 0)
33 step = 1;
34 volatile T result;
35 for (StorageType bits = startingBit; bits < endingBit; bits += step) {
36 T x = FPBits(bits).get_val();
37 result = func(x);
38 }
39 };
40
41 Timer timer;
42 timer.start();
43 runner(myFunc);
44 timer.stop();
45
46 StorageType numberOfRuns = endingBit - startingBit + 1;
47 double myAverage = static_cast<double>(timer.nanoseconds()) / numberOfRuns;
48 log << "-- My function --\n";
49 log << " Total time : " << timer.nanoseconds() << " ns \n";
50 log << " Average runtime : " << myAverage << " ns/op \n";
51 log << " Ops per second : "
52 << static_cast<uint64_t>(1'000'000'000.0 / myAverage) << " op/s \n";
53
54 timer.start();
55 runner(otherFunc);
56 timer.stop();
57
58 double otherAverage =
59 static_cast<double>(timer.nanoseconds()) / numberOfRuns;
60 log << "-- Other function --\n";
61 log << " Total time : " << timer.nanoseconds() << " ns \n";
62 log << " Average runtime : " << otherAverage << " ns/op \n";
63 log << " Ops per second : "
64 << static_cast<uint64_t>(1'000'000'000.0 / otherAverage) << " op/s \n";
65
66 log << "-- Average runtime ratio --\n";
67 log << " Mine / Other's : " << myAverage / otherAverage << " \n";
68 }
69
70 static void runPerf(Func myFunc, Func otherFunc, const char *logFile) {
71 std::ofstream log(logFile);
72 log << " Performance tests with inputs in denormal range:\n";
73 runPerfInRange(myFunc, otherFunc, /* startingBit= */ startingBit: StorageType(0),
74 /* endingBit= */ endingBit: FPBits::max_subnormal().uintval(), log);
75 log << "\n Performance tests with inputs in normal range:\n";
76 runPerfInRange(myFunc, otherFunc,
77 /* startingBit= */ startingBit: FPBits::min_normal().uintval(),
78 /* endingBit= */ endingBit: FPBits::max_normal().uintval(), log);
79 }
80};
81
82} // namespace testing
83} // namespace LIBC_NAMESPACE
84
85#define SINGLE_INPUT_SINGLE_OUTPUT_PERF(T, myFunc, otherFunc, filename) \
86 int main() { \
87 LIBC_NAMESPACE::testing::SingleInputSingleOutputPerf<T>::runPerf( \
88 &myFunc, &otherFunc, filename); \
89 return 0; \
90 }
91

source code of libc/test/src/math/performance_testing/SingleInputSingleOutputPerf.h