diff libcxx/benchmarks/function.bench.cpp @ 150:1d019706d866

LLVM10
author anatofuz
date Thu, 13 Feb 2020 15:10:13 +0900
parents
children 1f2b6ac9f198
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcxx/benchmarks/function.bench.cpp	Thu Feb 13 15:10:13 2020 +0900
@@ -0,0 +1,231 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <string>
+
+#include "CartesianBenchmarks.h"
+#include "benchmark/benchmark.h"
+#include "test_macros.h"
+
+namespace {
+
+enum class FunctionType {
+  Null,
+  FunctionPointer,
+  MemberFunctionPointer,
+  MemberPointer,
+  SmallTrivialFunctor,
+  SmallNonTrivialFunctor,
+  LargeTrivialFunctor,
+  LargeNonTrivialFunctor
+};
+
+struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {
+  static constexpr const char* Names[] = {"Null",
+                                          "FuncPtr",
+                                          "MemFuncPtr",
+                                          "MemPtr",
+                                          "SmallTrivialFunctor",
+                                          "SmallNonTrivialFunctor",
+                                          "LargeTrivialFunctor",
+                                          "LargeNonTrivialFunctor"};
+};
+
+enum class Opacity { kOpaque, kTransparent };
+
+struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
+  static constexpr const char* Names[] = {"Opaque", "Transparent"};
+};
+
+struct S {
+  int function() const { return 0; }
+  int field = 0;
+};
+
+int FunctionWithS(const S*) { return 0; }
+
+struct SmallTrivialFunctor {
+  int operator()(const S*) const { return 0; }
+};
+struct SmallNonTrivialFunctor {
+  SmallNonTrivialFunctor() {}
+  SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}
+  ~SmallNonTrivialFunctor() {}
+  int operator()(const S*) const { return 0; }
+};
+struct LargeTrivialFunctor {
+  LargeTrivialFunctor() {
+      // Do not spend time initializing the padding.
+  }
+  int padding[16];
+  int operator()(const S*) const { return 0; }
+};
+struct LargeNonTrivialFunctor {
+  int padding[16];
+  LargeNonTrivialFunctor() {
+      // Do not spend time initializing the padding.
+  }
+  LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}
+  ~LargeNonTrivialFunctor() {}
+  int operator()(const S*) const { return 0; }
+};
+
+using Function = std::function<int(const S*)>;
+
+TEST_ALWAYS_INLINE
+inline Function MakeFunction(FunctionType type, bool opaque = false) {
+  switch (type) {
+    case FunctionType::Null:
+      return nullptr;
+    case FunctionType::FunctionPointer:
+      return maybeOpaque(FunctionWithS, opaque);
+    case FunctionType::MemberFunctionPointer:
+      return maybeOpaque(&S::function, opaque);
+    case FunctionType::MemberPointer:
+      return maybeOpaque(&S::field, opaque);
+    case FunctionType::SmallTrivialFunctor:
+      return maybeOpaque(SmallTrivialFunctor{}, opaque);
+    case FunctionType::SmallNonTrivialFunctor:
+      return maybeOpaque(SmallNonTrivialFunctor{}, opaque);
+    case FunctionType::LargeTrivialFunctor:
+      return maybeOpaque(LargeTrivialFunctor{}, opaque);
+    case FunctionType::LargeNonTrivialFunctor:
+      return maybeOpaque(LargeNonTrivialFunctor{}, opaque);
+  }
+}
+
+template <class Opacity, class FunctionType>
+struct ConstructAndDestroy {
+  static void run(benchmark::State& state) {
+    for (auto _ : state) {
+      if (Opacity() == ::Opacity::kOpaque) {
+        benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
+      } else {
+        MakeFunction(FunctionType());
+      }
+    }
+  }
+
+  static std::string name() {
+    return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name();
+  }
+};
+
+template <class FunctionType>
+struct Copy {
+  static void run(benchmark::State& state) {
+    auto value = MakeFunction(FunctionType());
+    for (auto _ : state) {
+      benchmark::DoNotOptimize(value);
+      auto copy = value;  // NOLINT
+      benchmark::DoNotOptimize(copy);
+    }
+  }
+
+  static std::string name() { return "BM_Copy" + FunctionType::name(); }
+};
+
+template <class FunctionType>
+struct Move {
+  static void run(benchmark::State& state) {
+    Function values[2] = {MakeFunction(FunctionType())};
+    int i = 0;
+    for (auto _ : state) {
+      benchmark::DoNotOptimize(values);
+      benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));
+      i ^= 1;
+    }
+  }
+
+  static std::string name() {
+    return "BM_Move" + FunctionType::name();
+  }
+};
+
+template <class Function1, class Function2>
+struct Swap {
+  static void run(benchmark::State& state) {
+    Function values[2] = {MakeFunction(Function1()), MakeFunction(Function2())};
+    for (auto _ : state) {
+      benchmark::DoNotOptimize(values);
+      values[0].swap(values[1]);
+    }
+  }
+
+  static bool skip() { return Function1() > Function2(); }
+
+  static std::string name() {
+    return "BM_Swap" + Function1::name() + Function2::name();
+  }
+};
+
+template <class FunctionType>
+struct OperatorBool {
+  static void run(benchmark::State& state) {
+    auto f = MakeFunction(FunctionType());
+    for (auto _ : state) {
+      benchmark::DoNotOptimize(f);
+      benchmark::DoNotOptimize(static_cast<bool>(f));
+    }
+  }
+
+  static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }
+};
+
+template <class FunctionType>
+struct Invoke {
+  static void run(benchmark::State& state) {
+    S s;
+    const auto value = MakeFunction(FunctionType());
+    for (auto _ : state) {
+      benchmark::DoNotOptimize(value);
+      benchmark::DoNotOptimize(value(&s));
+    }
+  }
+
+  static bool skip() { return FunctionType() == ::FunctionType::Null; }
+
+  static std::string name() { return "BM_Invoke" + FunctionType::name(); }
+};
+
+template <class FunctionType>
+struct InvokeInlined {
+  static void run(benchmark::State& state) {
+    S s;
+    for (auto _ : state) {
+      MakeFunction(FunctionType())(&s);
+    }
+  }
+
+  static bool skip() { return FunctionType() == ::FunctionType::Null; }
+
+  static std::string name() {
+    return "BM_InvokeInlined" + FunctionType::name();
+  }
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  benchmark::Initialize(&argc, argv);
+  if (benchmark::ReportUnrecognizedArguments(argc, argv))
+    return 1;
+
+  makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity,
+                                AllFunctionTypes>();
+  makeCartesianProductBenchmark<Copy, AllFunctionTypes>();
+  makeCartesianProductBenchmark<Move, AllFunctionTypes>();
+  makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();
+  makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();
+  makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();
+  makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();
+  benchmark::RunSpecifiedBenchmarks();
+}