proxygen
main.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-present 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 
19 
20 #include <glog/logging.h>
21 
22 #include <folly/Benchmark.h>
23 #include <folly/ScopeGuard.h>
25 
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) {
41 }
42 
43 // Invoking a function through a std::function object
44 BENCHMARK(std_function_invoke, iters) {
46 }
47 
48 // Invoking a function through a folly::Function object
49 BENCHMARK(Function_invoke, iters) {
51 }
52 
53 // Invoking a member function through a member function pointer
54 BENCHMARK(mem_fn_invoke, iters) {
55  TestClass tc;
57 }
58 
59 // Invoke a function pointer through an inlined wrapper function
60 BENCHMARK(fn_ptr_invoke_through_inline, iters) {
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) {
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) {
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  auto g = makeGuard(fn);
161  (void)g;
162  }
163 }
164 
165 // Using ScopeGuard to invoke a std::function,
166 // but create the ScopeGuard with an rvalue to a std::function
167 BENCHMARK(scope_guard_std_function_rvalue, iters) {
168  for (size_t n = 0; n < iters; ++n) {
169  auto g = makeGuard(std::function<void()>(doNothing));
170  (void)g;
171  }
172 }
173 
174 // Using ScopeGuard to invoke a folly::Function,
175 // but create the ScopeGuard with an rvalue to a folly::Function
176 BENCHMARK(scope_guard_Function_rvalue, iters) {
177  for (size_t n = 0; n < iters; ++n) {
178  auto g = makeGuard(folly::Function<void()>(doNothing));
179  (void)g;
180  }
181 }
182 
183 // Using ScopeGuard to invoke a function pointer
184 BENCHMARK(scope_guard_fn_ptr, iters) {
185  for (size_t n = 0; n < iters; ++n) {
186  auto g = makeGuard(doNothing);
187  (void)g;
188  }
189 }
190 
191 // Using ScopeGuard to invoke a lambda that does nothing
192 BENCHMARK(scope_guard_lambda_noop, iters) {
193  for (size_t n = 0; n < iters; ++n) {
194  auto g = makeGuard([] {});
195  (void)g;
196  }
197 }
198 
199 // Using ScopeGuard to invoke a lambda that invokes a function
200 BENCHMARK(scope_guard_lambda_function, iters) {
201  for (size_t n = 0; n < iters; ++n) {
202  auto g = makeGuard([] { doNothing(); });
203  (void)g;
204  }
205 }
206 
207 // Using ScopeGuard to invoke a lambda that modifies a local variable
208 BENCHMARK(scope_guard_lambda_local_var, iters) {
209  uint32_t count = 0;
210  for (size_t n = 0; n < iters; ++n) {
211  auto g = makeGuard([&] {
212  // Increment count if n is odd. Without this conditional check
213  // (i.e., if we just increment count each time through the loop),
214  // gcc is smart enough to optimize the entire loop away, and just set
215  // count = iters.
216  if (n & 0x1) {
217  ++count;
218  }
219  });
220  (void)g;
221  }
222 
223  // Check that the value of count is what we expect.
224  // This check is necessary: if we don't use count, gcc detects that count is
225  // unused and optimizes the entire loop away.
226  CHECK_EQ(iters / 2, count);
227 }
228 
230 
232  for (size_t n = 0; n < iters; ++n) {
233  try {
234  folly::throw_exception<Exception>("this is a test");
235  } catch (const std::exception& ex) {
236  }
237  }
238 }
239 
240 BENCHMARK(catch_no_exception, iters) {
241  for (size_t n = 0; n < iters; ++n) {
242  try {
243  doNothing();
244  } catch (const std::exception& ex) {
245  }
246  }
247 }
248 
249 BENCHMARK(return_exc_ptr, iters) {
250  for (size_t n = 0; n < iters; ++n) {
252  }
253 }
254 
255 BENCHMARK(exc_ptr_param_return, iters) {
256  for (size_t n = 0; n < iters; ++n) {
257  std::exception_ptr ex;
259  }
260 }
261 
262 BENCHMARK(exc_ptr_param_return_null, iters) {
263  for (size_t n = 0; n < iters; ++n) {
264  exceptionPtrReturnParam(nullptr);
265  }
266 }
267 
268 BENCHMARK(return_string, iters) {
269  for (size_t n = 0; n < iters; ++n) {
270  returnString();
271  }
272 }
273 
274 BENCHMARK(return_string_noexcept, iters) {
275  for (size_t n = 0; n < iters; ++n) {
277  }
278 }
279 
280 BENCHMARK(return_code, iters) {
281  for (size_t n = 0; n < iters; ++n) {
282  returnCode(false);
283  }
284 }
285 
286 BENCHMARK(return_code_noexcept, iters) {
287  for (size_t n = 0; n < iters; ++n) {
288  returnCodeNoExcept(false);
289  }
290 }
291 
293 
294 BENCHMARK(std_function_create_move_invoke, iters) {
295  LargeClass a;
296  for (size_t i = 0; i < iters; ++i) {
297  std::function<void()> f(a);
298  invoke(std::move(f));
299  }
300 }
301 
302 BENCHMARK(Function_create_move_invoke, iters) {
303  LargeClass a;
304  for (size_t i = 0; i < iters; ++i) {
306  invoke(std::move(f));
307  }
308 }
309 
310 BENCHMARK(std_function_create_move_invoke_small, iters) {
311  for (size_t i = 0; i < iters; ++i) {
312  std::function<void()> f(doNothing);
313  invoke(std::move(f));
314  }
315 }
316 
317 BENCHMARK(Function_create_move_invoke_small, iters) {
318  for (size_t i = 0; i < iters; ++i) {
320  invoke(std::move(f));
321  }
322 }
323 
324 BENCHMARK(std_function_create_move_invoke_ref, iters) {
325  LargeClass a;
326  for (size_t i = 0; i < iters; ++i) {
327  std::function<void()> f(std::ref(a));
328  invoke(std::move(f));
329  }
330 }
331 
332 BENCHMARK(Function_create_move_invoke_ref, iters) {
333  LargeClass a;
334  for (size_t i = 0; i < iters; ++i) {
335  folly::Function<void()> f(std::ref(a));
336  invoke(std::move(f));
337  }
338 }
339 
341 
342 BENCHMARK(function_ptr_move, iters) {
343  auto f = &doNothing;
344  for (size_t i = 0; i < iters; ++i) {
345  auto f2 = std::move(f);
347  f = std::move(f2);
348  }
349 }
350 
351 BENCHMARK(std_function_move_small, iters) {
352  std::shared_ptr<int> a(new int);
353  std::function<void()> f([a]() { doNothing(); });
354  for (size_t i = 0; i < iters; ++i) {
355  auto f2 = std::move(f);
357  f = std::move(f2);
358  }
359 }
360 
361 BENCHMARK(Function_move_small, iters) {
362  std::shared_ptr<int> a(new int);
363  folly::Function<void()> f([a]() { doNothing(); });
364  for (size_t i = 0; i < iters; ++i) {
365  auto f2 = std::move(f);
367  f = std::move(f2);
368  }
369 }
370 
371 BENCHMARK(std_function_move_small_trivial, iters) {
372  std::function<void()> f(doNothing);
373  for (size_t i = 0; i < iters; ++i) {
374  auto f2 = std::move(f);
376  f = std::move(f2);
377  }
378 }
379 
380 BENCHMARK(Function_move_small_trivial, iters) {
382  for (size_t i = 0; i < iters; ++i) {
383  auto f2 = std::move(f);
385  f = std::move(f2);
386  }
387 }
388 
389 BENCHMARK(std_function_move_large, iters) {
390  LargeClass a;
391  std::function<void()> f(a);
392  for (size_t i = 0; i < iters; ++i) {
393  auto f2 = std::move(f);
395  f = std::move(f2);
396  }
397 }
398 
399 BENCHMARK(Function_move_large, iters) {
400  LargeClass a;
402  for (size_t i = 0; i < iters; ++i) {
403  auto f2 = std::move(f);
405  f = std::move(f2);
406  }
407 }
408 
409 // main()
410 
411 int main(int argc, char** argv) {
412  gflags::ParseCommandLineFlags(&argc, &argv, true);
414 }
415 
416 /*
417 ============================================================================
418 folly/test/function_benchmark/main.cpp relative time/iter iters/s
419 ============================================================================
420 fn_invoke 1.22ns 822.88M
421 fn_ptr_invoke 1.22ns 822.99M
422 std_function_invoke 2.73ns 365.78M
423 Function_invoke 2.73ns 365.79M
424 mem_fn_invoke 1.37ns 731.38M
425 fn_ptr_invoke_through_inline 1.22ns 822.95M
426 lambda_invoke_fn 1.22ns 822.88M
427 lambda_noop 0.00fs Infinity
428 lambda_local_var 182.49ps 5.48G
429 fn_ptr_invoke_through_template 1.22ns 822.95M
430 virtual_fn_invoke 1.22ns 822.98M
431 fn_ptr_create_invoke 1.22ns 822.94M
432 std_function_create_invoke 3.88ns 257.83M
433 Function_create_invoke 2.73ns 365.73M
434 mem_fn_create_invoke 1.22ns 822.98M
435 std_bind_create_invoke 18.91ns 52.89M
436 std_bind_direct_invoke 1.22ns 822.98M
437 scope_guard_std_function 7.24ns 138.14M
438 scope_guard_std_function_rvalue 6.44ns 155.23M
439 scope_guard_Function_rvalue 5.53ns 180.87M
440 scope_guard_fn_ptr 928.25ps 1.08G
441 scope_guard_lambda_noop 0.00fs Infinity
442 scope_guard_lambda_function 1.22ns 822.97M
443 scope_guard_lambda_local_var 101.27ps 9.87G
444 ----------------------------------------------------------------------------
445 throw_exception 1.90us 524.98K
446 catch_no_exception 1.22ns 822.98M
447 return_exc_ptr 1.39us 719.84K
448 exc_ptr_param_return 1.41us 711.08K
449 exc_ptr_param_return_null 1.82ns 548.61M
450 return_string 2.43ns 411.48M
451 return_string_noexcept 2.43ns 411.48M
452 return_code 1.22ns 822.98M
453 return_code_noexcept 943.51ps 1.06G
454 ----------------------------------------------------------------------------
455 std_function_create_move_invoke 48.74ns 20.52M
456 Function_create_move_invoke 50.21ns 19.92M
457 std_function_create_move_invoke_small 6.78ns 147.58M
458 Function_create_move_invoke_small 7.01ns 142.67M
459 std_function_create_move_invoke_ref 6.67ns 150.03M
460 Function_create_move_invoke_ref 6.88ns 145.35M
461 ----------------------------------------------------------------------------
462 function_ptr_move 1.21ns 823.05M
463 std_function_move_small 5.77ns 173.20M
464 Function_move_small 7.60ns 131.58M
465 std_function_move_small_trivial 5.77ns 173.27M
466 Function_move_small_trivial 5.47ns 182.86M
467 std_function_move_large 5.77ns 173.22M
468 Function_move_large 6.38ns 156.63M
469 ============================================================================
470  */
void BM_Function_invoke_impl(int iters, const folly::Function< void() const > &fn)
void BM_virtual_fn_invoke_impl(int iters, VirtualClass *vc)
int returnCode(int value)
PUSHMI_INLINE_VAR constexpr struct folly::pushmi::invoke_fn invoke
auto f
DECLARE_int32(bm_max_iters)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::string returnStringNoExcept() noexcept
void runBenchmarks()
Definition: Benchmark.cpp:456
char ** argv
void BM_fn_ptr_invoke_impl(int iters, void(*fn)())
std::exception_ptr returnExceptionPtr()
BENCHMARK_DRAW_LINE()
void doNothing()
BENCHMARK(fn_invoke, iters)
Definition: main.cpp:32
static bool tc
void exceptionPtrReturnParam(std::exception_ptr *excReturn)
char a
void doNothing()
std::string returnString()
void BM_fn_ptr_invoke_inlined_impl(int iters, void(*fn)())
int * count
FOLLY_NODISCARD detail::ScopeGuardImplDecay< F, true > makeGuard(F &&f) noexcept(noexcept(detail::ScopeGuardImplDecay< F, true >(static_cast< F && >(f))))
Definition: ScopeGuard.h:184
void BM_invoke_fn_template_impl(int iters, const T &fn)
int bind(NetworkSocket s, const sockaddr *name, socklen_t namelen)
Definition: NetOps.cpp:76
g_t g(f_t)
int main(int argc, char **argv)
Definition: main.cpp:18
int returnCodeNoExcept(int value) noexcept
void BM_mem_fn_invoke_impl(int iters, TestClass *tc, void(TestClass::*memfn)())
void BM_std_function_invoke_impl(int iters, const std::function< void()> &fn)
auto doNotOptimizeAway(const T &datum) -> typename std::enable_if< !detail::DoNotOptimizeAwayNeedsIndirect< T >::value >::type
Definition: Benchmark.h:258
FOLLY_NOINLINE FOLLY_COLD void throw_exception(Ex &&ex)
Definition: Exception.h:32