2 * Copyright 2011-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/test/function_benchmark/benchmark_impl.h>
18 #include <folly/test/function_benchmark/test_functions.h>
20 #include <glog/logging.h>
22 #include <folly/Benchmark.h>
23 #include <folly/ScopeGuard.h>
24 #include <folly/portability/GFlags.h>
26 using folly::makeGuard;
28 // Declare the bm_max_iters flag from folly/Benchmark.cpp
29 DECLARE_int32(bm_max_iters);
31 // Directly invoking a function
32 BENCHMARK(fn_invoke, iters) {
33 for (size_t n = 0; n < iters; ++n) {
38 // Invoking a function through a function pointer
39 BENCHMARK(fn_ptr_invoke, iters) {
40 BM_fn_ptr_invoke_impl(iters, doNothing);
43 // Invoking a function through a std::function object
44 BENCHMARK(std_function_invoke, iters) {
45 BM_std_function_invoke_impl(iters, doNothing);
48 // Invoking a function through a folly::Function object
49 BENCHMARK(Function_invoke, iters) {
50 BM_Function_invoke_impl(iters, doNothing);
53 // Invoking a member function through a member function pointer
54 BENCHMARK(mem_fn_invoke, iters) {
56 BM_mem_fn_invoke_impl(iters, &tc, &TestClass::doNothing);
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);
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(); });
69 // Invoke a lambda that does nothing
70 BENCHMARK(lambda_noop, iters) {
71 BM_invoke_fn_template_impl(iters, [] {});
74 // Invoke a lambda that modifies a local variable
75 BENCHMARK(lambda_local_var, iters) {
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.
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);
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);
97 // Invoking a virtual method
98 BENCHMARK(virtual_fn_invoke, iters) {
100 BM_virtual_fn_invoke_impl(iters, &vc);
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;
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;
119 // Creating a folly::Function object from a function pointer, and
121 BENCHMARK(Function_create_invoke, iters) {
122 for (size_t n = 0; n < iters; ++n) {
123 folly::Function<void()> fn = doNothing;
128 // Creating a pointer-to-member and invoking it
129 BENCHMARK(mem_fn_create_invoke, iters) {
131 for (size_t n = 0; n < iters; ++n) {
132 void (TestClass::*memfn)() = &TestClass::doNothing;
137 // Using std::bind to create a std::function from a member function,
139 BENCHMARK(std_bind_create_invoke, iters) {
141 for (size_t n = 0; n < iters; ++n) {
142 std::function<void()> fn = std::bind(&TestClass::doNothing, &tc);
147 // Using std::bind directly to invoke a member function
148 BENCHMARK(std_bind_direct_invoke, iters) {
150 for (size_t n = 0; n < iters; ++n) {
151 auto fn = std::bind(&TestClass::doNothing, &tc);
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);
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));
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));
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);
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([] {});
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(); });
207 // Using ScopeGuard to invoke a lambda that modifies a local variable
208 BENCHMARK(scope_guard_lambda_local_var, iters) {
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
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);
229 BENCHMARK_DRAW_LINE()
231 BENCHMARK(throw_exception, iters) {
232 for (size_t n = 0; n < iters; ++n) {
235 } catch (const std::exception& ex) {
240 BENCHMARK(catch_no_exception, iters) {
241 for (size_t n = 0; n < iters; ++n) {
244 } catch (const std::exception& ex) {
249 BENCHMARK(return_exc_ptr, iters) {
250 for (size_t n = 0; n < iters; ++n) {
251 returnExceptionPtr();
255 BENCHMARK(exc_ptr_param_return, iters) {
256 for (size_t n = 0; n < iters; ++n) {
257 std::exception_ptr ex;
258 exceptionPtrReturnParam(&ex);
262 BENCHMARK(exc_ptr_param_return_null, iters) {
263 for (size_t n = 0; n < iters; ++n) {
264 exceptionPtrReturnParam(nullptr);
268 BENCHMARK(return_string, iters) {
269 for (size_t n = 0; n < iters; ++n) {
274 BENCHMARK(return_string_noexcept, iters) {
275 for (size_t n = 0; n < iters; ++n) {
276 returnStringNoExcept();
280 BENCHMARK(return_code, iters) {
281 for (size_t n = 0; n < iters; ++n) {
286 BENCHMARK(return_code_noexcept, iters) {
287 for (size_t n = 0; n < iters; ++n) {
288 returnCodeNoExcept(false);
292 BENCHMARK_DRAW_LINE()
294 BENCHMARK(std_function_create_move_invoke, iters) {
296 for (size_t i = 0; i < iters; ++i) {
297 std::function<void()> f(a);
298 invoke(std::move(f));
302 BENCHMARK(Function_create_move_invoke, iters) {
304 for (size_t i = 0; i < iters; ++i) {
305 folly::Function<void()> f(a);
306 invoke(std::move(f));
310 BENCHMARK(std_function_create_move_invoke_ref, iters) {
312 for (size_t i = 0; i < iters; ++i) {
313 std::function<void()> f(std::ref(a));
314 invoke(std::move(f));
318 BENCHMARK(Function_create_move_invoke_ref, iters) {
320 for (size_t i = 0; i < iters; ++i) {
321 folly::Function<void()> f(std::ref(a));
322 invoke(std::move(f));
328 int main(int argc, char** argv) {
329 gflags::ParseCommandLineFlags(&argc, &argv, true);
330 folly::runBenchmarks();