2 * Copyright 2017 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::ScopeGuard;
27 using folly::makeGuard;
29 // Declare the bm_max_iters flag from folly/Benchmark.cpp
30 DECLARE_int32(bm_max_iters);
32 // Directly invoking a function
33 BENCHMARK(fn_invoke, iters) {
34 for (size_t n = 0; n < iters; ++n) {
39 // Invoking a function through a function pointer
40 BENCHMARK(fn_ptr_invoke, iters) {
41 BM_fn_ptr_invoke_impl(iters, doNothing);
44 // Invoking a function through a std::function object
45 BENCHMARK(std_function_invoke, iters) {
46 BM_std_function_invoke_impl(iters, doNothing);
49 // Invoking a function through a folly::Function object
50 BENCHMARK(Function_invoke, iters) {
51 BM_Function_invoke_impl(iters, doNothing);
54 // Invoking a member function through a member function pointer
55 BENCHMARK(mem_fn_invoke, iters) {
57 BM_mem_fn_invoke_impl(iters, &tc, &TestClass::doNothing);
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);
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(); });
70 // Invoke a lambda that does nothing
71 BENCHMARK(lambda_noop, iters) {
72 BM_invoke_fn_template_impl(iters, [] {});
75 // Invoke a lambda that modifies a local variable
76 BENCHMARK(lambda_local_var, iters) {
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.
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);
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);
98 // Invoking a virtual method
99 BENCHMARK(virtual_fn_invoke, iters) {
101 BM_virtual_fn_invoke_impl(iters, &vc);
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;
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;
120 // Creating a folly::Function object from a function pointer, and
122 BENCHMARK(Function_create_invoke, iters) {
123 for (size_t n = 0; n < iters; ++n) {
124 folly::Function<void()> fn = doNothing;
129 // Creating a pointer-to-member and invoking it
130 BENCHMARK(mem_fn_create_invoke, iters) {
132 for (size_t n = 0; n < iters; ++n) {
133 void (TestClass::*memfn)() = &TestClass::doNothing;
138 // Using std::bind to create a std::function from a member function,
140 BENCHMARK(std_bind_create_invoke, iters) {
142 for (size_t n = 0; n < iters; ++n) {
143 std::function<void()> fn = std::bind(&TestClass::doNothing, &tc);
148 // Using std::bind directly to invoke a member function
149 BENCHMARK(std_bind_direct_invoke, iters) {
151 for (size_t n = 0; n < iters; ++n) {
152 auto fn = std::bind(&TestClass::doNothing, &tc);
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);
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));
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));
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);
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([] {});
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(); });
208 // Using ScopeGuard to invoke a lambda that modifies a local variable
209 BENCHMARK(scope_guard_lambda_local_var, iters) {
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
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);
230 BENCHMARK_DRAW_LINE()
232 BENCHMARK(throw_exception, iters) {
233 for (size_t n = 0; n < iters; ++n) {
236 } catch (const std::exception& ex) {
241 BENCHMARK(catch_no_exception, iters) {
242 for (size_t n = 0; n < iters; ++n) {
245 } catch (const std::exception& ex) {
250 BENCHMARK(return_exc_ptr, iters) {
251 for (size_t n = 0; n < iters; ++n) {
252 returnExceptionPtr();
256 BENCHMARK(exc_ptr_param_return, iters) {
257 for (size_t n = 0; n < iters; ++n) {
258 std::exception_ptr ex;
259 exceptionPtrReturnParam(&ex);
263 BENCHMARK(exc_ptr_param_return_null, iters) {
264 for (size_t n = 0; n < iters; ++n) {
265 exceptionPtrReturnParam(nullptr);
269 BENCHMARK(return_string, iters) {
270 for (size_t n = 0; n < iters; ++n) {
275 BENCHMARK(return_string_noexcept, iters) {
276 for (size_t n = 0; n < iters; ++n) {
277 returnStringNoExcept();
281 BENCHMARK(return_code, iters) {
282 for (size_t n = 0; n < iters; ++n) {
287 BENCHMARK(return_code_noexcept, iters) {
288 for (size_t n = 0; n < iters; ++n) {
289 returnCodeNoExcept(false);
293 BENCHMARK_DRAW_LINE()
295 BENCHMARK(std_function_create_move_invoke, iters) {
297 for (size_t i = 0; i < iters; ++i) {
298 std::function<void()> f(a);
299 invoke(std::move(f));
303 BENCHMARK(Function_create_move_invoke, iters) {
305 for (size_t i = 0; i < iters; ++i) {
306 folly::Function<void()> f(a);
307 invoke(std::move(f));
311 BENCHMARK(std_function_create_move_invoke_ref, iters) {
313 for (size_t i = 0; i < iters; ++i) {
314 std::function<void()> f(std::ref(a));
315 invoke(std::move(f));
319 BENCHMARK(Function_create_move_invoke_ref, iters) {
321 for (size_t i = 0; i < iters; ++i) {
322 folly::Function<void()> f(std::ref(a));
323 invoke(std::move(f));
329 int main(int argc, char** argv) {
330 gflags::ParseCommandLineFlags(&argc, &argv, true);
331 folly::runBenchmarks();