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 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
17 #include "CartesianBenchmarks.h"
18 #include "benchmark/benchmark.h"
19 #include "test_macros.h"
23 enum class FunctionType
{
26 MemberFunctionPointer
,
29 SmallNonTrivialFunctor
,
31 LargeNonTrivialFunctor
34 struct AllFunctionTypes
: EnumValuesAsTuple
<AllFunctionTypes
, FunctionType
, 8> {
35 static constexpr const char* Names
[] = {
40 "SmallTrivialFunctor",
41 "SmallNonTrivialFunctor",
42 "LargeTrivialFunctor",
43 "LargeNonTrivialFunctor"};
46 enum class Opacity
{ kOpaque
, kTransparent
};
48 struct AllOpacity
: EnumValuesAsTuple
<AllOpacity
, Opacity
, 2> {
49 static constexpr const char* Names
[] = {"Opaque", "Transparent"};
53 int function() const { return 0; }
57 int FunctionWithS(const S
*) { return 0; }
59 struct SmallTrivialFunctor
{
60 int operator()(const S
*) const { return 0; }
62 struct SmallNonTrivialFunctor
{
63 SmallNonTrivialFunctor() {}
64 SmallNonTrivialFunctor(const SmallNonTrivialFunctor
&) {}
65 ~SmallNonTrivialFunctor() {}
66 int operator()(const S
*) const { return 0; }
68 struct LargeTrivialFunctor
{
69 LargeTrivialFunctor() {
70 // Do not spend time initializing the padding.
73 int operator()(const S
*) const { return 0; }
75 struct LargeNonTrivialFunctor
{
77 LargeNonTrivialFunctor() {
78 // Do not spend time initializing the padding.
80 LargeNonTrivialFunctor(const LargeNonTrivialFunctor
&) {}
81 ~LargeNonTrivialFunctor() {}
82 int operator()(const S
*) const { return 0; }
85 using Function
= std::function
<int(const S
*)>;
88 inline Function
MakeFunction(FunctionType type
, bool opaque
= false) {
90 case FunctionType::Null
:
92 case FunctionType::FunctionPointer
:
93 return maybeOpaque(FunctionWithS
, opaque
);
94 case FunctionType::MemberFunctionPointer
:
95 return maybeOpaque(&S::function
, opaque
);
96 case FunctionType::MemberPointer
:
97 return maybeOpaque(&S::field
, opaque
);
98 case FunctionType::SmallTrivialFunctor
:
99 return maybeOpaque(SmallTrivialFunctor
{}, opaque
);
100 case FunctionType::SmallNonTrivialFunctor
:
101 return maybeOpaque(SmallNonTrivialFunctor
{}, opaque
);
102 case FunctionType::LargeTrivialFunctor
:
103 return maybeOpaque(LargeTrivialFunctor
{}, opaque
);
104 case FunctionType::LargeNonTrivialFunctor
:
105 return maybeOpaque(LargeNonTrivialFunctor
{}, opaque
);
110 template <class Opacity
, class FunctionType
>
111 struct ConstructAndDestroy
{
112 static void run(benchmark::State
& state
) {
113 for (auto _
: state
) {
114 if (Opacity() == ::Opacity::kOpaque
) {
115 benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
117 MakeFunction(FunctionType());
122 static std::string
name() { return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name(); }
125 template <class FunctionType
>
127 static void run(benchmark::State
& state
) {
128 auto value
= MakeFunction(FunctionType());
129 for (auto _
: state
) {
130 benchmark::DoNotOptimize(value
);
131 auto copy
= value
; // NOLINT
132 benchmark::DoNotOptimize(copy
);
136 static std::string
name() { return "BM_Copy" + FunctionType::name(); }
139 template <class FunctionType
>
141 static void run(benchmark::State
& state
) {
142 Function values
[2] = {MakeFunction(FunctionType())};
144 for (auto _
: state
) {
145 benchmark::DoNotOptimize(values
);
146 benchmark::DoNotOptimize(values
[i
^ 1] = std::move(values
[i
]));
151 static std::string
name() { return "BM_Move" + FunctionType::name(); }
154 template <class Function1
, class Function2
>
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]);
164 static bool skip() { return Function1() > Function2(); }
166 static std::string
name() { return "BM_Swap" + Function1::name() + Function2::name(); }
169 template <class FunctionType
>
170 struct OperatorBool
{
171 static void run(benchmark::State
& state
) {
172 auto f
= MakeFunction(FunctionType());
173 for (auto _
: state
) {
174 benchmark::DoNotOptimize(f
);
175 benchmark::DoNotOptimize(static_cast<bool>(f
));
179 static std::string
name() { return "BM_OperatorBool" + FunctionType::name(); }
182 template <class FunctionType
>
184 static void run(benchmark::State
& state
) {
186 auto value
= MakeFunction(FunctionType());
187 for (auto _
: state
) {
188 benchmark::DoNotOptimize(value
);
189 benchmark::DoNotOptimize(value(&s
));
193 static bool skip() { return FunctionType() == ::FunctionType::Null
; }
195 static std::string
name() { return "BM_Invoke" + FunctionType::name(); }
198 template <class FunctionType
>
199 struct InvokeInlined
{
200 static void run(benchmark::State
& state
) {
202 for (auto _
: state
) {
203 MakeFunction(FunctionType())(&s
);
207 static bool skip() { return FunctionType() == ::FunctionType::Null
; }
209 static std::string
name() { return "BM_InvokeInlined" + FunctionType::name(); }
214 int main(int argc
, char** argv
) {
215 benchmark::Initialize(&argc
, argv
);
216 if (benchmark::ReportUnrecognizedArguments(argc
, argv
))
219 makeCartesianProductBenchmark
<ConstructAndDestroy
, AllOpacity
, AllFunctionTypes
>();
220 makeCartesianProductBenchmark
<Copy
, AllFunctionTypes
>();
221 makeCartesianProductBenchmark
<Move
, AllFunctionTypes
>();
222 makeCartesianProductBenchmark
<Swap
, AllFunctionTypes
, AllFunctionTypes
>();
223 makeCartesianProductBenchmark
<OperatorBool
, AllFunctionTypes
>();
224 makeCartesianProductBenchmark
<Invoke
, AllFunctionTypes
>();
225 makeCartesianProductBenchmark
<InvokeInlined
, AllFunctionTypes
>();
226 benchmark::RunSpecifiedBenchmarks();