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