• 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 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10 
11 #include <cstdint>
12 #include <functional>
13 #include <memory>
14 #include <string>
15 #include <utility>
16 
17 #include "CartesianBenchmarks.h"
18 #include "benchmark/benchmark.h"
19 #include "test_macros.h"
20 
21 namespace {
22 
23 enum class FunctionType {
24   Null,
25   FunctionPointer,
26   MemberFunctionPointer,
27   MemberPointer,
28   SmallTrivialFunctor,
29   SmallNonTrivialFunctor,
30   LargeTrivialFunctor,
31   LargeNonTrivialFunctor
32 };
33 
34 struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {
35   static constexpr const char* Names[] = {
36       "Null",
37       "FuncPtr",
38       "MemFuncPtr",
39       "MemPtr",
40       "SmallTrivialFunctor",
41       "SmallNonTrivialFunctor",
42       "LargeTrivialFunctor",
43       "LargeNonTrivialFunctor"};
44 };
45 
46 enum class Opacity { kOpaque, kTransparent };
47 
48 struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
49   static constexpr const char* Names[] = {"Opaque", "Transparent"};
50 };
51 
52 struct S {
function__anon0a7a1c970111::S53   int function() const { return 0; }
54   int field = 0;
55 };
56 
FunctionWithS(const S *)57 int FunctionWithS(const S*) { return 0; }
58 
59 struct SmallTrivialFunctor {
operator ()__anon0a7a1c970111::SmallTrivialFunctor60   int operator()(const S*) const { return 0; }
61 };
62 struct SmallNonTrivialFunctor {
SmallNonTrivialFunctor__anon0a7a1c970111::SmallNonTrivialFunctor63   SmallNonTrivialFunctor() {}
SmallNonTrivialFunctor__anon0a7a1c970111::SmallNonTrivialFunctor64   SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}
~SmallNonTrivialFunctor__anon0a7a1c970111::SmallNonTrivialFunctor65   ~SmallNonTrivialFunctor() {}
operator ()__anon0a7a1c970111::SmallNonTrivialFunctor66   int operator()(const S*) const { return 0; }
67 };
68 struct LargeTrivialFunctor {
LargeTrivialFunctor__anon0a7a1c970111::LargeTrivialFunctor69   LargeTrivialFunctor() {
70     // Do not spend time initializing the padding.
71   }
72   int padding[16];
operator ()__anon0a7a1c970111::LargeTrivialFunctor73   int operator()(const S*) const { return 0; }
74 };
75 struct LargeNonTrivialFunctor {
76   int padding[16];
LargeNonTrivialFunctor__anon0a7a1c970111::LargeNonTrivialFunctor77   LargeNonTrivialFunctor() {
78     // Do not spend time initializing the padding.
79   }
LargeNonTrivialFunctor__anon0a7a1c970111::LargeNonTrivialFunctor80   LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}
~LargeNonTrivialFunctor__anon0a7a1c970111::LargeNonTrivialFunctor81   ~LargeNonTrivialFunctor() {}
operator ()__anon0a7a1c970111::LargeNonTrivialFunctor82   int operator()(const S*) const { return 0; }
83 };
84 
85 using Function = std::function<int(const S*)>;
86 
87 TEST_ALWAYS_INLINE
MakeFunction(FunctionType type,bool opaque=false)88 inline Function MakeFunction(FunctionType type, bool opaque = false) {
89   switch (type) {
90   case FunctionType::Null:
91     return nullptr;
92   case FunctionType::FunctionPointer:
93     return maybeOpaque(FunctionWithS, opaque);
94   case FunctionType::MemberFunctionPointer:
95     return maybeOpaque(&S::function, opaque);
96   case FunctionType::MemberPointer:
97     return maybeOpaque(&S::field, opaque);
98   case FunctionType::SmallTrivialFunctor:
99     return maybeOpaque(SmallTrivialFunctor{}, opaque);
100   case FunctionType::SmallNonTrivialFunctor:
101     return maybeOpaque(SmallNonTrivialFunctor{}, opaque);
102   case FunctionType::LargeTrivialFunctor:
103     return maybeOpaque(LargeTrivialFunctor{}, opaque);
104   case FunctionType::LargeNonTrivialFunctor:
105     return maybeOpaque(LargeNonTrivialFunctor{}, opaque);
106   }
107   std::unreachable();
108 }
109 
110 template <class Opacity, class FunctionType>
111 struct ConstructAndDestroy {
run__anon0a7a1c970111::ConstructAndDestroy112   static void run(benchmark::State& state) {
113     for (auto _ : state) {
114       if (Opacity() == ::Opacity::kOpaque) {
115         benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
116       } else {
117         MakeFunction(FunctionType());
118       }
119     }
120   }
121 
name__anon0a7a1c970111::ConstructAndDestroy122   static std::string name() { return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name(); }
123 };
124 
125 template <class FunctionType>
126 struct Copy {
run__anon0a7a1c970111::Copy127   static void run(benchmark::State& state) {
128     auto value = MakeFunction(FunctionType());
129     for (auto _ : state) {
130       benchmark::DoNotOptimize(value);
131       auto copy = value; // NOLINT
132       benchmark::DoNotOptimize(copy);
133     }
134   }
135 
name__anon0a7a1c970111::Copy136   static std::string name() { return "BM_Copy" + FunctionType::name(); }
137 };
138 
139 template <class FunctionType>
140 struct Move {
run__anon0a7a1c970111::Move141   static void run(benchmark::State& state) {
142     Function values[2] = {MakeFunction(FunctionType())};
143     int i              = 0;
144     for (auto _ : state) {
145       benchmark::DoNotOptimize(values);
146       benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));
147       i ^= 1;
148     }
149   }
150 
name__anon0a7a1c970111::Move151   static std::string name() { return "BM_Move" + FunctionType::name(); }
152 };
153 
154 template <class Function1, class Function2>
155 struct Swap {
run__anon0a7a1c970111::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__anon0a7a1c970111::Swap164   static bool skip() { return Function1() > Function2(); }
165 
name__anon0a7a1c970111::Swap166   static std::string name() { return "BM_Swap" + Function1::name() + Function2::name(); }
167 };
168 
169 template <class FunctionType>
170 struct OperatorBool {
run__anon0a7a1c970111::OperatorBool171   static void run(benchmark::State& state) {
172     auto f = MakeFunction(FunctionType());
173     for (auto _ : state) {
174       benchmark::DoNotOptimize(f);
175       benchmark::DoNotOptimize(static_cast<bool>(f));
176     }
177   }
178 
name__anon0a7a1c970111::OperatorBool179   static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }
180 };
181 
182 template <class FunctionType>
183 struct Invoke {
run__anon0a7a1c970111::Invoke184   static void run(benchmark::State& state) {
185     S s;
186     auto value = MakeFunction(FunctionType());
187     for (auto _ : state) {
188       benchmark::DoNotOptimize(value);
189       benchmark::DoNotOptimize(value(&s));
190     }
191   }
192 
skip__anon0a7a1c970111::Invoke193   static bool skip() { return FunctionType() == ::FunctionType::Null; }
194 
name__anon0a7a1c970111::Invoke195   static std::string name() { return "BM_Invoke" + FunctionType::name(); }
196 };
197 
198 template <class FunctionType>
199 struct InvokeInlined {
run__anon0a7a1c970111::InvokeInlined200   static void run(benchmark::State& state) {
201     S s;
202     for (auto _ : state) {
203       MakeFunction(FunctionType())(&s);
204     }
205   }
206 
skip__anon0a7a1c970111::InvokeInlined207   static bool skip() { return FunctionType() == ::FunctionType::Null; }
208 
name__anon0a7a1c970111::InvokeInlined209   static std::string name() { return "BM_InvokeInlined" + FunctionType::name(); }
210 };
211 
212 } // namespace
213 
main(int argc,char ** argv)214 int main(int argc, char** argv) {
215   benchmark::Initialize(&argc, argv);
216   if (benchmark::ReportUnrecognizedArguments(argc, argv))
217     return 1;
218 
219   makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity, AllFunctionTypes>();
220   makeCartesianProductBenchmark<Copy, AllFunctionTypes>();
221   makeCartesianProductBenchmark<Move, AllFunctionTypes>();
222   makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();
223   makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();
224   makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();
225   makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();
226   benchmark::RunSpecifiedBenchmarks();
227 }
228