1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
14 #include "CartesianBenchmarks.h"
15 #include "benchmark/benchmark.h"
16 #include "test_macros.h"
20 enum class FunctionType
{
23 MemberFunctionPointer
,
26 SmallNonTrivialFunctor
,
28 LargeNonTrivialFunctor
31 struct AllFunctionTypes
: EnumValuesAsTuple
<AllFunctionTypes
, FunctionType
, 8> {
32 static constexpr const char* Names
[] = {"Null",
36 "SmallTrivialFunctor",
37 "SmallNonTrivialFunctor",
38 "LargeTrivialFunctor",
39 "LargeNonTrivialFunctor"};
42 enum class Opacity
{ kOpaque
, kTransparent
};
44 struct AllOpacity
: EnumValuesAsTuple
<AllOpacity
, Opacity
, 2> {
45 static constexpr const char* Names
[] = {"Opaque", "Transparent"};
49 int function() const { return 0; }
53 int FunctionWithS(const S
*) { return 0; }
55 struct SmallTrivialFunctor
{
56 int operator()(const S
*) const { return 0; }
58 struct SmallNonTrivialFunctor
{
59 SmallNonTrivialFunctor() {}
60 SmallNonTrivialFunctor(const SmallNonTrivialFunctor
&) {}
61 ~SmallNonTrivialFunctor() {}
62 int operator()(const S
*) const { return 0; }
64 struct LargeTrivialFunctor
{
65 LargeTrivialFunctor() {
66 // Do not spend time initializing the padding.
69 int operator()(const S
*) const { return 0; }
71 struct LargeNonTrivialFunctor
{
73 LargeNonTrivialFunctor() {
74 // Do not spend time initializing the padding.
76 LargeNonTrivialFunctor(const LargeNonTrivialFunctor
&) {}
77 ~LargeNonTrivialFunctor() {}
78 int operator()(const S
*) const { return 0; }
81 using Function
= std::function
<int(const S
*)>;
84 inline Function
MakeFunction(FunctionType type
, bool opaque
= false) {
86 case FunctionType::Null
:
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
);
105 template <class Opacity
, class FunctionType
>
106 struct ConstructAndDestroy
{
107 static void run(benchmark::State
& state
) {
108 for (auto _
: state
) {
109 if (Opacity() == ::Opacity::kOpaque
) {
110 benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
112 MakeFunction(FunctionType());
117 static std::string
name() {
118 return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name();
122 template <class FunctionType
>
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
);
133 static std::string
name() { return "BM_Copy" + FunctionType::name(); }
136 template <class FunctionType
>
138 static void run(benchmark::State
& state
) {
139 Function values
[2] = {MakeFunction(FunctionType())};
141 for (auto _
: state
) {
142 benchmark::DoNotOptimize(values
);
143 benchmark::DoNotOptimize(values
[i
^ 1] = std::move(values
[i
]));
148 static std::string
name() {
149 return "BM_Move" + FunctionType::name();
153 template <class Function1
, class Function2
>
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]);
163 static bool skip() { return Function1() > Function2(); }
165 static std::string
name() {
166 return "BM_Swap" + Function1::name() + Function2::name();
170 template <class FunctionType
>
171 struct 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
));
180 static std::string
name() { return "BM_OperatorBool" + FunctionType::name(); }
183 template <class FunctionType
>
185 static void run(benchmark::State
& state
) {
187 const auto value
= MakeFunction(FunctionType());
188 for (auto _
: state
) {
189 benchmark::DoNotOptimize(value
);
190 benchmark::DoNotOptimize(value(&s
));
194 static bool skip() { return FunctionType() == ::FunctionType::Null
; }
196 static std::string
name() { return "BM_Invoke" + FunctionType::name(); }
199 template <class FunctionType
>
200 struct InvokeInlined
{
201 static void run(benchmark::State
& state
) {
203 for (auto _
: state
) {
204 MakeFunction(FunctionType())(&s
);
208 static bool skip() { return FunctionType() == ::FunctionType::Null
; }
210 static std::string
name() {
211 return "BM_InvokeInlined" + FunctionType::name();
217 int main(int argc
, char** argv
) {
218 benchmark::Initialize(&argc
, argv
);
219 if (benchmark::ReportUnrecognizedArguments(argc
, argv
))
222 makeCartesianProductBenchmark
<ConstructAndDestroy
, AllOpacity
,
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();