1c6aa206bSSiva Chandra Reddy //===-- Common utility class for differential analysis --------------------===// 2c6aa206bSSiva Chandra Reddy // 3c6aa206bSSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4c6aa206bSSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information. 5c6aa206bSSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c6aa206bSSiva Chandra Reddy // 7c6aa206bSSiva Chandra Reddy //===----------------------------------------------------------------------===// 8c6aa206bSSiva Chandra Reddy 9c120edc7SMichael Jones #include "src/__support/FPUtil/FPBits.h" 10c6aa206bSSiva Chandra Reddy #include "utils/testutils/StreamWrapper.h" 11c6aa206bSSiva Chandra Reddy #include "utils/testutils/Timer.h" 12c6aa206bSSiva Chandra Reddy 13c6aa206bSSiva Chandra Reddy namespace __llvm_libc { 14c6aa206bSSiva Chandra Reddy namespace testing { 15c6aa206bSSiva Chandra Reddy 16c6aa206bSSiva Chandra Reddy template <typename T> class SingleInputSingleOutputDiff { 17c6aa206bSSiva Chandra Reddy using FPBits = fputil::FPBits<T>; 18c6aa206bSSiva Chandra Reddy using UIntType = typename FPBits::UIntType; 19c6aa206bSSiva Chandra Reddy static constexpr UIntType MSBit = UIntType(1) << (8 * sizeof(UIntType) - 1); 20c6aa206bSSiva Chandra Reddy static constexpr UIntType UIntMax = (MSBit - 1) + MSBit; 21c6aa206bSSiva Chandra Reddy 22c6aa206bSSiva Chandra Reddy public: 23c6aa206bSSiva Chandra Reddy typedef T Func(T); 24c6aa206bSSiva Chandra Reddy runDiff(Func myFunc,Func otherFunc,const char * logFile)25c6aa206bSSiva Chandra Reddy static void runDiff(Func myFunc, Func otherFunc, const char *logFile) { 26c6aa206bSSiva Chandra Reddy UIntType diffCount = 0; 27c6aa206bSSiva Chandra Reddy testutils::OutputFileStream log(logFile); 28c6aa206bSSiva Chandra Reddy log << "Starting diff for values from 0 to " << UIntMax << '\n' 29c6aa206bSSiva Chandra Reddy << "Only differing results will be logged.\n\n"; 30c6aa206bSSiva Chandra Reddy for (UIntType bits = 0;; ++bits) { 31c6aa206bSSiva Chandra Reddy T x = T(FPBits(bits)); 32c6aa206bSSiva Chandra Reddy T myResult = myFunc(x); 33c6aa206bSSiva Chandra Reddy T otherResult = otherFunc(x); 34c6aa206bSSiva Chandra Reddy UIntType myBits = FPBits(myResult).uintval(); 35c6aa206bSSiva Chandra Reddy UIntType otherBits = FPBits(otherResult).uintval(); 36c6aa206bSSiva Chandra Reddy if (myBits != otherBits) { 37c6aa206bSSiva Chandra Reddy ++diffCount; 38c6aa206bSSiva Chandra Reddy log << " Input: " << bits << " (" << x << ")\n" 39c6aa206bSSiva Chandra Reddy << " My result: " << myBits << " (" << myResult << ")\n" 40c6aa206bSSiva Chandra Reddy << "Other result: " << otherBits << " (" << otherResult << ")\n" 41c6aa206bSSiva Chandra Reddy << '\n'; 42c6aa206bSSiva Chandra Reddy } 43c6aa206bSSiva Chandra Reddy if (bits == UIntMax) 44c6aa206bSSiva Chandra Reddy break; 45c6aa206bSSiva Chandra Reddy } 46c6aa206bSSiva Chandra Reddy log << "Total number of differing results: " << diffCount << '\n'; 47c6aa206bSSiva Chandra Reddy } 48c6aa206bSSiva Chandra Reddy runPerfInRange(Func myFunc,Func otherFunc,UIntType startingBit,UIntType endingBit,testutils::OutputFileStream & log)49*db8716a2STue Ly static void runPerfInRange(Func myFunc, Func otherFunc, UIntType startingBit, 50*db8716a2STue Ly UIntType endingBit, 51*db8716a2STue Ly testutils::OutputFileStream &log) { 52*db8716a2STue Ly auto runner = [=](Func func) { 53c6aa206bSSiva Chandra Reddy volatile T result; 54*db8716a2STue Ly for (UIntType bits = startingBit;; ++bits) { 55c6aa206bSSiva Chandra Reddy T x = T(FPBits(bits)); 56c6aa206bSSiva Chandra Reddy result = func(x); 57*db8716a2STue Ly if (bits == endingBit) 58c6aa206bSSiva Chandra Reddy break; 59c6aa206bSSiva Chandra Reddy } 60c6aa206bSSiva Chandra Reddy }; 61c6aa206bSSiva Chandra Reddy 62c6aa206bSSiva Chandra Reddy Timer timer; 63c6aa206bSSiva Chandra Reddy timer.start(); 64c6aa206bSSiva Chandra Reddy runner(myFunc); 65c6aa206bSSiva Chandra Reddy timer.stop(); 66*db8716a2STue Ly 67*db8716a2STue Ly UIntType numberOfRuns = endingBit - startingBit + 1; 68*db8716a2STue Ly double myAverage = static_cast<double>(timer.nanoseconds()) / numberOfRuns; 69*db8716a2STue Ly log << "-- My function --\n"; 70*db8716a2STue Ly log << " Total time : " << timer.nanoseconds() << " ns \n"; 71*db8716a2STue Ly log << " Average runtime : " << myAverage << " ns/op \n"; 72*db8716a2STue Ly log << " Ops per second : " 73*db8716a2STue Ly << static_cast<uint64_t>(1'000'000'000.0 / myAverage) << " op/s \n"; 74c6aa206bSSiva Chandra Reddy 75c6aa206bSSiva Chandra Reddy timer.start(); 76c6aa206bSSiva Chandra Reddy runner(otherFunc); 77c6aa206bSSiva Chandra Reddy timer.stop(); 78*db8716a2STue Ly 79*db8716a2STue Ly double otherAverage = 80*db8716a2STue Ly static_cast<double>(timer.nanoseconds()) / numberOfRuns; 81*db8716a2STue Ly log << "-- Other function --\n"; 82*db8716a2STue Ly log << " Total time : " << timer.nanoseconds() << " ns \n"; 83*db8716a2STue Ly log << " Average runtime : " << otherAverage << " ns/op \n"; 84*db8716a2STue Ly log << " Ops per second : " 85*db8716a2STue Ly << static_cast<uint64_t>(1'000'000'000.0 / otherAverage) << " op/s \n"; 86*db8716a2STue Ly 87*db8716a2STue Ly log << "-- Average runtime ratio --\n"; 88*db8716a2STue Ly log << " Mine / Other's : " << myAverage / otherAverage << " \n"; 89*db8716a2STue Ly } 90*db8716a2STue Ly runPerf(Func myFunc,Func otherFunc,const char * logFile)91*db8716a2STue Ly static void runPerf(Func myFunc, Func otherFunc, const char *logFile) { 92*db8716a2STue Ly testutils::OutputFileStream log(logFile); 93*db8716a2STue Ly log << " Performance tests with inputs in denormal range:\n"; 94*db8716a2STue Ly runPerfInRange(myFunc, otherFunc, /* startingBit= */ UIntType(0), 95*db8716a2STue Ly /* endingBit= */ FPBits::MAX_SUBNORMAL, log); 96*db8716a2STue Ly log << "\n Performance tests with inputs in normal range:\n"; 97*db8716a2STue Ly runPerfInRange(myFunc, otherFunc, /* startingBit= */ FPBits::MIN_NORMAL, 98*db8716a2STue Ly /* endingBit= */ FPBits::MAX_NORMAL, log); 99c6aa206bSSiva Chandra Reddy } 100c6aa206bSSiva Chandra Reddy }; 101c6aa206bSSiva Chandra Reddy 102c6aa206bSSiva Chandra Reddy } // namespace testing 103c6aa206bSSiva Chandra Reddy } // namespace __llvm_libc 104c6aa206bSSiva Chandra Reddy 105c6aa206bSSiva Chandra Reddy #define SINGLE_INPUT_SINGLE_OUTPUT_DIFF(T, myFunc, otherFunc, filename) \ 106c6aa206bSSiva Chandra Reddy int main() { \ 107c6aa206bSSiva Chandra Reddy __llvm_libc::testing::SingleInputSingleOutputDiff<T>::runDiff( \ 108c6aa206bSSiva Chandra Reddy &myFunc, &otherFunc, filename); \ 109c6aa206bSSiva Chandra Reddy return 0; \ 110c6aa206bSSiva Chandra Reddy } 111c6aa206bSSiva Chandra Reddy 112c6aa206bSSiva Chandra Reddy #define SINGLE_INPUT_SINGLE_OUTPUT_PERF(T, myFunc, otherFunc, filename) \ 113c6aa206bSSiva Chandra Reddy int main() { \ 114c6aa206bSSiva Chandra Reddy __llvm_libc::testing::SingleInputSingleOutputDiff<T>::runPerf( \ 115c6aa206bSSiva Chandra Reddy &myFunc, &otherFunc, filename); \ 116c6aa206bSSiva Chandra Reddy return 0; \ 117c6aa206bSSiva Chandra Reddy } 118