Fix to build SharedMutexTest on aarch64
[folly.git] / folly / test / function_benchmark / main.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
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 <folly/test/function_benchmark/benchmark_impl.h>
18 #include <folly/test/function_benchmark/test_functions.h>
19
20 #include <glog/logging.h>
21
22 #include <folly/Benchmark.h>
23 #include <folly/ScopeGuard.h>
24 #include <folly/portability/GFlags.h>
25
26 using folly::ScopeGuard;
27 using folly::makeGuard;
28
29 // Declare the bm_max_iters flag from folly/Benchmark.cpp
30 DECLARE_int32(bm_max_iters);
31
32 // Directly invoking a function
33 BENCHMARK(fn_invoke, iters) {
34   for (size_t n = 0; n < iters; ++n) {
35     doNothing();
36   }
37 }
38
39 // Invoking a function through a function pointer
40 BENCHMARK(fn_ptr_invoke, iters) {
41   BM_fn_ptr_invoke_impl(iters, doNothing);
42 }
43
44 // Invoking a function through a std::function object
45 BENCHMARK(std_function_invoke, iters) {
46   BM_std_function_invoke_impl(iters, doNothing);
47 }
48
49 // Invoking a function through a folly::Function object
50 BENCHMARK(Function_invoke, iters) {
51   BM_Function_invoke_impl(iters, doNothing);
52 }
53
54 // Invoking a member function through a member function pointer
55 BENCHMARK(mem_fn_invoke, iters) {
56   TestClass tc;
57   BM_mem_fn_invoke_impl(iters, &tc, &TestClass::doNothing);
58 }
59
60 // Invoke a function pointer through an inlined wrapper function
61 BENCHMARK(fn_ptr_invoke_through_inline, iters) {
62   BM_fn_ptr_invoke_inlined_impl(iters, doNothing);
63 }
64
65 // Invoke a lambda that calls doNothing() through an inlined wrapper function
66 BENCHMARK(lambda_invoke_fn, iters) {
67   BM_invoke_fn_template_impl(iters, [] { doNothing(); });
68 }
69
70 // Invoke a lambda that does nothing
71 BENCHMARK(lambda_noop, iters) {
72   BM_invoke_fn_template_impl(iters, [] {});
73 }
74
75 // Invoke a lambda that modifies a local variable
76 BENCHMARK(lambda_local_var, iters) {
77   uint32_t count1 = 0;
78   uint32_t count2 = 0;
79   BM_invoke_fn_template_impl(iters, [&] {
80     // Do something slightly more complicated than just incrementing a
81     // variable.  Otherwise gcc is smart enough to optimize the loop away.
82     if (count1 & 0x1) {
83       ++count2;
84     }
85     ++count1;
86   });
87
88   // Use the values we computed, so gcc won't optimize the loop away
89   CHECK_EQ(iters, count1);
90   CHECK_EQ(iters / 2, count2);
91 }
92
93 // Invoke a function pointer through the same wrapper used for lambdas
94 BENCHMARK(fn_ptr_invoke_through_template, iters) {
95   BM_invoke_fn_template_impl(iters, doNothing);
96 }
97
98 // Invoking a virtual method
99 BENCHMARK(virtual_fn_invoke, iters) {
100   VirtualClass vc;
101   BM_virtual_fn_invoke_impl(iters, &vc);
102 }
103
104 // Creating a function pointer and invoking it
105 BENCHMARK(fn_ptr_create_invoke, iters) {
106   for (size_t n = 0; n < iters; ++n) {
107     void (*fn)() = doNothing;
108     fn();
109   }
110 }
111
112 // Creating a std::function object from a function pointer, and invoking it
113 BENCHMARK(std_function_create_invoke, iters) {
114   for (size_t n = 0; n < iters; ++n) {
115     std::function<void()> fn = doNothing;
116     fn();
117   }
118 }
119
120 // Creating a folly::Function object from a function pointer, and
121 // invoking it
122 BENCHMARK(Function_create_invoke, iters) {
123   for (size_t n = 0; n < iters; ++n) {
124     folly::Function<void()> fn = doNothing;
125     fn();
126   }
127 }
128
129 // Creating a pointer-to-member and invoking it
130 BENCHMARK(mem_fn_create_invoke, iters) {
131   TestClass tc;
132   for (size_t n = 0; n < iters; ++n) {
133     void (TestClass::*memfn)() = &TestClass::doNothing;
134     (tc.*memfn)();
135   }
136 }
137
138 // Using std::bind to create a std::function from a member function,
139 // and invoking it
140 BENCHMARK(std_bind_create_invoke, iters) {
141   TestClass tc;
142   for (size_t n = 0; n < iters; ++n) {
143     std::function<void()> fn = std::bind(&TestClass::doNothing, &tc);
144     fn();
145   }
146 }
147
148 // Using std::bind directly to invoke a member function
149 BENCHMARK(std_bind_direct_invoke, iters) {
150   TestClass tc;
151   for (size_t n = 0; n < iters; ++n) {
152     auto fn = std::bind(&TestClass::doNothing, &tc);
153     fn();
154   }
155 }
156
157 // Using ScopeGuard to invoke a std::function
158 BENCHMARK(scope_guard_std_function, iters) {
159   std::function<void()> fn(doNothing);
160   for (size_t n = 0; n < iters; ++n) {
161     ScopeGuard g = makeGuard(fn);
162     (void)g;
163   }
164 }
165
166 // Using ScopeGuard to invoke a std::function,
167 // but create the ScopeGuard with an rvalue to a std::function
168 BENCHMARK(scope_guard_std_function_rvalue, iters) {
169   for (size_t n = 0; n < iters; ++n) {
170     ScopeGuard g = makeGuard(std::function<void()>(doNothing));
171     (void)g;
172   }
173 }
174
175 // Using ScopeGuard to invoke a folly::Function,
176 // but create the ScopeGuard with an rvalue to a folly::Function
177 BENCHMARK(scope_guard_Function_rvalue, iters) {
178   for (size_t n = 0; n < iters; ++n) {
179     ScopeGuard g = makeGuard(folly::Function<void()>(doNothing));
180     (void)g;
181   }
182 }
183
184 // Using ScopeGuard to invoke a function pointer
185 BENCHMARK(scope_guard_fn_ptr, iters) {
186   for (size_t n = 0; n < iters; ++n) {
187     ScopeGuard g = makeGuard(doNothing);
188     (void)g;
189   }
190 }
191
192 // Using ScopeGuard to invoke a lambda that does nothing
193 BENCHMARK(scope_guard_lambda_noop, iters) {
194   for (size_t n = 0; n < iters; ++n) {
195     ScopeGuard g = makeGuard([] {});
196     (void)g;
197   }
198 }
199
200 // Using ScopeGuard to invoke a lambda that invokes a function
201 BENCHMARK(scope_guard_lambda_function, iters) {
202   for (size_t n = 0; n < iters; ++n) {
203     ScopeGuard g = makeGuard([] { doNothing(); });
204     (void)g;
205   }
206 }
207
208 // Using ScopeGuard to invoke a lambda that modifies a local variable
209 BENCHMARK(scope_guard_lambda_local_var, iters) {
210   uint32_t count = 0;
211   for (size_t n = 0; n < iters; ++n) {
212     ScopeGuard g = makeGuard([&] {
213       // Increment count if n is odd.  Without this conditional check
214       // (i.e., if we just increment count each time through the loop),
215       // gcc is smart enough to optimize the entire loop away, and just set
216       // count = iters.
217       if (n & 0x1) {
218         ++count;
219       }
220     });
221     (void)g;
222   }
223
224   // Check that the value of count is what we expect.
225   // This check is necessary: if we don't use count, gcc detects that count is
226   // unused and optimizes the entire loop away.
227   CHECK_EQ(iters / 2, count);
228 }
229
230 BENCHMARK_DRAW_LINE()
231
232 BENCHMARK(throw_exception, iters) {
233   for (size_t n = 0; n < iters; ++n) {
234     try {
235       throwException();
236     } catch (const std::exception& ex) {
237     }
238   }
239 }
240
241 BENCHMARK(catch_no_exception, iters) {
242   for (size_t n = 0; n < iters; ++n) {
243     try {
244       doNothing();
245     } catch (const std::exception& ex) {
246     }
247   }
248 }
249
250 BENCHMARK(return_exc_ptr, iters) {
251   for (size_t n = 0; n < iters; ++n) {
252     returnExceptionPtr();
253   }
254 }
255
256 BENCHMARK(exc_ptr_param_return, iters) {
257   for (size_t n = 0; n < iters; ++n) {
258     std::exception_ptr ex;
259     exceptionPtrReturnParam(&ex);
260   }
261 }
262
263 BENCHMARK(exc_ptr_param_return_null, iters) {
264   for (size_t n = 0; n < iters; ++n) {
265     exceptionPtrReturnParam(nullptr);
266   }
267 }
268
269 BENCHMARK(return_string, iters) {
270   for (size_t n = 0; n < iters; ++n) {
271     returnString();
272   }
273 }
274
275 BENCHMARK(return_string_noexcept, iters) {
276   for (size_t n = 0; n < iters; ++n) {
277     returnStringNoExcept();
278   }
279 }
280
281 BENCHMARK(return_code, iters) {
282   for (size_t n = 0; n < iters; ++n) {
283     returnCode(false);
284   }
285 }
286
287 BENCHMARK(return_code_noexcept, iters) {
288   for (size_t n = 0; n < iters; ++n) {
289     returnCodeNoExcept(false);
290   }
291 }
292
293 BENCHMARK_DRAW_LINE()
294
295 BENCHMARK(std_function_create_move_invoke, iters) {
296   LargeClass a;
297   for (size_t i = 0; i < iters; ++i) {
298     std::function<void()> f(a);
299     invoke(std::move(f));
300   }
301 }
302
303 BENCHMARK(Function_create_move_invoke, iters) {
304   LargeClass a;
305   for (size_t i = 0; i < iters; ++i) {
306     folly::Function<void()> f(a);
307     invoke(std::move(f));
308   }
309 }
310
311 BENCHMARK(std_function_create_move_invoke_ref, iters) {
312   LargeClass a;
313   for (size_t i = 0; i < iters; ++i) {
314     std::function<void()> f(std::ref(a));
315     invoke(std::move(f));
316   }
317 }
318
319 BENCHMARK(Function_create_move_invoke_ref, iters) {
320   LargeClass a;
321   for (size_t i = 0; i < iters; ++i) {
322     folly::Function<void()> f(std::ref(a));
323     invoke(std::move(f));
324   }
325 }
326
327 // main()
328
329 int main(int argc, char** argv) {
330   gflags::ParseCommandLineFlags(&argc, &argv, true);
331   folly::runBenchmarks();
332 }