ordered_set.bench.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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 <algorithm>
  9. #include <cstdint>
  10. #include <memory>
  11. #include <random>
  12. #include <set>
  13. #include <string>
  14. #include <vector>
  15. #include "CartesianBenchmarks.h"
  16. #include "benchmark/benchmark.h"
  17. #include "test_macros.h"
  18. namespace {
  19. enum class HitType { Hit, Miss };
  20. struct AllHitTypes : EnumValuesAsTuple<AllHitTypes, HitType, 2> {
  21. static constexpr const char* Names[] = {"Hit", "Miss"};
  22. };
  23. enum class AccessPattern { Ordered, Random };
  24. struct AllAccessPattern
  25. : EnumValuesAsTuple<AllAccessPattern, AccessPattern, 2> {
  26. static constexpr const char* Names[] = {"Ordered", "Random"};
  27. };
  28. void sortKeysBy(std::vector<uint64_t>& Keys, AccessPattern AP) {
  29. if (AP == AccessPattern::Random) {
  30. std::random_device R;
  31. std::mt19937 M(R());
  32. std::shuffle(std::begin(Keys), std::end(Keys), M);
  33. }
  34. }
  35. struct TestSets {
  36. std::vector<std::set<uint64_t> > Sets;
  37. std::vector<uint64_t> Keys;
  38. };
  39. TestSets makeTestingSets(size_t TableSize, size_t NumTables, HitType Hit,
  40. AccessPattern Access) {
  41. TestSets R;
  42. R.Sets.resize(1);
  43. for (uint64_t I = 0; I < TableSize; ++I) {
  44. R.Sets[0].insert(2 * I);
  45. R.Keys.push_back(Hit == HitType::Hit ? 2 * I : 2 * I + 1);
  46. }
  47. R.Sets.resize(NumTables, R.Sets[0]);
  48. sortKeysBy(R.Keys, Access);
  49. return R;
  50. }
  51. struct Base {
  52. size_t TableSize;
  53. size_t NumTables;
  54. Base(size_t T, size_t N) : TableSize(T), NumTables(N) {}
  55. bool skip() const {
  56. size_t Total = TableSize * NumTables;
  57. return Total < 100 || Total > 1000000;
  58. }
  59. std::string baseName() const {
  60. return "_TableSize" + std::to_string(TableSize) + "_NumTables" +
  61. std::to_string(NumTables);
  62. }
  63. };
  64. template <class Access>
  65. struct Create : Base {
  66. using Base::Base;
  67. void run(benchmark::State& State) const {
  68. std::vector<uint64_t> Keys(TableSize);
  69. std::iota(Keys.begin(), Keys.end(), uint64_t{0});
  70. sortKeysBy(Keys, Access());
  71. while (State.KeepRunningBatch(TableSize * NumTables)) {
  72. std::vector<std::set<uint64_t>> Sets(NumTables);
  73. for (auto K : Keys) {
  74. for (auto& Set : Sets) {
  75. benchmark::DoNotOptimize(Set.insert(K));
  76. }
  77. }
  78. }
  79. }
  80. std::string name() const {
  81. return "BM_Create" + Access::name() + baseName();
  82. }
  83. };
  84. template <class Hit, class Access>
  85. struct Find : Base {
  86. using Base::Base;
  87. void run(benchmark::State& State) const {
  88. auto Data = makeTestingSets(TableSize, NumTables, Hit(), Access());
  89. while (State.KeepRunningBatch(TableSize * NumTables)) {
  90. for (auto K : Data.Keys) {
  91. for (auto& Set : Data.Sets) {
  92. benchmark::DoNotOptimize(Set.find(K));
  93. }
  94. }
  95. }
  96. }
  97. std::string name() const {
  98. return "BM_Find" + Hit::name() + Access::name() + baseName();
  99. }
  100. };
  101. template <class Hit, class Access>
  102. struct FindNeEnd : Base {
  103. using Base::Base;
  104. void run(benchmark::State& State) const {
  105. auto Data = makeTestingSets(TableSize, NumTables, Hit(), Access());
  106. while (State.KeepRunningBatch(TableSize * NumTables)) {
  107. for (auto K : Data.Keys) {
  108. for (auto& Set : Data.Sets) {
  109. benchmark::DoNotOptimize(Set.find(K) != Set.end());
  110. }
  111. }
  112. }
  113. }
  114. std::string name() const {
  115. return "BM_FindNeEnd" + Hit::name() + Access::name() + baseName();
  116. }
  117. };
  118. template <class Access>
  119. struct InsertHit : Base {
  120. using Base::Base;
  121. void run(benchmark::State& State) const {
  122. auto Data = makeTestingSets(TableSize, NumTables, HitType::Hit, Access());
  123. while (State.KeepRunningBatch(TableSize * NumTables)) {
  124. for (auto K : Data.Keys) {
  125. for (auto& Set : Data.Sets) {
  126. benchmark::DoNotOptimize(Set.insert(K));
  127. }
  128. }
  129. }
  130. }
  131. std::string name() const {
  132. return "BM_InsertHit" + Access::name() + baseName();
  133. }
  134. };
  135. template <class Access>
  136. struct InsertMissAndErase : Base {
  137. using Base::Base;
  138. void run(benchmark::State& State) const {
  139. auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss, Access());
  140. while (State.KeepRunningBatch(TableSize * NumTables)) {
  141. for (auto K : Data.Keys) {
  142. for (auto& Set : Data.Sets) {
  143. benchmark::DoNotOptimize(Set.erase(Set.insert(K).first));
  144. }
  145. }
  146. }
  147. }
  148. std::string name() const {
  149. return "BM_InsertMissAndErase" + Access::name() + baseName();
  150. }
  151. };
  152. struct IterateRangeFor : Base {
  153. using Base::Base;
  154. void run(benchmark::State& State) const {
  155. auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss,
  156. AccessPattern::Ordered);
  157. while (State.KeepRunningBatch(TableSize * NumTables)) {
  158. for (auto& Set : Data.Sets) {
  159. for (auto& V : Set) {
  160. benchmark::DoNotOptimize(V);
  161. }
  162. }
  163. }
  164. }
  165. std::string name() const { return "BM_IterateRangeFor" + baseName(); }
  166. };
  167. struct IterateBeginEnd : Base {
  168. using Base::Base;
  169. void run(benchmark::State& State) const {
  170. auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss,
  171. AccessPattern::Ordered);
  172. while (State.KeepRunningBatch(TableSize * NumTables)) {
  173. for (auto& Set : Data.Sets) {
  174. for (auto it = Set.begin(); it != Set.end(); ++it) {
  175. benchmark::DoNotOptimize(*it);
  176. }
  177. }
  178. }
  179. }
  180. std::string name() const { return "BM_IterateBeginEnd" + baseName(); }
  181. };
  182. } // namespace
  183. int main(int argc, char** argv) {
  184. benchmark::Initialize(&argc, argv);
  185. if (benchmark::ReportUnrecognizedArguments(argc, argv))
  186. return 1;
  187. const std::vector<size_t> TableSize{1, 10, 100, 1000, 10000, 100000, 1000000};
  188. const std::vector<size_t> NumTables{1, 10, 100, 1000, 10000, 100000, 1000000};
  189. makeCartesianProductBenchmark<Create, AllAccessPattern>(TableSize, NumTables);
  190. makeCartesianProductBenchmark<Find, AllHitTypes, AllAccessPattern>(
  191. TableSize, NumTables);
  192. makeCartesianProductBenchmark<FindNeEnd, AllHitTypes, AllAccessPattern>(
  193. TableSize, NumTables);
  194. makeCartesianProductBenchmark<InsertHit, AllAccessPattern>(
  195. TableSize, NumTables);
  196. makeCartesianProductBenchmark<InsertMissAndErase, AllAccessPattern>(
  197. TableSize, NumTables);
  198. makeCartesianProductBenchmark<IterateRangeFor>(TableSize, NumTables);
  199. makeCartesianProductBenchmark<IterateBeginEnd>(TableSize, NumTables);
  200. benchmark::RunSpecifiedBenchmarks();
  201. }