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