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