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();
 | |
| }
 |