228 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2010 11#include <cstdint>12#include <functional>13#include <memory>14#include <string>15#include <utility>16 17#include "CartesianBenchmarks.h"18#include "benchmark/benchmark.h"19#include "test_macros.h"20 21namespace {22 23enum class FunctionType {24 Null,25 FunctionPointer,26 MemberFunctionPointer,27 MemberPointer,28 SmallTrivialFunctor,29 SmallNonTrivialFunctor,30 LargeTrivialFunctor,31 LargeNonTrivialFunctor32};33 34struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {35 static constexpr const char* Names[] = {36 "Null",37 "FuncPtr",38 "MemFuncPtr",39 "MemPtr",40 "SmallTrivialFunctor",41 "SmallNonTrivialFunctor",42 "LargeTrivialFunctor",43 "LargeNonTrivialFunctor"};44};45 46enum class Opacity { kOpaque, kTransparent };47 48struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {49 static constexpr const char* Names[] = {"Opaque", "Transparent"};50};51 52struct S {53 int function() const { return 0; }54 int field = 0;55};56 57int FunctionWithS(const S*) { return 0; }58 59struct SmallTrivialFunctor {60 int operator()(const S*) const { return 0; }61};62struct SmallNonTrivialFunctor {63 SmallNonTrivialFunctor() {}64 SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}65 ~SmallNonTrivialFunctor() {}66 int operator()(const S*) const { return 0; }67};68struct LargeTrivialFunctor {69 LargeTrivialFunctor() {70 // Do not spend time initializing the padding.71 }72 int padding[16];73 int operator()(const S*) const { return 0; }74};75struct LargeNonTrivialFunctor {76 int padding[16];77 LargeNonTrivialFunctor() {78 // Do not spend time initializing the padding.79 }80 LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}81 ~LargeNonTrivialFunctor() {}82 int operator()(const S*) const { return 0; }83};84 85using Function = std::function<int(const S*)>;86 87TEST_ALWAYS_INLINE88inline Function MakeFunction(FunctionType type, bool opaque = false) {89 switch (type) {90 case FunctionType::Null:91 return nullptr;92 case FunctionType::FunctionPointer:93 return maybeOpaque(FunctionWithS, opaque);94 case FunctionType::MemberFunctionPointer:95 return maybeOpaque(&S::function, opaque);96 case FunctionType::MemberPointer:97 return maybeOpaque(&S::field, opaque);98 case FunctionType::SmallTrivialFunctor:99 return maybeOpaque(SmallTrivialFunctor{}, opaque);100 case FunctionType::SmallNonTrivialFunctor:101 return maybeOpaque(SmallNonTrivialFunctor{}, opaque);102 case FunctionType::LargeTrivialFunctor:103 return maybeOpaque(LargeTrivialFunctor{}, opaque);104 case FunctionType::LargeNonTrivialFunctor:105 return maybeOpaque(LargeNonTrivialFunctor{}, opaque);106 }107 std::unreachable();108}109 110template <class Opacity, class FunctionType>111struct ConstructAndDestroy {112 static void run(benchmark::State& state) {113 for (auto _ : state) {114 if (Opacity() == ::Opacity::kOpaque) {115 benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));116 } else {117 MakeFunction(FunctionType());118 }119 }120 }121 122 static std::string name() { return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name(); }123};124 125template <class FunctionType>126struct Copy {127 static void run(benchmark::State& state) {128 auto value = MakeFunction(FunctionType());129 for (auto _ : state) {130 benchmark::DoNotOptimize(value);131 auto copy = value; // NOLINT132 benchmark::DoNotOptimize(copy);133 }134 }135 136 static std::string name() { return "BM_Copy" + FunctionType::name(); }137};138 139template <class FunctionType>140struct Move {141 static void run(benchmark::State& state) {142 Function values[2] = {MakeFunction(FunctionType())};143 int i = 0;144 for (auto _ : state) {145 benchmark::DoNotOptimize(values);146 benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));147 i ^= 1;148 }149 }150 151 static std::string name() { return "BM_Move" + FunctionType::name(); }152};153 154template <class Function1, class Function2>155struct Swap {156 static void run(benchmark::State& state) {157 Function values[2] = {MakeFunction(Function1()), MakeFunction(Function2())};158 for (auto _ : state) {159 benchmark::DoNotOptimize(values);160 values[0].swap(values[1]);161 }162 }163 164 static bool skip() { return Function1() > Function2(); }165 166 static std::string name() { return "BM_Swap" + Function1::name() + Function2::name(); }167};168 169template <class FunctionType>170struct OperatorBool {171 static void run(benchmark::State& state) {172 auto f = MakeFunction(FunctionType());173 for (auto _ : state) {174 benchmark::DoNotOptimize(f);175 benchmark::DoNotOptimize(static_cast<bool>(f));176 }177 }178 179 static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }180};181 182template <class FunctionType>183struct Invoke {184 static void run(benchmark::State& state) {185 S s;186 auto value = MakeFunction(FunctionType());187 for (auto _ : state) {188 benchmark::DoNotOptimize(value);189 benchmark::DoNotOptimize(value(&s));190 }191 }192 193 static bool skip() { return FunctionType() == ::FunctionType::Null; }194 195 static std::string name() { return "BM_Invoke" + FunctionType::name(); }196};197 198template <class FunctionType>199struct InvokeInlined {200 static void run(benchmark::State& state) {201 S s;202 for (auto _ : state) {203 MakeFunction(FunctionType())(&s);204 }205 }206 207 static bool skip() { return FunctionType() == ::FunctionType::Null; }208 209 static std::string name() { return "BM_InvokeInlined" + FunctionType::name(); }210};211 212} // namespace213 214int main(int argc, char** argv) {215 benchmark::Initialize(&argc, argv);216 if (benchmark::ReportUnrecognizedArguments(argc, argv))217 return 1;218 219 makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity, AllFunctionTypes>();220 makeCartesianProductBenchmark<Copy, AllFunctionTypes>();221 makeCartesianProductBenchmark<Move, AllFunctionTypes>();222 makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();223 makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();224 makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();225 makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();226 benchmark::RunSpecifiedBenchmarks();227}228