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