xref: /netbsd-src/external/apache2/llvm/dist/libcxx/benchmarks/function.bench.cpp (revision 4d6fc14bc9b0c5bf3e30be318c143ee82cadd108)
1*4d6fc14bSjoerg //===----------------------------------------------------------------------===//
2*4d6fc14bSjoerg //
3*4d6fc14bSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*4d6fc14bSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*4d6fc14bSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*4d6fc14bSjoerg //
7*4d6fc14bSjoerg //===----------------------------------------------------------------------===//
8*4d6fc14bSjoerg 
9*4d6fc14bSjoerg #include <cstdint>
10*4d6fc14bSjoerg #include <functional>
11*4d6fc14bSjoerg #include <memory>
12*4d6fc14bSjoerg #include <string>
13*4d6fc14bSjoerg 
14*4d6fc14bSjoerg #include "CartesianBenchmarks.h"
15*4d6fc14bSjoerg #include "benchmark/benchmark.h"
16*4d6fc14bSjoerg #include "test_macros.h"
17*4d6fc14bSjoerg 
18*4d6fc14bSjoerg namespace {
19*4d6fc14bSjoerg 
20*4d6fc14bSjoerg enum class FunctionType {
21*4d6fc14bSjoerg   Null,
22*4d6fc14bSjoerg   FunctionPointer,
23*4d6fc14bSjoerg   MemberFunctionPointer,
24*4d6fc14bSjoerg   MemberPointer,
25*4d6fc14bSjoerg   SmallTrivialFunctor,
26*4d6fc14bSjoerg   SmallNonTrivialFunctor,
27*4d6fc14bSjoerg   LargeTrivialFunctor,
28*4d6fc14bSjoerg   LargeNonTrivialFunctor
29*4d6fc14bSjoerg };
30*4d6fc14bSjoerg 
31*4d6fc14bSjoerg struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {
32*4d6fc14bSjoerg   static constexpr const char* Names[] = {"Null",
33*4d6fc14bSjoerg                                           "FuncPtr",
34*4d6fc14bSjoerg                                           "MemFuncPtr",
35*4d6fc14bSjoerg                                           "MemPtr",
36*4d6fc14bSjoerg                                           "SmallTrivialFunctor",
37*4d6fc14bSjoerg                                           "SmallNonTrivialFunctor",
38*4d6fc14bSjoerg                                           "LargeTrivialFunctor",
39*4d6fc14bSjoerg                                           "LargeNonTrivialFunctor"};
40*4d6fc14bSjoerg };
41*4d6fc14bSjoerg 
42*4d6fc14bSjoerg enum class Opacity { kOpaque, kTransparent };
43*4d6fc14bSjoerg 
44*4d6fc14bSjoerg struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
45*4d6fc14bSjoerg   static constexpr const char* Names[] = {"Opaque", "Transparent"};
46*4d6fc14bSjoerg };
47*4d6fc14bSjoerg 
48*4d6fc14bSjoerg struct S {
function__anon684cb2650111::S49*4d6fc14bSjoerg   int function() const { return 0; }
50*4d6fc14bSjoerg   int field = 0;
51*4d6fc14bSjoerg };
52*4d6fc14bSjoerg 
FunctionWithS(const S *)53*4d6fc14bSjoerg int FunctionWithS(const S*) { return 0; }
54*4d6fc14bSjoerg 
55*4d6fc14bSjoerg struct SmallTrivialFunctor {
operator ()__anon684cb2650111::SmallTrivialFunctor56*4d6fc14bSjoerg   int operator()(const S*) const { return 0; }
57*4d6fc14bSjoerg };
58*4d6fc14bSjoerg struct SmallNonTrivialFunctor {
SmallNonTrivialFunctor__anon684cb2650111::SmallNonTrivialFunctor59*4d6fc14bSjoerg   SmallNonTrivialFunctor() {}
SmallNonTrivialFunctor__anon684cb2650111::SmallNonTrivialFunctor60*4d6fc14bSjoerg   SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}
~SmallNonTrivialFunctor__anon684cb2650111::SmallNonTrivialFunctor61*4d6fc14bSjoerg   ~SmallNonTrivialFunctor() {}
operator ()__anon684cb2650111::SmallNonTrivialFunctor62*4d6fc14bSjoerg   int operator()(const S*) const { return 0; }
63*4d6fc14bSjoerg };
64*4d6fc14bSjoerg struct LargeTrivialFunctor {
LargeTrivialFunctor__anon684cb2650111::LargeTrivialFunctor65*4d6fc14bSjoerg   LargeTrivialFunctor() {
66*4d6fc14bSjoerg       // Do not spend time initializing the padding.
67*4d6fc14bSjoerg   }
68*4d6fc14bSjoerg   int padding[16];
operator ()__anon684cb2650111::LargeTrivialFunctor69*4d6fc14bSjoerg   int operator()(const S*) const { return 0; }
70*4d6fc14bSjoerg };
71*4d6fc14bSjoerg struct LargeNonTrivialFunctor {
72*4d6fc14bSjoerg   int padding[16];
LargeNonTrivialFunctor__anon684cb2650111::LargeNonTrivialFunctor73*4d6fc14bSjoerg   LargeNonTrivialFunctor() {
74*4d6fc14bSjoerg       // Do not spend time initializing the padding.
75*4d6fc14bSjoerg   }
LargeNonTrivialFunctor__anon684cb2650111::LargeNonTrivialFunctor76*4d6fc14bSjoerg   LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}
~LargeNonTrivialFunctor__anon684cb2650111::LargeNonTrivialFunctor77*4d6fc14bSjoerg   ~LargeNonTrivialFunctor() {}
operator ()__anon684cb2650111::LargeNonTrivialFunctor78*4d6fc14bSjoerg   int operator()(const S*) const { return 0; }
79*4d6fc14bSjoerg };
80*4d6fc14bSjoerg 
81*4d6fc14bSjoerg using Function = std::function<int(const S*)>;
82*4d6fc14bSjoerg 
83*4d6fc14bSjoerg TEST_ALWAYS_INLINE
MakeFunction(FunctionType type,bool opaque=false)84*4d6fc14bSjoerg inline Function MakeFunction(FunctionType type, bool opaque = false) {
85*4d6fc14bSjoerg   switch (type) {
86*4d6fc14bSjoerg     case FunctionType::Null:
87*4d6fc14bSjoerg       return nullptr;
88*4d6fc14bSjoerg     case FunctionType::FunctionPointer:
89*4d6fc14bSjoerg       return maybeOpaque(FunctionWithS, opaque);
90*4d6fc14bSjoerg     case FunctionType::MemberFunctionPointer:
91*4d6fc14bSjoerg       return maybeOpaque(&S::function, opaque);
92*4d6fc14bSjoerg     case FunctionType::MemberPointer:
93*4d6fc14bSjoerg       return maybeOpaque(&S::field, opaque);
94*4d6fc14bSjoerg     case FunctionType::SmallTrivialFunctor:
95*4d6fc14bSjoerg       return maybeOpaque(SmallTrivialFunctor{}, opaque);
96*4d6fc14bSjoerg     case FunctionType::SmallNonTrivialFunctor:
97*4d6fc14bSjoerg       return maybeOpaque(SmallNonTrivialFunctor{}, opaque);
98*4d6fc14bSjoerg     case FunctionType::LargeTrivialFunctor:
99*4d6fc14bSjoerg       return maybeOpaque(LargeTrivialFunctor{}, opaque);
100*4d6fc14bSjoerg     case FunctionType::LargeNonTrivialFunctor:
101*4d6fc14bSjoerg       return maybeOpaque(LargeNonTrivialFunctor{}, opaque);
102*4d6fc14bSjoerg   }
103*4d6fc14bSjoerg }
104*4d6fc14bSjoerg 
105*4d6fc14bSjoerg template <class Opacity, class FunctionType>
106*4d6fc14bSjoerg struct ConstructAndDestroy {
run__anon684cb2650111::ConstructAndDestroy107*4d6fc14bSjoerg   static void run(benchmark::State& state) {
108*4d6fc14bSjoerg     for (auto _ : state) {
109*4d6fc14bSjoerg       if (Opacity() == ::Opacity::kOpaque) {
110*4d6fc14bSjoerg         benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
111*4d6fc14bSjoerg       } else {
112*4d6fc14bSjoerg         MakeFunction(FunctionType());
113*4d6fc14bSjoerg       }
114*4d6fc14bSjoerg     }
115*4d6fc14bSjoerg   }
116*4d6fc14bSjoerg 
name__anon684cb2650111::ConstructAndDestroy117*4d6fc14bSjoerg   static std::string name() {
118*4d6fc14bSjoerg     return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name();
119*4d6fc14bSjoerg   }
120*4d6fc14bSjoerg };
121*4d6fc14bSjoerg 
122*4d6fc14bSjoerg template <class FunctionType>
123*4d6fc14bSjoerg struct Copy {
run__anon684cb2650111::Copy124*4d6fc14bSjoerg   static void run(benchmark::State& state) {
125*4d6fc14bSjoerg     auto value = MakeFunction(FunctionType());
126*4d6fc14bSjoerg     for (auto _ : state) {
127*4d6fc14bSjoerg       benchmark::DoNotOptimize(value);
128*4d6fc14bSjoerg       auto copy = value;  // NOLINT
129*4d6fc14bSjoerg       benchmark::DoNotOptimize(copy);
130*4d6fc14bSjoerg     }
131*4d6fc14bSjoerg   }
132*4d6fc14bSjoerg 
name__anon684cb2650111::Copy133*4d6fc14bSjoerg   static std::string name() { return "BM_Copy" + FunctionType::name(); }
134*4d6fc14bSjoerg };
135*4d6fc14bSjoerg 
136*4d6fc14bSjoerg template <class FunctionType>
137*4d6fc14bSjoerg struct Move {
run__anon684cb2650111::Move138*4d6fc14bSjoerg   static void run(benchmark::State& state) {
139*4d6fc14bSjoerg     Function values[2] = {MakeFunction(FunctionType())};
140*4d6fc14bSjoerg     int i = 0;
141*4d6fc14bSjoerg     for (auto _ : state) {
142*4d6fc14bSjoerg       benchmark::DoNotOptimize(values);
143*4d6fc14bSjoerg       benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));
144*4d6fc14bSjoerg       i ^= 1;
145*4d6fc14bSjoerg     }
146*4d6fc14bSjoerg   }
147*4d6fc14bSjoerg 
name__anon684cb2650111::Move148*4d6fc14bSjoerg   static std::string name() {
149*4d6fc14bSjoerg     return "BM_Move" + FunctionType::name();
150*4d6fc14bSjoerg   }
151*4d6fc14bSjoerg };
152*4d6fc14bSjoerg 
153*4d6fc14bSjoerg template <class Function1, class Function2>
154*4d6fc14bSjoerg struct Swap {
run__anon684cb2650111::Swap155*4d6fc14bSjoerg   static void run(benchmark::State& state) {
156*4d6fc14bSjoerg     Function values[2] = {MakeFunction(Function1()), MakeFunction(Function2())};
157*4d6fc14bSjoerg     for (auto _ : state) {
158*4d6fc14bSjoerg       benchmark::DoNotOptimize(values);
159*4d6fc14bSjoerg       values[0].swap(values[1]);
160*4d6fc14bSjoerg     }
161*4d6fc14bSjoerg   }
162*4d6fc14bSjoerg 
skip__anon684cb2650111::Swap163*4d6fc14bSjoerg   static bool skip() { return Function1() > Function2(); }
164*4d6fc14bSjoerg 
name__anon684cb2650111::Swap165*4d6fc14bSjoerg   static std::string name() {
166*4d6fc14bSjoerg     return "BM_Swap" + Function1::name() + Function2::name();
167*4d6fc14bSjoerg   }
168*4d6fc14bSjoerg };
169*4d6fc14bSjoerg 
170*4d6fc14bSjoerg template <class FunctionType>
171*4d6fc14bSjoerg struct OperatorBool {
run__anon684cb2650111::OperatorBool172*4d6fc14bSjoerg   static void run(benchmark::State& state) {
173*4d6fc14bSjoerg     auto f = MakeFunction(FunctionType());
174*4d6fc14bSjoerg     for (auto _ : state) {
175*4d6fc14bSjoerg       benchmark::DoNotOptimize(f);
176*4d6fc14bSjoerg       benchmark::DoNotOptimize(static_cast<bool>(f));
177*4d6fc14bSjoerg     }
178*4d6fc14bSjoerg   }
179*4d6fc14bSjoerg 
name__anon684cb2650111::OperatorBool180*4d6fc14bSjoerg   static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }
181*4d6fc14bSjoerg };
182*4d6fc14bSjoerg 
183*4d6fc14bSjoerg template <class FunctionType>
184*4d6fc14bSjoerg struct Invoke {
run__anon684cb2650111::Invoke185*4d6fc14bSjoerg   static void run(benchmark::State& state) {
186*4d6fc14bSjoerg     S s;
187*4d6fc14bSjoerg     const auto value = MakeFunction(FunctionType());
188*4d6fc14bSjoerg     for (auto _ : state) {
189*4d6fc14bSjoerg       benchmark::DoNotOptimize(value);
190*4d6fc14bSjoerg       benchmark::DoNotOptimize(value(&s));
191*4d6fc14bSjoerg     }
192*4d6fc14bSjoerg   }
193*4d6fc14bSjoerg 
skip__anon684cb2650111::Invoke194*4d6fc14bSjoerg   static bool skip() { return FunctionType() == ::FunctionType::Null; }
195*4d6fc14bSjoerg 
name__anon684cb2650111::Invoke196*4d6fc14bSjoerg   static std::string name() { return "BM_Invoke" + FunctionType::name(); }
197*4d6fc14bSjoerg };
198*4d6fc14bSjoerg 
199*4d6fc14bSjoerg template <class FunctionType>
200*4d6fc14bSjoerg struct InvokeInlined {
run__anon684cb2650111::InvokeInlined201*4d6fc14bSjoerg   static void run(benchmark::State& state) {
202*4d6fc14bSjoerg     S s;
203*4d6fc14bSjoerg     for (auto _ : state) {
204*4d6fc14bSjoerg       MakeFunction(FunctionType())(&s);
205*4d6fc14bSjoerg     }
206*4d6fc14bSjoerg   }
207*4d6fc14bSjoerg 
skip__anon684cb2650111::InvokeInlined208*4d6fc14bSjoerg   static bool skip() { return FunctionType() == ::FunctionType::Null; }
209*4d6fc14bSjoerg 
name__anon684cb2650111::InvokeInlined210*4d6fc14bSjoerg   static std::string name() {
211*4d6fc14bSjoerg     return "BM_InvokeInlined" + FunctionType::name();
212*4d6fc14bSjoerg   }
213*4d6fc14bSjoerg };
214*4d6fc14bSjoerg 
215*4d6fc14bSjoerg }  // namespace
216*4d6fc14bSjoerg 
main(int argc,char ** argv)217*4d6fc14bSjoerg int main(int argc, char** argv) {
218*4d6fc14bSjoerg   benchmark::Initialize(&argc, argv);
219*4d6fc14bSjoerg   if (benchmark::ReportUnrecognizedArguments(argc, argv))
220*4d6fc14bSjoerg     return 1;
221*4d6fc14bSjoerg 
222*4d6fc14bSjoerg   makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity,
223*4d6fc14bSjoerg                                 AllFunctionTypes>();
224*4d6fc14bSjoerg   makeCartesianProductBenchmark<Copy, AllFunctionTypes>();
225*4d6fc14bSjoerg   makeCartesianProductBenchmark<Move, AllFunctionTypes>();
226*4d6fc14bSjoerg   makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();
227*4d6fc14bSjoerg   makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();
228*4d6fc14bSjoerg   makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();
229*4d6fc14bSjoerg   makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();
230*4d6fc14bSjoerg   benchmark::RunSpecifiedBenchmarks();
231*4d6fc14bSjoerg }
232