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