forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			232 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// 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.hpp"
 | 
						|
#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();
 | 
						|
}
 |