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