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