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