• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 namespace LIBC_NAMESPACE {
15 namespace testing {
16 
17 template <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 
23 public:
24   typedef T Func(T);
25 
runPerfInRange(Func myFunc,Func otherFunc,StorageType startingBit,StorageType endingBit,std::ofstream & log)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 
runPerf(Func myFunc,Func otherFunc,const char * logFile)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= */ StorageType(0),
74                    /* endingBit= */ FPBits::max_subnormal().uintval(), log);
75     log << "\n Performance tests with inputs in normal range:\n";
76     runPerfInRange(myFunc, otherFunc,
77                    /* startingBit= */ FPBits::min_normal().uintval(),
78                    /* 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