blob: 5cc3e7105e42c9081d473671b992cf70e0c80866 [file] [log] [blame]
Samuel Benzaquen91c92162018-10-12 21:01:15 +00001//===----------------------------------------------------------------------===//
2//
Chandler Carruthd2012102019-01-19 10:56:40 +00003// 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
Samuel Benzaquen91c92162018-10-12 21:01:15 +00006//
7//===----------------------------------------------------------------------===//
8
9#include <cstdint>
10#include <functional>
11#include <memory>
12#include <string>
13
14#include "CartesianBenchmarks.hpp"
15#include "benchmark/benchmark.h"
16#include "test_macros.h"
17
18namespace {
19
20enum class FunctionType {
21 Null,
22 FunctionPointer,
23 MemberFunctionPointer,
24 MemberPointer,
25 SmallTrivialFunctor,
26 SmallNonTrivialFunctor,
27 LargeTrivialFunctor,
28 LargeNonTrivialFunctor
29};
30
31struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {
32 static constexpr const char* Names[] = {"Null",
33 "FuncPtr",
34 "MemFuncPtr",
35 "MemPtr",
36 "SmallTrivialFunctor",
37 "SmallNonTrivialFunctor",
38 "LargeTrivialFunctor",
39 "LargeNonTrivialFunctor"};
40};
41
42enum class Opacity { kOpaque, kTransparent };
43
44struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
45 static constexpr const char* Names[] = {"Opaque", "Transparent"};
46};
47
48struct S {
49 int function() const { return 0; }
Eric Fiselier920d8722018-11-13 23:00:55 +000050 int field = 0;
Samuel Benzaquen91c92162018-10-12 21:01:15 +000051};
52
53int FunctionWithS(const S*) { return 0; }
54
55struct SmallTrivialFunctor {
56 int operator()(const S*) const { return 0; }
57};
58struct SmallNonTrivialFunctor {
59 SmallNonTrivialFunctor() {}
60 SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}
61 ~SmallNonTrivialFunctor() {}
62 int operator()(const S*) const { return 0; }
63};
64struct LargeTrivialFunctor {
65 LargeTrivialFunctor() {
66 // Do not spend time initializing the padding.
67 }
68 int padding[16];
69 int operator()(const S*) const { return 0; }
70};
71struct LargeNonTrivialFunctor {
72 int padding[16];
73 LargeNonTrivialFunctor() {
74 // Do not spend time initializing the padding.
75 }
76 LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}
77 ~LargeNonTrivialFunctor() {}
78 int operator()(const S*) const { return 0; }
79};
80
81using Function = std::function<int(const S*)>;
82
83TEST_ALWAYS_INLINE
84inline Function MakeFunction(FunctionType type, bool opaque = false) {
85 switch (type) {
86 case FunctionType::Null:
87 return nullptr;
88 case FunctionType::FunctionPointer:
89 return maybeOpaque(FunctionWithS, opaque);
90 case FunctionType::MemberFunctionPointer:
91 return maybeOpaque(&S::function, opaque);
92 case FunctionType::MemberPointer:
93 return maybeOpaque(&S::field, opaque);
94 case FunctionType::SmallTrivialFunctor:
95 return maybeOpaque(SmallTrivialFunctor{}, opaque);
96 case FunctionType::SmallNonTrivialFunctor:
97 return maybeOpaque(SmallNonTrivialFunctor{}, opaque);
98 case FunctionType::LargeTrivialFunctor:
99 return maybeOpaque(LargeTrivialFunctor{}, opaque);
100 case FunctionType::LargeNonTrivialFunctor:
101 return maybeOpaque(LargeNonTrivialFunctor{}, opaque);
102 }
103}
104
105template <class Opacity, class FunctionType>
106struct ConstructAndDestroy {
107 static void run(benchmark::State& state) {
108 for (auto _ : state) {
109 if (Opacity() == ::Opacity::kOpaque) {
110 benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
111 } else {
112 MakeFunction(FunctionType());
113 }
114 }
115 }
116
117 static std::string name() {
118 return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name();
119 }
120};
121
122template <class FunctionType>
123struct Copy {
124 static void run(benchmark::State& state) {
125 auto value = MakeFunction(FunctionType());
126 for (auto _ : state) {
127 benchmark::DoNotOptimize(value);
128 auto copy = value; // NOLINT
129 benchmark::DoNotOptimize(copy);
130 }
131 }
132
133 static std::string name() { return "BM_Copy" + FunctionType::name(); }
134};
135
136template <class FunctionType>
137struct Move {
138 static void run(benchmark::State& state) {
139 Function values[2] = {MakeFunction(FunctionType())};
140 int i = 0;
141 for (auto _ : state) {
142 benchmark::DoNotOptimize(values);
143 benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));
144 i ^= 1;
145 }
146 }
147
148 static std::string name() {
149 return "BM_Move" + FunctionType::name();
150 }
151};
152
153template <class Function1, class Function2>
154struct Swap {
155 static void run(benchmark::State& state) {
156 Function values[2] = {MakeFunction(Function1()), MakeFunction(Function2())};
157 for (auto _ : state) {
158 benchmark::DoNotOptimize(values);
159 values[0].swap(values[1]);
160 }
161 }
162
163 static bool skip() { return Function1() > Function2(); }
164
165 static std::string name() {
166 return "BM_Swap" + Function1::name() + Function2::name();
167 }
168};
169
170template <class FunctionType>
171struct OperatorBool {
172 static void run(benchmark::State& state) {
173 auto f = MakeFunction(FunctionType());
174 for (auto _ : state) {
175 benchmark::DoNotOptimize(f);
176 benchmark::DoNotOptimize(static_cast<bool>(f));
177 }
178 }
179
180 static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }
181};
182
183template <class FunctionType>
184struct Invoke {
185 static void run(benchmark::State& state) {
186 S s;
187 const auto value = MakeFunction(FunctionType());
188 for (auto _ : state) {
189 benchmark::DoNotOptimize(value);
190 benchmark::DoNotOptimize(value(&s));
191 }
192 }
193
194 static bool skip() { return FunctionType() == ::FunctionType::Null; }
195
196 static std::string name() { return "BM_Invoke" + FunctionType::name(); }
197};
198
199template <class FunctionType>
200struct InvokeInlined {
201 static void run(benchmark::State& state) {
202 S s;
203 for (auto _ : state) {
204 MakeFunction(FunctionType())(&s);
205 }
206 }
207
208 static bool skip() { return FunctionType() == ::FunctionType::Null; }
209
210 static std::string name() {
211 return "BM_InvokeInlined" + FunctionType::name();
212 }
213};
214
215} // namespace
216
217int main(int argc, char** argv) {
218 benchmark::Initialize(&argc, argv);
219 if (benchmark::ReportUnrecognizedArguments(argc, argv))
220 return 1;
221
222 makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity,
223 AllFunctionTypes>();
224 makeCartesianProductBenchmark<Copy, AllFunctionTypes>();
225 makeCartesianProductBenchmark<Move, AllFunctionTypes>();
226 makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();
227 makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();
228 makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();
229 makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();
230 benchmark::RunSpecifiedBenchmarks();
231}