blob: 93383e2b9cd6a518f4beec073b284f3c9d92198c [file] [log] [blame]
Samuel Benzaquen8e11d692018-11-20 17:15:17 +00001
2#include <algorithm>
Eric Fiselier9e3e1372016-07-19 23:07:03 +00003#include <cstdint>
Samuel Benzaquen8e11d692018-11-20 17:15:17 +00004#include <map>
5#include <random>
6#include <string>
7#include <utility>
8#include <vector>
Eric Fiselier9e3e1372016-07-19 23:07:03 +00009
Nico Weberfa647f82019-08-21 01:59:12 +000010#include "CartesianBenchmarks.h"
11#include "GenerateInput.h"
Samuel Benzaquen8e11d692018-11-20 17:15:17 +000012#include "benchmark/benchmark.h"
13#include "test_macros.h"
Eric Fiselier9e3e1372016-07-19 23:07:03 +000014
Samuel Benzaquen8e11d692018-11-20 17:15:17 +000015namespace {
Eric Fiselier9e3e1372016-07-19 23:07:03 +000016
MinJae Hwanga79586c2020-07-06 18:29:38 -040017enum class ValueType { Uint32, Uint64, Pair, Tuple, String };
18struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 5> {
19 static constexpr const char* Names[] = {
20 "uint32", "uint64", "pair<uint32, uint32>",
21 "tuple<uint32, uint64, uint32>", "string"};
Samuel Benzaquen8e11d692018-11-20 17:15:17 +000022};
23
24template <class V>
MinJae Hwanga79586c2020-07-06 18:29:38 -040025using 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> > > >;
Samuel Benzaquen8e11d692018-11-20 17:15:17 +000034
35enum class Order {
36 Random,
37 Ascending,
38 Descending,
39 SingleElement,
40 PipeOrgan,
41 Heap
42};
43struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 6> {
44 static constexpr const char* Names[] = {"Random", "Ascending",
45 "Descending", "SingleElement",
46 "PipeOrgan", "Heap"};
47};
48
MinJae Hwanga79586c2020-07-06 18:29:38 -040049template <typename T>
50void fillValues(std::vector<T>& V, size_t N, Order O) {
Samuel Benzaquen8e11d692018-11-20 17:15:17 +000051 if (O == Order::SingleElement) {
52 V.resize(N, 0);
53 } else {
54 while (V.size() < N)
55 V.push_back(V.size());
56 }
Eric Fiselier9e3e1372016-07-19 23:07:03 +000057}
58
MinJae Hwanga79586c2020-07-06 18:29:38 -040059template <typename T>
60void fillValues(std::vector<std::pair<T, T> >& V, size_t N, Order O) {
Samuel Benzaquen8e11d692018-11-20 17:15:17 +000061 if (O == Order::SingleElement) {
MinJae Hwanga79586c2020-07-06 18:29:38 -040062 V.resize(N, std::make_pair(0, 0));
Samuel Benzaquen8e11d692018-11-20 17:15:17 +000063 } else {
64 while (V.size() < N)
MinJae Hwanga79586c2020-07-06 18:29:38 -040065 // 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()));
70 }
71 }
72}
73
74template <typename T1, typename T2, typename T3>
75void 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;
92 }
93 }
94}
95
96void 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));
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000102 }
103}
Eric Fiselier9e3e1372016-07-19 23:07:03 +0000104
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000105template <class T>
106void 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;
114 }
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;
131 }
132}
Eric Fiselier9e3e1372016-07-19 23:07:03 +0000133
MinJae Hwanga79586c2020-07-06 18:29:38 -0400134constexpr size_t TestSetElements =
135#if !TEST_HAS_FEATURE(memory_sanitizer)
136 1 << 18;
137#else
138 1 << 14;
139#endif
140
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000141template <class ValueType>
142std::vector<std::vector<Value<ValueType> > > makeOrderedValues(size_t N,
143 Order O) {
MinJae Hwanga79586c2020-07-06 18:29:38 -0400144 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);
150 }
151 return Ret;
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000152}
Eric Fiselier9e3e1372016-07-19 23:07:03 +0000153
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000154template <class T, class U>
155TEST_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();
161}
Eric Fiselier9e3e1372016-07-19 23:07:03 +0000162
MinJae Hwanga79586c2020-07-06 18:29:38 -0400163enum class BatchSize {
164 CountElements,
165 CountBatch,
166};
167
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000168template <class ValueType, class F>
169void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O,
MinJae Hwanga79586c2020-07-06 18:29:38 -0400170 BatchSize Count, F Body) {
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000171 auto Copies = makeOrderedValues<ValueType>(Quantity, O);
MinJae Hwanga79586c2020-07-06 18:29:38 -0400172 auto Orig = Copies;
Eric Fiselier9e3e1372016-07-19 23:07:03 +0000173
MinJae Hwanga79586c2020-07-06 18:29:38 -0400174 const size_t Batch = Count == BatchSize::CountElements
175 ? Copies.size() * Quantity
176 : Copies.size();
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000177 while (state.KeepRunningBatch(Batch)) {
178 for (auto& Copy : Copies) {
MinJae Hwanga79586c2020-07-06 18:29:38 -0400179 Body(Copy);
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000180 benchmark::DoNotOptimize(Copy);
181 }
MinJae Hwanga79586c2020-07-06 18:29:38 -0400182 state.PauseTiming();
183 Copies = Orig;
184 state.ResumeTiming();
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000185 }
186}
Eric Fiselier9e3e1372016-07-19 23:07:03 +0000187
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000188template <class ValueType, class Order>
189struct Sort {
190 size_t Quantity;
Eric Fiselier9e3e1372016-07-19 23:07:03 +0000191
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000192 void run(benchmark::State& state) const {
MinJae Hwanga79586c2020-07-06 18:29:38 -0400193 runOpOnCopies<ValueType>(
194 state, Quantity, Order(), BatchSize::CountElements,
195 [](auto& Copy) { std::sort(Copy.begin(), Copy.end()); });
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000196 }
Eric Fiselier9e3e1372016-07-19 23:07:03 +0000197
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000198 bool skip() const { return Order() == ::Order::Heap; }
199
200 std::string name() const {
201 return "BM_Sort" + ValueType::name() + Order::name() + "_" +
202 std::to_string(Quantity);
203 };
204};
205
206template <class ValueType, class Order>
207struct StableSort {
208 size_t Quantity;
209
210 void run(benchmark::State& state) const {
MinJae Hwanga79586c2020-07-06 18:29:38 -0400211 runOpOnCopies<ValueType>(
212 state, Quantity, Order(), BatchSize::CountElements,
213 [](auto& Copy) { std::stable_sort(Copy.begin(), Copy.end()); });
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000214 }
215
216 bool skip() const { return Order() == ::Order::Heap; }
217
218 std::string name() const {
219 return "BM_StableSort" + ValueType::name() + Order::name() + "_" +
220 std::to_string(Quantity);
221 };
222};
223
224template <class ValueType, class Order>
225struct MakeHeap {
226 size_t Quantity;
227
228 void run(benchmark::State& state) const {
MinJae Hwanga79586c2020-07-06 18:29:38 -0400229 runOpOnCopies<ValueType>(
230 state, Quantity, Order(), BatchSize::CountElements,
231 [](auto& Copy) { std::make_heap(Copy.begin(), Copy.end()); });
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000232 }
233
234 std::string name() const {
235 return "BM_MakeHeap" + ValueType::name() + Order::name() + "_" +
236 std::to_string(Quantity);
237 };
238};
239
240template <class ValueType>
241struct SortHeap {
242 size_t Quantity;
243
244 void run(benchmark::State& state) const {
245 runOpOnCopies<ValueType>(
MinJae Hwanga79586c2020-07-06 18:29:38 -0400246 state, Quantity, Order::Heap, BatchSize::CountElements,
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000247 [](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); });
248 }
249
250 std::string name() const {
251 return "BM_SortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
252 };
253};
254
255template <class ValueType, class Order>
256struct MakeThenSortHeap {
257 size_t Quantity;
258
259 void run(benchmark::State& state) const {
MinJae Hwanga79586c2020-07-06 18:29:38 -0400260 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());
264 });
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000265 }
266
267 std::string name() const {
268 return "BM_MakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
269 std::to_string(Quantity);
270 };
271};
272
273template <class ValueType, class Order>
274struct PushHeap {
275 size_t Quantity;
276
277 void run(benchmark::State& state) const {
MinJae Hwanga79586c2020-07-06 18:29:38 -0400278 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);
282 }
283 });
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000284 }
285
286 bool skip() const { return Order() == ::Order::Heap; }
287
288 std::string name() const {
289 return "BM_PushHeap" + ValueType::name() + Order::name() + "_" +
290 std::to_string(Quantity);
291 };
292};
293
294template <class ValueType>
295struct PopHeap {
296 size_t Quantity;
297
298 void run(benchmark::State& state) const {
MinJae Hwanga79586c2020-07-06 18:29:38 -0400299 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);
303 }
304 });
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000305 }
306
307 std::string name() const {
308 return "BM_PopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
309 };
310};
311
312} // namespace
313
314int main(int argc, char** argv) {
315 benchmark::Initialize(&argc, argv);
316 if (benchmark::ReportUnrecognizedArguments(argc, argv))
317 return 1;
318
319 const std::vector<size_t> Quantities = {1 << 0, 1 << 2, 1 << 4, 1 << 6,
Eric Fiselierbb3de8e2019-08-21 00:14:48 +0000320 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
326 };
Samuel Benzaquen8e11d692018-11-20 17:15:17 +0000327 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();
MinJae Hwanga79586c2020-07-06 18:29:38 -0400337}