Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
[folly.git] / folly / test / function_benchmark / main.cpp
diff --git a/folly/test/function_benchmark/main.cpp b/folly/test/function_benchmark/main.cpp
new file mode 100644 (file)
index 0000000..33610c9
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2012 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "folly/test/function_benchmark/benchmark_impl.h"
+#include "folly/test/function_benchmark/test_functions.h"
+
+#include "folly/Benchmark.h"
+#include "folly/ScopeGuard.h"
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+
+using folly::ScopeGuard;
+using folly::makeGuard;
+
+// Declare the bm_max_iters flag from folly/Benchmark.cpp
+DECLARE_int32(bm_max_iters);
+
+// Directly invoking a function
+BENCHMARK(fn_invoke, iters) {
+  for (int n = 0; n < iters; ++n) {
+    doNothing();
+  }
+}
+
+// Invoking a function through a function pointer
+BENCHMARK(fn_ptr_invoke, iters) {
+  BM_fn_ptr_invoke_impl(iters, doNothing);
+}
+
+// Invoking a function through a std::function object
+BENCHMARK(std_function_invoke, iters) {
+  BM_std_function_invoke_impl(iters, doNothing);
+}
+
+// Invoking a member function through a member function pointer
+BENCHMARK(mem_fn_invoke, iters) {
+  TestClass tc;
+  BM_mem_fn_invoke_impl(iters, &tc, &TestClass::doNothing);
+}
+
+// Invoke a function pointer through an inlined wrapper function
+BENCHMARK(fn_ptr_invoke_through_inline, iters) {
+  BM_fn_ptr_invoke_inlined_impl(iters, doNothing);
+}
+
+// Invoke a lambda that calls doNothing() through an inlined wrapper function
+BENCHMARK(lambda_invoke_fn, iters) {
+  BM_invoke_fn_template_impl(iters, [] { doNothing(); });
+}
+
+// Invoke a lambda that does nothing
+BENCHMARK(lambda_noop, iters) {
+  BM_invoke_fn_template_impl(iters, [] {});
+}
+
+// Invoke a lambda that modifies a local variable
+BENCHMARK(lambda_local_var, iters) {
+  uint32_t count1 = 0;
+  uint32_t count2 = 0;
+  BM_invoke_fn_template_impl(iters, [&] {
+    // Do something slightly more complicated than just incrementing a
+    // variable.  Otherwise gcc is smart enough to optimize the loop away.
+    if (count1 & 0x1) {
+      ++count2;
+    }
+    ++count1;
+  });
+
+  // Use the values we computed, so gcc won't optimize the loop away
+  CHECK_EQ(iters, count1);
+  CHECK_EQ(iters / 2, count2);
+}
+
+// Invoke a function pointer through the same wrapper used for lambdas
+BENCHMARK(fn_ptr_invoke_through_template, iters) {
+  BM_invoke_fn_template_impl(iters, doNothing);
+}
+
+// Invoking a virtual method
+BENCHMARK(virtual_fn_invoke, iters) {
+  VirtualClass vc;
+  BM_virtual_fn_invoke_impl(iters, &vc);
+}
+
+// Creating a function pointer and invoking it
+BENCHMARK(fn_ptr_create_invoke, iters) {
+  for (int n = 0; n < iters; ++n) {
+    void (*fn)() = doNothing;
+    fn();
+  }
+}
+
+// Creating a std::function object from a function pointer, and invoking it
+BENCHMARK(std_function_create_invoke, iters) {
+  for (int n = 0; n < iters; ++n) {
+    std::function<void()> fn = doNothing;
+    fn();
+  }
+}
+
+// Creating a pointer-to-member and invoking it
+BENCHMARK(mem_fn_create_invoke, iters) {
+  TestClass tc;
+  for (int n = 0; n < iters; ++n) {
+    void (TestClass::*memfn)() = &TestClass::doNothing;
+    (tc.*memfn)();
+  }
+}
+
+// Using std::bind to create a std::function from a member function,
+// and invoking it
+BENCHMARK(std_bind_create_invoke, iters) {
+  TestClass tc;
+  for (int n = 0; n < iters; ++n) {
+    std::function<void()> fn = std::bind(&TestClass::doNothing, &tc);
+    fn();
+  }
+}
+
+// Using ScopeGuard to invoke a std::function
+BENCHMARK(scope_guard_std_function, iters) {
+  std::function<void()> fn(doNothing);
+  for (int n = 0; n < iters; ++n) {
+    ScopeGuard g = makeGuard(fn);
+  }
+}
+
+// Using ScopeGuard to invoke a std::function,
+// but create the ScopeGuard with an rvalue to a std::function
+BENCHMARK(scope_guard_std_function_rvalue, iters) {
+  for (int n = 0; n < iters; ++n) {
+    ScopeGuard g = makeGuard(std::function<void()>(doNothing));
+  }
+}
+
+// Using ScopeGuard to invoke a function pointer
+BENCHMARK(scope_guard_fn_ptr, iters) {
+  for (int n = 0; n < iters; ++n) {
+    ScopeGuard g = makeGuard(doNothing);
+  }
+}
+
+// Using ScopeGuard to invoke a lambda that does nothing
+BENCHMARK(scope_guard_lambda_noop, iters) {
+  for (int n = 0; n < iters; ++n) {
+    ScopeGuard g = makeGuard([] {});
+  }
+}
+
+// Using ScopeGuard to invoke a lambda that invokes a function
+BENCHMARK(scope_guard_lambda_function, iters) {
+  for (int n = 0; n < iters; ++n) {
+    ScopeGuard g = makeGuard([] { doNothing(); });
+  }
+}
+
+// Using ScopeGuard to invoke a lambda that modifies a local variable
+BENCHMARK(scope_guard_lambda_local_var, iters) {
+  uint32_t count = 0;
+  for (int n = 0; n < iters; ++n) {
+    ScopeGuard g = makeGuard([&] {
+      // Increment count if n is odd.  Without this conditional check
+      // (i.e., if we just increment count each time through the loop),
+      // gcc is smart enough to optimize the entire loop away, and just set
+      // count = iters.
+      if (n & 0x1) {
+        ++count;
+      }
+    });
+  }
+
+  // Check that the value of count is what we expect.
+  // This check is necessary: if we don't use count, gcc detects that count is
+  // unused and optimizes the entire loop away.
+  CHECK_EQ(iters / 2, count);
+}
+
+// main()
+
+int main(int argc, char** argv) {
+  google::ParseCommandLineFlags(&argc, &argv, true);
+  folly::runBenchmarks();
+}