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 "utils/testutils/StreamWrapper.h" 11 #include "utils/testutils/Timer.h" 12 13 namespace __llvm_libc { 14 namespace testing { 15 16 template <typename T> class SingleInputSingleOutputDiff { 17 using FPBits = fputil::FPBits<T>; 18 using UIntType = typename FPBits::UIntType; 19 static constexpr UIntType MSBit = UIntType(1) << (8 * sizeof(UIntType) - 1); 20 static constexpr UIntType UIntMax = (MSBit - 1) + MSBit; 21 22 public: 23 typedef T Func(T); 24 25 static void runDiff(Func myFunc, Func otherFunc, const char *logFile) { 26 UIntType diffCount = 0; 27 testutils::OutputFileStream log(logFile); 28 log << "Starting diff for values from 0 to " << UIntMax << '\n' 29 << "Only differing results will be logged.\n\n"; 30 for (UIntType bits = 0;; ++bits) { 31 T x = T(FPBits(bits)); 32 T myResult = myFunc(x); 33 T otherResult = otherFunc(x); 34 UIntType myBits = FPBits(myResult).uintval(); 35 UIntType otherBits = FPBits(otherResult).uintval(); 36 if (myBits != otherBits) { 37 ++diffCount; 38 log << " Input: " << bits << " (" << x << ")\n" 39 << " My result: " << myBits << " (" << myResult << ")\n" 40 << "Other result: " << otherBits << " (" << otherResult << ")\n" 41 << '\n'; 42 } 43 if (bits == UIntMax) 44 break; 45 } 46 log << "Total number of differing results: " << diffCount << '\n'; 47 } 48 49 static void runPerf(Func myFunc, Func otherFunc, const char *logFile) { 50 auto runner = [](Func func) { 51 volatile T result; 52 for (UIntType bits = 0;; ++bits) { 53 T x = T(FPBits(bits)); 54 result = func(x); 55 if (bits == UIntMax) 56 break; 57 } 58 }; 59 60 testutils::OutputFileStream log(logFile); 61 Timer timer; 62 timer.start(); 63 runner(myFunc); 64 timer.stop(); 65 log << " Run time of my function: " << timer.nanoseconds() << " ns \n"; 66 67 timer.start(); 68 runner(otherFunc); 69 timer.stop(); 70 log << "Run time of other function: " << timer.nanoseconds() << " ns \n"; 71 } 72 }; 73 74 } // namespace testing 75 } // namespace __llvm_libc 76 77 #define SINGLE_INPUT_SINGLE_OUTPUT_DIFF(T, myFunc, otherFunc, filename) \ 78 int main() { \ 79 __llvm_libc::testing::SingleInputSingleOutputDiff<T>::runDiff( \ 80 &myFunc, &otherFunc, filename); \ 81 return 0; \ 82 } 83 84 #define SINGLE_INPUT_SINGLE_OUTPUT_PERF(T, myFunc, otherFunc, filename) \ 85 int main() { \ 86 __llvm_libc::testing::SingleInputSingleOutputDiff<T>::runPerf( \ 87 &myFunc, &otherFunc, filename); \ 88 return 0; \ 89 } 90