[DebugInfo] Avoid re-ordering assignments in LCSSA
[llvm-project.git] / libcxx / benchmarks / algorithms.bench.cpp
blob93383e2b9cd6a518f4beec073b284f3c9d92198c
2 #include <algorithm>
3 #include <cstdint>
4 #include <map>
5 #include <random>
6 #include <string>
7 #include <utility>
8 #include <vector>
10 #include "CartesianBenchmarks.h"
11 #include "GenerateInput.h"
12 #include "benchmark/benchmark.h"
13 #include "test_macros.h"
15 namespace {
17 enum class ValueType { Uint32, Uint64, Pair, Tuple, String };
18 struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 5> {
19 static constexpr const char* Names[] = {
20 "uint32", "uint64", "pair<uint32, uint32>",
21 "tuple<uint32, uint64, uint32>", "string"};
24 template <class V>
25 using Value = std::conditional_t<
26 V() == ValueType::Uint32, uint32_t,
27 std::conditional_t<
28 V() == ValueType::Uint64, uint64_t,
29 std::conditional_t<
30 V() == ValueType::Pair, std::pair<uint32_t, uint32_t>,
31 std::conditional_t<V() == ValueType::Tuple,
32 std::tuple<uint32_t, uint64_t, uint32_t>,
33 std::string> > > >;
35 enum class Order {
36 Random,
37 Ascending,
38 Descending,
39 SingleElement,
40 PipeOrgan,
41 Heap
43 struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 6> {
44 static constexpr const char* Names[] = {"Random", "Ascending",
45 "Descending", "SingleElement",
46 "PipeOrgan", "Heap"};
49 template <typename T>
50 void fillValues(std::vector<T>& V, size_t N, Order O) {
51 if (O == Order::SingleElement) {
52 V.resize(N, 0);
53 } else {
54 while (V.size() < N)
55 V.push_back(V.size());
59 template <typename T>
60 void fillValues(std::vector<std::pair<T, T> >& V, size_t N, Order O) {
61 if (O == Order::SingleElement) {
62 V.resize(N, std::make_pair(0, 0));
63 } else {
64 while (V.size() < N)
65 // Half of array will have the same first element.
66 if (V.size() % 2) {
67 V.push_back(std::make_pair(V.size(), V.size()));
68 } else {
69 V.push_back(std::make_pair(0, V.size()));
74 template <typename T1, typename T2, typename T3>
75 void fillValues(std::vector<std::tuple<T1, T2, T3> >& V, size_t N, Order O) {
76 if (O == Order::SingleElement) {
77 V.resize(N, std::make_tuple(0, 0, 0));
78 } else {
79 while (V.size() < N)
80 // One third of array will have the same first element.
81 // One third of array will have the same first element and the same second element.
82 switch (V.size() % 3) {
83 case 0:
84 V.push_back(std::make_tuple(V.size(), V.size(), V.size()));
85 break;
86 case 1:
87 V.push_back(std::make_tuple(0, V.size(), V.size()));
88 break;
89 case 2:
90 V.push_back(std::make_tuple(0, 0, V.size()));
91 break;
96 void fillValues(std::vector<std::string>& V, size_t N, Order O) {
97 if (O == Order::SingleElement) {
98 V.resize(N, getRandomString(64));
99 } else {
100 while (V.size() < N)
101 V.push_back(getRandomString(64));
105 template <class T>
106 void sortValues(T& V, Order O) {
107 assert(std::is_sorted(V.begin(), V.end()));
108 switch (O) {
109 case Order::Random: {
110 std::random_device R;
111 std::mt19937 M(R());
112 std::shuffle(V.begin(), V.end(), M);
113 break;
115 case Order::Ascending:
116 std::sort(V.begin(), V.end());
117 break;
118 case Order::Descending:
119 std::sort(V.begin(), V.end(), std::greater<>());
120 break;
121 case Order::SingleElement:
122 // Nothing to do
123 break;
124 case Order::PipeOrgan:
125 std::sort(V.begin(), V.end());
126 std::reverse(V.begin() + V.size() / 2, V.end());
127 break;
128 case Order::Heap:
129 std::make_heap(V.begin(), V.end());
130 break;
134 constexpr size_t TestSetElements =
135 #if !TEST_HAS_FEATURE(memory_sanitizer)
136 1 << 18;
137 #else
138 1 << 14;
139 #endif
141 template <class ValueType>
142 std::vector<std::vector<Value<ValueType> > > makeOrderedValues(size_t N,
143 Order O) {
144 std::vector<std::vector<Value<ValueType> > > Ret;
145 const size_t NumCopies = std::max(size_t{1}, TestSetElements / N);
146 Ret.resize(NumCopies);
147 for (auto& V : Ret) {
148 fillValues(V, N, O);
149 sortValues(V, O);
151 return Ret;
154 template <class T, class U>
155 TEST_ALWAYS_INLINE void resetCopies(benchmark::State& state, T& Copies,
156 U& Orig) {
157 state.PauseTiming();
158 for (auto& Copy : Copies)
159 Copy = Orig;
160 state.ResumeTiming();
163 enum class BatchSize {
164 CountElements,
165 CountBatch,
168 template <class ValueType, class F>
169 void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O,
170 BatchSize Count, F Body) {
171 auto Copies = makeOrderedValues<ValueType>(Quantity, O);
172 auto Orig = Copies;
174 const size_t Batch = Count == BatchSize::CountElements
175 ? Copies.size() * Quantity
176 : Copies.size();
177 while (state.KeepRunningBatch(Batch)) {
178 for (auto& Copy : Copies) {
179 Body(Copy);
180 benchmark::DoNotOptimize(Copy);
182 state.PauseTiming();
183 Copies = Orig;
184 state.ResumeTiming();
188 template <class ValueType, class Order>
189 struct Sort {
190 size_t Quantity;
192 void run(benchmark::State& state) const {
193 runOpOnCopies<ValueType>(
194 state, Quantity, Order(), BatchSize::CountElements,
195 [](auto& Copy) { std::sort(Copy.begin(), Copy.end()); });
198 bool skip() const { return Order() == ::Order::Heap; }
200 std::string name() const {
201 return "BM_Sort" + ValueType::name() + Order::name() + "_" +
202 std::to_string(Quantity);
206 template <class ValueType, class Order>
207 struct StableSort {
208 size_t Quantity;
210 void run(benchmark::State& state) const {
211 runOpOnCopies<ValueType>(
212 state, Quantity, Order(), BatchSize::CountElements,
213 [](auto& Copy) { std::stable_sort(Copy.begin(), Copy.end()); });
216 bool skip() const { return Order() == ::Order::Heap; }
218 std::string name() const {
219 return "BM_StableSort" + ValueType::name() + Order::name() + "_" +
220 std::to_string(Quantity);
224 template <class ValueType, class Order>
225 struct MakeHeap {
226 size_t Quantity;
228 void run(benchmark::State& state) const {
229 runOpOnCopies<ValueType>(
230 state, Quantity, Order(), BatchSize::CountElements,
231 [](auto& Copy) { std::make_heap(Copy.begin(), Copy.end()); });
234 std::string name() const {
235 return "BM_MakeHeap" + ValueType::name() + Order::name() + "_" +
236 std::to_string(Quantity);
240 template <class ValueType>
241 struct SortHeap {
242 size_t Quantity;
244 void run(benchmark::State& state) const {
245 runOpOnCopies<ValueType>(
246 state, Quantity, Order::Heap, BatchSize::CountElements,
247 [](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); });
250 std::string name() const {
251 return "BM_SortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
255 template <class ValueType, class Order>
256 struct MakeThenSortHeap {
257 size_t Quantity;
259 void run(benchmark::State& state) const {
260 runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements,
261 [](auto& Copy) {
262 std::make_heap(Copy.begin(), Copy.end());
263 std::sort_heap(Copy.begin(), Copy.end());
267 std::string name() const {
268 return "BM_MakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
269 std::to_string(Quantity);
273 template <class ValueType, class Order>
274 struct PushHeap {
275 size_t Quantity;
277 void run(benchmark::State& state) const {
278 runOpOnCopies<ValueType>(
279 state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
280 for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
281 std::push_heap(Copy.begin(), I + 1);
286 bool skip() const { return Order() == ::Order::Heap; }
288 std::string name() const {
289 return "BM_PushHeap" + ValueType::name() + Order::name() + "_" +
290 std::to_string(Quantity);
294 template <class ValueType>
295 struct PopHeap {
296 size_t Quantity;
298 void run(benchmark::State& state) const {
299 runOpOnCopies<ValueType>(
300 state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
301 for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
302 std::pop_heap(B, I);
307 std::string name() const {
308 return "BM_PopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
312 } // namespace
314 int main(int argc, char** argv) {
315 benchmark::Initialize(&argc, argv);
316 if (benchmark::ReportUnrecognizedArguments(argc, argv))
317 return 1;
319 const std::vector<size_t> Quantities = {1 << 0, 1 << 2, 1 << 4, 1 << 6,
320 1 << 8, 1 << 10, 1 << 14,
321 // Running each benchmark in parallel consumes too much memory with MSAN
322 // and can lead to the test process being killed.
323 #if !TEST_HAS_FEATURE(memory_sanitizer)
324 1 << 18
325 #endif
327 makeCartesianProductBenchmark<Sort, AllValueTypes, AllOrders>(Quantities);
328 makeCartesianProductBenchmark<StableSort, AllValueTypes, AllOrders>(
329 Quantities);
330 makeCartesianProductBenchmark<MakeHeap, AllValueTypes, AllOrders>(Quantities);
331 makeCartesianProductBenchmark<SortHeap, AllValueTypes>(Quantities);
332 makeCartesianProductBenchmark<MakeThenSortHeap, AllValueTypes, AllOrders>(
333 Quantities);
334 makeCartesianProductBenchmark<PushHeap, AllValueTypes, AllOrders>(Quantities);
335 makeCartesianProductBenchmark<PopHeap, AllValueTypes>(Quantities);
336 benchmark::RunSpecifiedBenchmarks();