1 //===-- Common utility class for differential analysis --------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "src/__support/FPUtil/FPBits.h"
10 #include "test/src/math/differential_testing/Timer.h"
14 namespace LIBC_NAMESPACE
{
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
;
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
) {
39 log
<< " Input: " << bits
<< " (" << x
<< ")\n"
40 << " My result: " << myBits
<< " (" << myResult
<< ")\n"
41 << "Other result: " << otherBits
<< " (" << otherResult
<< ")\n"
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
) {
54 for (UIntType bits
= startingBit
;; ++bits
) {
55 T x
= T(FPBits(bits
));
57 if (bits
== endingBit
)
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";
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) \
107 LIBC_NAMESPACE::testing::SingleInputSingleOutputDiff<T>::runDiff( \
108 &myFunc, &otherFunc, filename); \
112 #define SINGLE_INPUT_SINGLE_OUTPUT_PERF(T, myFunc, otherFunc, filename) \
114 LIBC_NAMESPACE::testing::SingleInputSingleOutputDiff<T>::runPerf( \
115 &myFunc, &otherFunc, filename); \