function.bench.cpp 6.6 KB

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