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