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