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
[] = {
37 "SmallTrivialFunctor",
38 "SmallNonTrivialFunctor",
39 "LargeTrivialFunctor",
40 "LargeNonTrivialFunctor"};
43 enum class Opacity
{ kOpaque
, kTransparent
};
45 struct AllOpacity
: EnumValuesAsTuple
<AllOpacity
, Opacity
, 2> {
46 static constexpr const char* Names
[] = {"Opaque", "Transparent"};
50 int function() const { return 0; }
54 int FunctionWithS(const S
*) { return 0; }
56 struct SmallTrivialFunctor
{
57 int operator()(const S
*) const { return 0; }
59 struct SmallNonTrivialFunctor
{
60 SmallNonTrivialFunctor() {}
61 SmallNonTrivialFunctor(const SmallNonTrivialFunctor
&) {}
62 ~SmallNonTrivialFunctor() {}
63 int operator()(const S
*) const { return 0; }
65 struct LargeTrivialFunctor
{
66 LargeTrivialFunctor() {
67 // Do not spend time initializing the padding.
70 int operator()(const S
*) const { return 0; }
72 struct LargeNonTrivialFunctor
{
74 LargeNonTrivialFunctor() {
75 // Do not spend time initializing the padding.
77 LargeNonTrivialFunctor(const LargeNonTrivialFunctor
&) {}
78 ~LargeNonTrivialFunctor() {}
79 int operator()(const S
*) const { return 0; }
82 using Function
= std::function
<int(const S
*)>;
85 inline Function
MakeFunction(FunctionType type
, bool opaque
= false) {
87 case FunctionType::Null
:
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
);
106 template <class Opacity
, class FunctionType
>
107 struct ConstructAndDestroy
{
108 static void run(benchmark::State
& state
) {
109 for (auto _
: state
) {
110 if (Opacity() == ::Opacity::kOpaque
) {
111 benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
113 MakeFunction(FunctionType());
118 static std::string
name() { return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name(); }
121 template <class FunctionType
>
123 static void run(benchmark::State
& state
) {
124 auto value
= MakeFunction(FunctionType());
125 for (auto _
: state
) {
126 benchmark::DoNotOptimize(value
);
127 auto copy
= value
; // NOLINT
128 benchmark::DoNotOptimize(copy
);
132 static std::string
name() { return "BM_Copy" + FunctionType::name(); }
135 template <class FunctionType
>
137 static void run(benchmark::State
& state
) {
138 Function values
[2] = {MakeFunction(FunctionType())};
140 for (auto _
: state
) {
141 benchmark::DoNotOptimize(values
);
142 benchmark::DoNotOptimize(values
[i
^ 1] = std::move(values
[i
]));
147 static std::string
name() { return "BM_Move" + FunctionType::name(); }
150 template <class Function1
, class Function2
>
152 static void run(benchmark::State
& state
) {
153 Function values
[2] = {MakeFunction(Function1()), MakeFunction(Function2())};
154 for (auto _
: state
) {
155 benchmark::DoNotOptimize(values
);
156 values
[0].swap(values
[1]);
160 static bool skip() { return Function1() > Function2(); }
162 static std::string
name() { return "BM_Swap" + Function1::name() + Function2::name(); }
165 template <class FunctionType
>
166 struct OperatorBool
{
167 static void run(benchmark::State
& state
) {
168 auto f
= MakeFunction(FunctionType());
169 for (auto _
: state
) {
170 benchmark::DoNotOptimize(f
);
171 benchmark::DoNotOptimize(static_cast<bool>(f
));
175 static std::string
name() { return "BM_OperatorBool" + FunctionType::name(); }
178 template <class FunctionType
>
180 static void run(benchmark::State
& state
) {
182 const auto value
= MakeFunction(FunctionType());
183 for (auto _
: state
) {
184 benchmark::DoNotOptimize(value
);
185 benchmark::DoNotOptimize(value(&s
));
189 static bool skip() { return FunctionType() == ::FunctionType::Null
; }
191 static std::string
name() { return "BM_Invoke" + FunctionType::name(); }
194 template <class FunctionType
>
195 struct InvokeInlined
{
196 static void run(benchmark::State
& state
) {
198 for (auto _
: state
) {
199 MakeFunction(FunctionType())(&s
);
203 static bool skip() { return FunctionType() == ::FunctionType::Null
; }
205 static std::string
name() { return "BM_InvokeInlined" + FunctionType::name(); }
210 int main(int argc
, char** argv
) {
211 benchmark::Initialize(&argc
, argv
);
212 if (benchmark::ReportUnrecognizedArguments(argc
, argv
))
215 makeCartesianProductBenchmark
<ConstructAndDestroy
, AllOpacity
, AllFunctionTypes
>();
216 makeCartesianProductBenchmark
<Copy
, AllFunctionTypes
>();
217 makeCartesianProductBenchmark
<Move
, AllFunctionTypes
>();
218 makeCartesianProductBenchmark
<Swap
, AllFunctionTypes
, AllFunctionTypes
>();
219 makeCartesianProductBenchmark
<OperatorBool
, AllFunctionTypes
>();
220 makeCartesianProductBenchmark
<Invoke
, AllFunctionTypes
>();
221 makeCartesianProductBenchmark
<InvokeInlined
, AllFunctionTypes
>();
222 benchmark::RunSpecifiedBenchmarks();