• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===----------------------------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include <cstdint>
11 #include <functional>
12 #include <memory>
13 #include <string>
14 
15 #include "CartesianBenchmarks.hpp"
16 #include "benchmark/benchmark.h"
17 #include "test_macros.h"
18 
19 namespace {
20 
21 enum class FunctionType {
22   Null,
23   FunctionPointer,
24   MemberFunctionPointer,
25   MemberPointer,
26   SmallTrivialFunctor,
27   SmallNonTrivialFunctor,
28   LargeTrivialFunctor,
29   LargeNonTrivialFunctor
30 };
31 
32 struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {
33   static constexpr const char* Names[] = {"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__anon1faf23050111::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 ()__anon1faf23050111::SmallTrivialFunctor57   int operator()(const S*) const { return 0; }
58 };
59 struct SmallNonTrivialFunctor {
SmallNonTrivialFunctor__anon1faf23050111::SmallNonTrivialFunctor60   SmallNonTrivialFunctor() {}
SmallNonTrivialFunctor__anon1faf23050111::SmallNonTrivialFunctor61   SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}
~SmallNonTrivialFunctor__anon1faf23050111::SmallNonTrivialFunctor62   ~SmallNonTrivialFunctor() {}
operator ()__anon1faf23050111::SmallNonTrivialFunctor63   int operator()(const S*) const { return 0; }
64 };
65 struct LargeTrivialFunctor {
LargeTrivialFunctor__anon1faf23050111::LargeTrivialFunctor66   LargeTrivialFunctor() {
67       // Do not spend time initializing the padding.
68   }
69   int padding[16];
operator ()__anon1faf23050111::LargeTrivialFunctor70   int operator()(const S*) const { return 0; }
71 };
72 struct LargeNonTrivialFunctor {
73   int padding[16];
LargeNonTrivialFunctor__anon1faf23050111::LargeNonTrivialFunctor74   LargeNonTrivialFunctor() {
75       // Do not spend time initializing the padding.
76   }
LargeNonTrivialFunctor__anon1faf23050111::LargeNonTrivialFunctor77   LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}
~LargeNonTrivialFunctor__anon1faf23050111::LargeNonTrivialFunctor78   ~LargeNonTrivialFunctor() {}
operator ()__anon1faf23050111::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__anon1faf23050111::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__anon1faf23050111::ConstructAndDestroy118   static std::string name() {
119     return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name();
120   }
121 };
122 
123 template <class FunctionType>
124 struct Copy {
run__anon1faf23050111::Copy125   static void run(benchmark::State& state) {
126     auto value = MakeFunction(FunctionType());
127     for (auto _ : state) {
128       benchmark::DoNotOptimize(value);
129       auto copy = value;  // NOLINT
130       benchmark::DoNotOptimize(copy);
131     }
132   }
133 
name__anon1faf23050111::Copy134   static std::string name() { return "BM_Copy" + FunctionType::name(); }
135 };
136 
137 template <class FunctionType>
138 struct Move {
run__anon1faf23050111::Move139   static void run(benchmark::State& state) {
140     Function values[2] = {MakeFunction(FunctionType())};
141     int i = 0;
142     for (auto _ : state) {
143       benchmark::DoNotOptimize(values);
144       benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));
145       i ^= 1;
146     }
147   }
148 
name__anon1faf23050111::Move149   static std::string name() {
150     return "BM_Move" + FunctionType::name();
151   }
152 };
153 
154 template <class Function1, class Function2>
155 struct Swap {
run__anon1faf23050111::Swap156   static void run(benchmark::State& state) {
157     Function values[2] = {MakeFunction(Function1()), MakeFunction(Function2())};
158     for (auto _ : state) {
159       benchmark::DoNotOptimize(values);
160       values[0].swap(values[1]);
161     }
162   }
163 
skip__anon1faf23050111::Swap164   static bool skip() { return Function1() > Function2(); }
165 
name__anon1faf23050111::Swap166   static std::string name() {
167     return "BM_Swap" + Function1::name() + Function2::name();
168   }
169 };
170 
171 template <class FunctionType>
172 struct OperatorBool {
run__anon1faf23050111::OperatorBool173   static void run(benchmark::State& state) {
174     auto f = MakeFunction(FunctionType());
175     for (auto _ : state) {
176       benchmark::DoNotOptimize(f);
177       benchmark::DoNotOptimize(static_cast<bool>(f));
178     }
179   }
180 
name__anon1faf23050111::OperatorBool181   static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }
182 };
183 
184 template <class FunctionType>
185 struct Invoke {
run__anon1faf23050111::Invoke186   static void run(benchmark::State& state) {
187     S s;
188     const auto value = MakeFunction(FunctionType());
189     for (auto _ : state) {
190       benchmark::DoNotOptimize(value);
191       benchmark::DoNotOptimize(value(&s));
192     }
193   }
194 
skip__anon1faf23050111::Invoke195   static bool skip() { return FunctionType() == ::FunctionType::Null; }
196 
name__anon1faf23050111::Invoke197   static std::string name() { return "BM_Invoke" + FunctionType::name(); }
198 };
199 
200 template <class FunctionType>
201 struct InvokeInlined {
run__anon1faf23050111::InvokeInlined202   static void run(benchmark::State& state) {
203     S s;
204     for (auto _ : state) {
205       MakeFunction(FunctionType())(&s);
206     }
207   }
208 
skip__anon1faf23050111::InvokeInlined209   static bool skip() { return FunctionType() == ::FunctionType::Null; }
210 
name__anon1faf23050111::InvokeInlined211   static std::string name() {
212     return "BM_InvokeInlined" + FunctionType::name();
213   }
214 };
215 
216 }  // namespace
217 
main(int argc,char ** argv)218 int main(int argc, char** argv) {
219   benchmark::Initialize(&argc, argv);
220   if (benchmark::ReportUnrecognizedArguments(argc, argv))
221     return 1;
222 
223   makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity,
224                                 AllFunctionTypes>();
225   makeCartesianProductBenchmark<Copy, AllFunctionTypes>();
226   makeCartesianProductBenchmark<Move, AllFunctionTypes>();
227   makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();
228   makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();
229   makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();
230   makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();
231   benchmark::RunSpecifiedBenchmarks();
232 }
233