1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cstdint>
18 #include <functional>
19 #include <memory>
20 #include <tuple>
21 #include <type_traits>
22
23 #include <folly/Benchmark.h>
24 #include <folly/Function.h>
25 #include <folly/Random.h>
26 #include <folly/synchronization/detail/InlineFunctionRef.h>
27
28 /**
29 * ============================================================================
30 * folly/test/FunctionRefBenchmark.cpp relative time/iter iters/s
31 * ============================================================================
32 * SmallFunctionFunctionPointerInvoke 3.02ns 331.34M
33 * SmallFunctionStdFunctionInvoke 3.02ns 331.34M
34 * SmallFunctionStdFunctionWithReferenceWrapperInv 3.02ns 331.33M
35 * SmallFunctionFollyFunctionInvoke 3.02ns 331.30M
36 * SmallFunctionFollyFunctionRefInvoke 3.02ns 331.34M
37 * ----------------------------------------------------------------------------
38 * SmallFunctionFunctionPointerCreateInvoke 3.02ns 331.34M
39 * SmallFunctionStdFunctionCreateInvoke 3.76ns 266.24M
40 * SmallFunctionStdFunctionReferenceWrapperCreateI 4.77ns 209.52M
41 * SmallFunctionFollyFunctionCreateInvoke 3.24ns 308.40M
42 * SmallFunctionFollyFunctionRefCreateInvoke 3.02ns 331.34M
43 * ----------------------------------------------------------------------------
44 * BigFunctionStdFunctionInvoke 3.02ns 330.74M
45 * BigFunctionStdFunctionReferenceWrapperInvoke 3.02ns 330.74M
46 * BigFunctionFollyFunctionInvoke 3.02ns 331.31M
47 * BigFunctionFollyFunctionRefInvoke 3.02ns 331.31M
48 * ----------------------------------------------------------------------------
49 * BigFunctionStdFunctionCreateInvoke 43.87ns 22.79M
50 * BigFunctionStdFunctionReferenceWrapperCreateInv 4.20ns 238.22M
51 * BigFunctionFollyFunctionCreateInvoke 43.01ns 23.25M
52 * BigFunctionFollyFunctionRefCreateInvoke 3.02ns 331.31M
53 * ============================================================================
54 */
55
56 namespace folly {
57 namespace {
58 template <typename MakeFunction>
runSmallInvokeBenchmark(std::size_t iters,MakeFunction make)59 void runSmallInvokeBenchmark(std::size_t iters, MakeFunction make) {
60 auto lambda = [](auto& i) {
61 folly::makeUnpredictable(i);
62 return i;
63 };
64 folly::makeUnpredictable(lambda);
65 auto func = make(lambda);
66 folly::makeUnpredictable(func);
67
68 for (auto i = iters; --i;) {
69 folly::doNotOptimizeAway(func(i));
70 }
71 }
72
73 template <typename MakeFunction>
runSmallCreateAndInvokeBenchmark(std::size_t iters,MakeFunction make)74 void runSmallCreateAndInvokeBenchmark(std::size_t iters, MakeFunction make) {
75 auto lambda = [](auto& i) {
76 folly::makeUnpredictable(i);
77 return i;
78 };
79 folly::makeUnpredictable(lambda);
80
81 for (auto i = iters; --i;) {
82 auto func = make(lambda);
83 folly::makeUnpredictable(func);
84 folly::doNotOptimizeAway(func(i));
85 }
86 }
87
88 template <typename MakeFunction>
runBigAndInvokeBenchmark(std::size_t iters,MakeFunction make)89 void runBigAndInvokeBenchmark(std::size_t iters, MakeFunction make) {
90 auto suspender = BenchmarkSuspender{};
91 auto array = std::array<std::uint8_t, 4096>{};
92
93 auto lambda = [=](auto& i) {
94 // we use std::ignore to ensure ODR-usage of array
95 std::ignore = array;
96 folly::makeUnpredictable(i);
97 return i;
98 };
99 folly::makeUnpredictable(lambda);
100 auto func = make(lambda);
101 folly::makeUnpredictable(func);
102
103 suspender.dismissing([&] {
104 for (auto i = iters; --i;) {
105 folly::doNotOptimizeAway(func(i));
106 }
107 });
108 }
109
110 template <typename MakeFunction>
runBigCreateAndInvokeBenchmark(std::size_t iters,MakeFunction make)111 void runBigCreateAndInvokeBenchmark(std::size_t iters, MakeFunction make) {
112 auto suspender = BenchmarkSuspender{};
113 auto array = std::array<std::uint8_t, 1024>{};
114 folly::makeUnpredictable(array);
115
116 auto lambda = [=](auto& i) {
117 folly::doNotOptimizeAway(array);
118 folly::makeUnpredictable(i);
119 return i;
120 };
121 folly::makeUnpredictable(lambda);
122
123 suspender.dismissing([&] {
124 for (auto i = iters; --i;) {
125 auto func = make(lambda);
126 folly::makeUnpredictable(func);
127 folly::doNotOptimizeAway(func(i));
128 }
129 });
130 }
131 } // namespace
132
BENCHMARK(SmallFunctionFunctionPointerInvoke,iters)133 BENCHMARK(SmallFunctionFunctionPointerInvoke, iters) {
134 using FPtr = size_t (*)(size_t&);
135 runSmallInvokeBenchmark(iters, [](auto& f) { return FPtr{f}; });
136 }
BENCHMARK(SmallFunctionStdFunctionInvoke,iters)137 BENCHMARK(SmallFunctionStdFunctionInvoke, iters) {
138 runSmallInvokeBenchmark(
139 iters, [](auto& f) { return std::function<size_t(size_t&)>{f}; });
140 }
BENCHMARK(SmallFunctionStdFunctionWithReferenceWrapperInvoke,iters)141 BENCHMARK(SmallFunctionStdFunctionWithReferenceWrapperInvoke, iters) {
142 runSmallInvokeBenchmark(iters, [](auto& f) {
143 return std::function<size_t(size_t&)>{std::ref(f)};
144 });
145 }
BENCHMARK(SmallFunctionFollyFunctionInvoke,iters)146 BENCHMARK(SmallFunctionFollyFunctionInvoke, iters) {
147 runSmallInvokeBenchmark(
148 iters, [](auto& f) { return folly::Function<size_t(size_t&)>{f}; });
149 }
BENCHMARK(SmallFunctionFollyFunctionRefInvoke,iters)150 BENCHMARK(SmallFunctionFollyFunctionRefInvoke, iters) {
151 runSmallInvokeBenchmark(
152 iters, [](auto& f) { return folly::FunctionRef<size_t(size_t&)>{f}; });
153 }
BENCHMARK(SmallFunctionFollyInlineFunctionRefInvoke,iters)154 BENCHMARK(SmallFunctionFollyInlineFunctionRefInvoke, iters) {
155 runSmallInvokeBenchmark(iters, [](auto f) {
156 return detail::InlineFunctionRef<size_t(size_t&), 24>{std::move(f)};
157 });
158 }
159
160 BENCHMARK_DRAW_LINE();
BENCHMARK(SmallFunctionFunctionPointerCreateInvoke,iters)161 BENCHMARK(SmallFunctionFunctionPointerCreateInvoke, iters) {
162 using FPtr = size_t (*)(size_t&);
163 runSmallCreateAndInvokeBenchmark(iters, [](auto& f) { return FPtr{f}; });
164 }
BENCHMARK(SmallFunctionStdFunctionCreateInvoke,iters)165 BENCHMARK(SmallFunctionStdFunctionCreateInvoke, iters) {
166 runSmallCreateAndInvokeBenchmark(
167 iters, [](auto& f) { return std::function<size_t(size_t&)>{f}; });
168 }
BENCHMARK(SmallFunctionStdFunctionReferenceWrapperCreateInvoke,iters)169 BENCHMARK(SmallFunctionStdFunctionReferenceWrapperCreateInvoke, iters) {
170 runSmallCreateAndInvokeBenchmark(iters, [](auto& f) {
171 return std::function<size_t(size_t&)>{std::ref(f)};
172 });
173 }
BENCHMARK(SmallFunctionFollyFunctionCreateInvoke,iters)174 BENCHMARK(SmallFunctionFollyFunctionCreateInvoke, iters) {
175 runSmallCreateAndInvokeBenchmark(
176 iters, [](auto& f) { return folly::Function<size_t(size_t&)>{f}; });
177 }
BENCHMARK(SmallFunctionFollyFunctionRefCreateInvoke,iters)178 BENCHMARK(SmallFunctionFollyFunctionRefCreateInvoke, iters) {
179 runSmallCreateAndInvokeBenchmark(
180 iters, [](auto& f) { return folly::FunctionRef<size_t(size_t&)>{f}; });
181 }
BENCHMARK(SmallFunctionFollyInlineFunctionRefCreateInvoke,iters)182 BENCHMARK(SmallFunctionFollyInlineFunctionRefCreateInvoke, iters) {
183 runSmallInvokeBenchmark(iters, [](auto f) {
184 return detail::InlineFunctionRef<size_t(size_t&), 24>{std::move(f)};
185 });
186 }
187
188 BENCHMARK_DRAW_LINE();
BENCHMARK(BigFunctionStdFunctionInvoke,iters)189 BENCHMARK(BigFunctionStdFunctionInvoke, iters) {
190 runBigAndInvokeBenchmark(
191 iters, [](auto& f) { return std::function<size_t(size_t&)>{f}; });
192 }
BENCHMARK(BigFunctionStdFunctionReferenceWrapperInvoke,iters)193 BENCHMARK(BigFunctionStdFunctionReferenceWrapperInvoke, iters) {
194 runBigAndInvokeBenchmark(iters, [](auto& f) {
195 return std::function<size_t(size_t&)>{std::ref(f)};
196 });
197 }
BENCHMARK(BigFunctionFollyFunctionInvoke,iters)198 BENCHMARK(BigFunctionFollyFunctionInvoke, iters) {
199 runBigAndInvokeBenchmark(
200 iters, [](auto& f) { return folly::Function<size_t(size_t&)>{f}; });
201 }
BENCHMARK(BigFunctionFollyFunctionRefInvoke,iters)202 BENCHMARK(BigFunctionFollyFunctionRefInvoke, iters) {
203 runBigAndInvokeBenchmark(
204 iters, [](auto& f) { return folly::FunctionRef<size_t(size_t&)>{f}; });
205 }
BENCHMARK(BigFunctionFollyInlineFunctionRefInvoke,iters)206 BENCHMARK(BigFunctionFollyInlineFunctionRefInvoke, iters) {
207 runSmallInvokeBenchmark(iters, [](auto f) {
208 return detail::InlineFunctionRef<size_t(size_t&), 24>{std::move(f)};
209 });
210 }
211
212 BENCHMARK_DRAW_LINE();
BENCHMARK(BigFunctionStdFunctionCreateInvoke,iters)213 BENCHMARK(BigFunctionStdFunctionCreateInvoke, iters) {
214 runBigCreateAndInvokeBenchmark(
215 iters, [](auto& f) { return std::function<size_t(size_t&)>{f}; });
216 }
BENCHMARK(BigFunctionStdFunctionReferenceWrapperCreateInvoke,iters)217 BENCHMARK(BigFunctionStdFunctionReferenceWrapperCreateInvoke, iters) {
218 runBigCreateAndInvokeBenchmark(iters, [](auto& f) {
219 return std::function<size_t(size_t&)>{std::ref(f)};
220 });
221 }
BENCHMARK(BigFunctionFollyFunctionCreateInvoke,iters)222 BENCHMARK(BigFunctionFollyFunctionCreateInvoke, iters) {
223 runBigCreateAndInvokeBenchmark(
224 iters, [](auto& f) { return folly::Function<size_t(size_t&)>{f}; });
225 }
BENCHMARK(BigFunctionFollyFunctionRefCreateInvoke,iters)226 BENCHMARK(BigFunctionFollyFunctionRefCreateInvoke, iters) {
227 runBigCreateAndInvokeBenchmark(
228 iters, [](auto& f) { return folly::FunctionRef<size_t(size_t&)>{f}; });
229 }
BENCHMARK(BigFunctionFollyInlineFunctionRefCreateInvoke,iters)230 BENCHMARK(BigFunctionFollyInlineFunctionRefCreateInvoke, iters) {
231 runSmallInvokeBenchmark(iters, [](auto f) {
232 return detail::InlineFunctionRef<size_t(size_t&), 24>{std::move(f)};
233 });
234 }
235 } // namespace folly
236
main(int argc,char ** argv)237 int main(int argc, char** argv) {
238 gflags::ParseCommandLineFlags(&argc, &argv, true);
239 folly::runBenchmarks();
240 }
241