1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/functional/function_ref.h"
16
17 #include <memory>
18
19 #include "benchmark/benchmark.h"
20 #include "absl/base/attributes.h"
21
22 namespace absl {
23 ABSL_NAMESPACE_BEGIN
24 namespace {
25
26 int dummy = 0;
27
FreeFunction()28 void FreeFunction() { benchmark::DoNotOptimize(dummy); }
29
30 struct TrivialFunctor {
operator ()absl::__anon608ce3690111::TrivialFunctor31 void operator()() const { benchmark::DoNotOptimize(dummy); }
32 };
33
34 struct LargeFunctor {
operator ()absl::__anon608ce3690111::LargeFunctor35 void operator()() const { benchmark::DoNotOptimize(this); }
36 std::string a, b, c;
37 };
38
39 template <typename Function, typename... Args>
CallFunction(Function f,Args &&...args)40 void ABSL_ATTRIBUTE_NOINLINE CallFunction(Function f, Args&&... args) {
41 f(std::forward<Args>(args)...);
42 }
43
44 template <typename Function, typename Callable, typename... Args>
ConstructAndCallFunctionBenchmark(benchmark::State & state,const Callable & c,Args &&...args)45 void ConstructAndCallFunctionBenchmark(benchmark::State& state,
46 const Callable& c, Args&&... args) {
47 for (auto _ : state) {
48 CallFunction<Function>(c, std::forward<Args>(args)...);
49 }
50 }
51
BM_TrivialStdFunction(benchmark::State & state)52 void BM_TrivialStdFunction(benchmark::State& state) {
53 ConstructAndCallFunctionBenchmark<std::function<void()>>(state,
54 TrivialFunctor{});
55 }
56 BENCHMARK(BM_TrivialStdFunction);
57
BM_TrivialFunctionRef(benchmark::State & state)58 void BM_TrivialFunctionRef(benchmark::State& state) {
59 ConstructAndCallFunctionBenchmark<FunctionRef<void()>>(state,
60 TrivialFunctor{});
61 }
62 BENCHMARK(BM_TrivialFunctionRef);
63
BM_LargeStdFunction(benchmark::State & state)64 void BM_LargeStdFunction(benchmark::State& state) {
65 ConstructAndCallFunctionBenchmark<std::function<void()>>(state,
66 LargeFunctor{});
67 }
68 BENCHMARK(BM_LargeStdFunction);
69
BM_LargeFunctionRef(benchmark::State & state)70 void BM_LargeFunctionRef(benchmark::State& state) {
71 ConstructAndCallFunctionBenchmark<FunctionRef<void()>>(state, LargeFunctor{});
72 }
73 BENCHMARK(BM_LargeFunctionRef);
74
BM_FunPtrStdFunction(benchmark::State & state)75 void BM_FunPtrStdFunction(benchmark::State& state) {
76 ConstructAndCallFunctionBenchmark<std::function<void()>>(state, FreeFunction);
77 }
78 BENCHMARK(BM_FunPtrStdFunction);
79
BM_FunPtrFunctionRef(benchmark::State & state)80 void BM_FunPtrFunctionRef(benchmark::State& state) {
81 ConstructAndCallFunctionBenchmark<FunctionRef<void()>>(state, FreeFunction);
82 }
83 BENCHMARK(BM_FunPtrFunctionRef);
84
85 // Doesn't include construction or copy overhead in the loop.
86 template <typename Function, typename Callable, typename... Args>
CallFunctionBenchmark(benchmark::State & state,const Callable & c,Args...args)87 void CallFunctionBenchmark(benchmark::State& state, const Callable& c,
88 Args... args) {
89 Function f = c;
90 for (auto _ : state) {
91 benchmark::DoNotOptimize(&f);
92 f(args...);
93 }
94 }
95
96 struct FunctorWithTrivialArgs {
operator ()absl::__anon608ce3690111::FunctorWithTrivialArgs97 void operator()(int a, int b, int c) const {
98 benchmark::DoNotOptimize(a);
99 benchmark::DoNotOptimize(b);
100 benchmark::DoNotOptimize(c);
101 }
102 };
103
BM_TrivialArgsStdFunction(benchmark::State & state)104 void BM_TrivialArgsStdFunction(benchmark::State& state) {
105 CallFunctionBenchmark<std::function<void(int, int, int)>>(
106 state, FunctorWithTrivialArgs{}, 1, 2, 3);
107 }
108 BENCHMARK(BM_TrivialArgsStdFunction);
109
BM_TrivialArgsFunctionRef(benchmark::State & state)110 void BM_TrivialArgsFunctionRef(benchmark::State& state) {
111 CallFunctionBenchmark<FunctionRef<void(int, int, int)>>(
112 state, FunctorWithTrivialArgs{}, 1, 2, 3);
113 }
114 BENCHMARK(BM_TrivialArgsFunctionRef);
115
116 struct FunctorWithNonTrivialArgs {
operator ()absl::__anon608ce3690111::FunctorWithNonTrivialArgs117 void operator()(std::string a, std::string b, std::string c) const {
118 benchmark::DoNotOptimize(&a);
119 benchmark::DoNotOptimize(&b);
120 benchmark::DoNotOptimize(&c);
121 }
122 };
123
BM_NonTrivialArgsStdFunction(benchmark::State & state)124 void BM_NonTrivialArgsStdFunction(benchmark::State& state) {
125 std::string a, b, c;
126 CallFunctionBenchmark<
127 std::function<void(std::string, std::string, std::string)>>(
128 state, FunctorWithNonTrivialArgs{}, a, b, c);
129 }
130 BENCHMARK(BM_NonTrivialArgsStdFunction);
131
BM_NonTrivialArgsFunctionRef(benchmark::State & state)132 void BM_NonTrivialArgsFunctionRef(benchmark::State& state) {
133 std::string a, b, c;
134 CallFunctionBenchmark<
135 FunctionRef<void(std::string, std::string, std::string)>>(
136 state, FunctorWithNonTrivialArgs{}, a, b, c);
137 }
138 BENCHMARK(BM_NonTrivialArgsFunctionRef);
139
140 } // namespace
141 ABSL_NAMESPACE_END
142 } // namespace absl
143