Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libc / test / src / math / differential_testing / SingleInputSingleOutputDiff.h
blobc20cf3152f622009274836ab2cccd0fcda28fbfb
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 //===----------------------------------------------------------------------===//
9 #include "src/__support/FPUtil/FPBits.h"
10 #include "test/src/math/differential_testing/Timer.h"
12 #include <fstream>
14 namespace LIBC_NAMESPACE {
15 namespace testing {
17 template <typename T> class SingleInputSingleOutputDiff {
18 using FPBits = fputil::FPBits<T>;
19 using UIntType = typename FPBits::UIntType;
20 static constexpr UIntType MSBit = UIntType(1) << (8 * sizeof(UIntType) - 1);
21 static constexpr UIntType UIntMax = (MSBit - 1) + MSBit;
23 public:
24 typedef T Func(T);
26 static void runDiff(Func myFunc, Func otherFunc, const char *logFile) {
27 UIntType diffCount = 0;
28 std::ofstream log(logFile);
29 log << "Starting diff for values from 0 to " << UIntMax << '\n'
30 << "Only differing results will be logged.\n\n";
31 for (UIntType bits = 0;; ++bits) {
32 T x = T(FPBits(bits));
33 T myResult = myFunc(x);
34 T otherResult = otherFunc(x);
35 UIntType myBits = FPBits(myResult).uintval();
36 UIntType otherBits = FPBits(otherResult).uintval();
37 if (myBits != otherBits) {
38 ++diffCount;
39 log << " Input: " << bits << " (" << x << ")\n"
40 << " My result: " << myBits << " (" << myResult << ")\n"
41 << "Other result: " << otherBits << " (" << otherResult << ")\n"
42 << '\n';
44 if (bits == UIntMax)
45 break;
47 log << "Total number of differing results: " << diffCount << '\n';
50 static void runPerfInRange(Func myFunc, Func otherFunc, UIntType startingBit,
51 UIntType endingBit, std::ofstream &log) {
52 auto runner = [=](Func func) {
53 volatile T result;
54 for (UIntType bits = startingBit;; ++bits) {
55 T x = T(FPBits(bits));
56 result = func(x);
57 if (bits == endingBit)
58 break;
62 Timer timer;
63 timer.start();
64 runner(myFunc);
65 timer.stop();
67 UIntType numberOfRuns = endingBit - startingBit + 1;
68 double myAverage = static_cast<double>(timer.nanoseconds()) / numberOfRuns;
69 log << "-- My function --\n";
70 log << " Total time : " << timer.nanoseconds() << " ns \n";
71 log << " Average runtime : " << myAverage << " ns/op \n";
72 log << " Ops per second : "
73 << static_cast<uint64_t>(1'000'000'000.0 / myAverage) << " op/s \n";
75 timer.start();
76 runner(otherFunc);
77 timer.stop();
79 double otherAverage =
80 static_cast<double>(timer.nanoseconds()) / numberOfRuns;
81 log << "-- Other function --\n";
82 log << " Total time : " << timer.nanoseconds() << " ns \n";
83 log << " Average runtime : " << otherAverage << " ns/op \n";
84 log << " Ops per second : "
85 << static_cast<uint64_t>(1'000'000'000.0 / otherAverage) << " op/s \n";
87 log << "-- Average runtime ratio --\n";
88 log << " Mine / Other's : " << myAverage / otherAverage << " \n";
91 static void runPerf(Func myFunc, Func otherFunc, const char *logFile) {
92 std::ofstream log(logFile);
93 log << " Performance tests with inputs in denormal range:\n";
94 runPerfInRange(myFunc, otherFunc, /* startingBit= */ UIntType(0),
95 /* endingBit= */ FPBits::MAX_SUBNORMAL, log);
96 log << "\n Performance tests with inputs in normal range:\n";
97 runPerfInRange(myFunc, otherFunc, /* startingBit= */ FPBits::MIN_NORMAL,
98 /* endingBit= */ FPBits::MAX_NORMAL, log);
102 } // namespace testing
103 } // namespace LIBC_NAMESPACE
105 #define SINGLE_INPUT_SINGLE_OUTPUT_DIFF(T, myFunc, otherFunc, filename) \
106 int main() { \
107 LIBC_NAMESPACE::testing::SingleInputSingleOutputDiff<T>::runDiff( \
108 &myFunc, &otherFunc, filename); \
109 return 0; \
112 #define SINGLE_INPUT_SINGLE_OUTPUT_PERF(T, myFunc, otherFunc, filename) \
113 int main() { \
114 LIBC_NAMESPACE::testing::SingleInputSingleOutputDiff<T>::runPerf( \
115 &myFunc, &otherFunc, filename); \
116 return 0; \