• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===----------------------------------------------------------------------===//
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 <cstdint>
10 #include <functional>
11 #include <memory>
12 #include <string>
13 
14 #include "CartesianBenchmarks.h"
15 #include "benchmark/benchmark.h"
16 #include "test_macros.h"
17 
18 namespace {
19 
20 enum class FunctionType {
21   Null,
22   FunctionPointer,
23   MemberFunctionPointer,
24   MemberPointer,
25   SmallTrivialFunctor,
26   SmallNonTrivialFunctor,
27   LargeTrivialFunctor,
28   LargeNonTrivialFunctor
29 };
30 
31 struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {
32   static constexpr const char* Names[] = {
33       "Null",
34       "FuncPtr",
35       "MemFuncPtr",
36       "MemPtr",
37       "SmallTrivialFunctor",
38       "SmallNonTrivialFunctor",
39       "LargeTrivialFunctor",
40       "LargeNonTrivialFunctor"};
41 };
42 
43 enum class Opacity { kOpaque, kTransparent };
44 
45 struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
46   static constexpr const char* Names[] = {"Opaque", "Transparent"};
47 };
48 
49 struct S {
function__anon2c46c2800111::S50   int function() const { return 0; }
51   int field = 0;
52 };
53 
FunctionWithS(const S *)54 int FunctionWithS(const S*) { return 0; }
55 
56 struct SmallTrivialFunctor {
operator ()__anon2c46c2800111::SmallTrivialFunctor57   int operator()(const S*) const { return 0; }
58 };
59 struct SmallNonTrivialFunctor {
SmallNonTrivialFunctor__anon2c46c2800111::SmallNonTrivialFunctor60   SmallNonTrivialFunctor() {}
SmallNonTrivialFunctor__anon2c46c2800111::SmallNonTrivialFunctor61   SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}
~SmallNonTrivialFunctor__anon2c46c2800111::SmallNonTrivialFunctor62   ~SmallNonTrivialFunctor() {}
operator ()__anon2c46c2800111::SmallNonTrivialFunctor63   int operator()(const S*) const { return 0; }
64 };
65 struct LargeTrivialFunctor {
LargeTrivialFunctor__anon2c46c2800111::LargeTrivialFunctor66   LargeTrivialFunctor() {
67     // Do not spend time initializing the padding.
68   }
69   int padding[16];
operator ()__anon2c46c2800111::LargeTrivialFunctor70   int operator()(const S*) const { return 0; }
71 };
72 struct LargeNonTrivialFunctor {
73   int padding[16];
LargeNonTrivialFunctor__anon2c46c2800111::LargeNonTrivialFunctor74   LargeNonTrivialFunctor() {
75     // Do not spend time initializing the padding.
76   }
LargeNonTrivialFunctor__anon2c46c2800111::LargeNonTrivialFunctor77   LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}
~LargeNonTrivialFunctor__anon2c46c2800111::LargeNonTrivialFunctor78   ~LargeNonTrivialFunctor() {}
operator ()__anon2c46c2800111::LargeNonTrivialFunctor79   int operator()(const S*) const { return 0; }
80 };
81 
82 using Function = std::function<int(const S*)>;
83 
84 TEST_ALWAYS_INLINE
MakeFunction(FunctionType type,bool opaque=false)85 inline Function MakeFunction(FunctionType type, bool opaque = false) {
86   switch (type) {
87   case FunctionType::Null:
88     return nullptr;
89   case FunctionType::FunctionPointer:
90     return maybeOpaque(FunctionWithS, opaque);
91   case FunctionType::MemberFunctionPointer:
92     return maybeOpaque(&S::function, opaque);
93   case FunctionType::MemberPointer:
94     return maybeOpaque(&S::field, opaque);
95   case FunctionType::SmallTrivialFunctor:
96     return maybeOpaque(SmallTrivialFunctor{}, opaque);
97   case FunctionType::SmallNonTrivialFunctor:
98     return maybeOpaque(SmallNonTrivialFunctor{}, opaque);
99   case FunctionType::LargeTrivialFunctor:
100     return maybeOpaque(LargeTrivialFunctor{}, opaque);
101   case FunctionType::LargeNonTrivialFunctor:
102     return maybeOpaque(LargeNonTrivialFunctor{}, opaque);
103   }
104 }
105 
106 template <class Opacity, class FunctionType>
107 struct ConstructAndDestroy {
run__anon2c46c2800111::ConstructAndDestroy108   static void run(benchmark::State& state) {
109     for (auto _ : state) {
110       if (Opacity() == ::Opacity::kOpaque) {
111         benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
112       } else {
113         MakeFunction(FunctionType());
114       }
115     }
116   }
117 
name__anon2c46c2800111::ConstructAndDestroy118   static std::string name() { return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name(); }
119 };
120 
121 template <class FunctionType>
122 struct Copy {
run__anon2c46c2800111::Copy123   static void run(benchmark::State& state) {
124     auto value = MakeFunction(FunctionType());
125     for (auto _ : state) {
126       benchmark::DoNotOptimize(value);
127       auto copy = value; // NOLINT
128       benchmark::DoNotOptimize(copy);
129     }
130   }
131 
name__anon2c46c2800111::Copy132   static std::string name() { return "BM_Copy" + FunctionType::name(); }
133 };
134 
135 template <class FunctionType>
136 struct Move {
run__anon2c46c2800111::Move137   static void run(benchmark::State& state) {
138     Function values[2] = {MakeFunction(FunctionType())};
139     int i              = 0;
140     for (auto _ : state) {
141       benchmark::DoNotOptimize(values);
142       benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));
143       i ^= 1;
144     }
145   }
146 
name__anon2c46c2800111::Move147   static std::string name() { return "BM_Move" + FunctionType::name(); }
148 };
149 
150 template <class Function1, class Function2>
151 struct Swap {
run__anon2c46c2800111::Swap152   static void run(benchmark::State& state) {
153     Function values[2] = {MakeFunction(Function1()), MakeFunction(Function2())};
154     for (auto _ : state) {
155       benchmark::DoNotOptimize(values);
156       values[0].swap(values[1]);
157     }
158   }
159 
skip__anon2c46c2800111::Swap160   static bool skip() { return Function1() > Function2(); }
161 
name__anon2c46c2800111::Swap162   static std::string name() { return "BM_Swap" + Function1::name() + Function2::name(); }
163 };
164 
165 template <class FunctionType>
166 struct OperatorBool {
run__anon2c46c2800111::OperatorBool167   static void run(benchmark::State& state) {
168     auto f = MakeFunction(FunctionType());
169     for (auto _ : state) {
170       benchmark::DoNotOptimize(f);
171       benchmark::DoNotOptimize(static_cast<bool>(f));
172     }
173   }
174 
name__anon2c46c2800111::OperatorBool175   static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }
176 };
177 
178 template <class FunctionType>
179 struct Invoke {
run__anon2c46c2800111::Invoke180   static void run(benchmark::State& state) {
181     S s;
182     const auto value = MakeFunction(FunctionType());
183     for (auto _ : state) {
184       benchmark::DoNotOptimize(value);
185       benchmark::DoNotOptimize(value(&s));
186     }
187   }
188 
skip__anon2c46c2800111::Invoke189   static bool skip() { return FunctionType() == ::FunctionType::Null; }
190 
name__anon2c46c2800111::Invoke191   static std::string name() { return "BM_Invoke" + FunctionType::name(); }
192 };
193 
194 template <class FunctionType>
195 struct InvokeInlined {
run__anon2c46c2800111::InvokeInlined196   static void run(benchmark::State& state) {
197     S s;
198     for (auto _ : state) {
199       MakeFunction(FunctionType())(&s);
200     }
201   }
202 
skip__anon2c46c2800111::InvokeInlined203   static bool skip() { return FunctionType() == ::FunctionType::Null; }
204 
name__anon2c46c2800111::InvokeInlined205   static std::string name() { return "BM_InvokeInlined" + FunctionType::name(); }
206 };
207 
208 } // namespace
209 
main(int argc,char ** argv)210 int main(int argc, char** argv) {
211   benchmark::Initialize(&argc, argv);
212   if (benchmark::ReportUnrecognizedArguments(argc, argv))
213     return 1;
214 
215   makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity, AllFunctionTypes>();
216   makeCartesianProductBenchmark<Copy, AllFunctionTypes>();
217   makeCartesianProductBenchmark<Move, AllFunctionTypes>();
218   makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();
219   makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();
220   makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();
221   makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();
222   benchmark::RunSpecifiedBenchmarks();
223 }
224