xref: /netbsd-src/external/apache2/llvm/dist/libcxx/benchmarks/algorithms.bench.cpp (revision 4d6fc14bc9b0c5bf3e30be318c143ee82cadd108)
1*4d6fc14bSjoerg 
2*4d6fc14bSjoerg #include <algorithm>
3*4d6fc14bSjoerg #include <cstdint>
4*4d6fc14bSjoerg #include <map>
5*4d6fc14bSjoerg #include <random>
6*4d6fc14bSjoerg #include <string>
7*4d6fc14bSjoerg #include <utility>
8*4d6fc14bSjoerg #include <vector>
9*4d6fc14bSjoerg 
10*4d6fc14bSjoerg #include "CartesianBenchmarks.h"
11*4d6fc14bSjoerg #include "GenerateInput.h"
12*4d6fc14bSjoerg #include "benchmark/benchmark.h"
13*4d6fc14bSjoerg #include "test_macros.h"
14*4d6fc14bSjoerg 
15*4d6fc14bSjoerg namespace {
16*4d6fc14bSjoerg 
17*4d6fc14bSjoerg enum class ValueType { Uint32, Uint64, Pair, Tuple, String };
18*4d6fc14bSjoerg struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 5> {
19*4d6fc14bSjoerg   static constexpr const char* Names[] = {
20*4d6fc14bSjoerg       "uint32", "uint64", "pair<uint32, uint32>",
21*4d6fc14bSjoerg       "tuple<uint32, uint64, uint32>", "string"};
22*4d6fc14bSjoerg };
23*4d6fc14bSjoerg 
24*4d6fc14bSjoerg template <class V>
25*4d6fc14bSjoerg using Value = std::conditional_t<
26*4d6fc14bSjoerg     V() == ValueType::Uint32, uint32_t,
27*4d6fc14bSjoerg     std::conditional_t<
28*4d6fc14bSjoerg         V() == ValueType::Uint64, uint64_t,
29*4d6fc14bSjoerg         std::conditional_t<
30*4d6fc14bSjoerg             V() == ValueType::Pair, std::pair<uint32_t, uint32_t>,
31*4d6fc14bSjoerg             std::conditional_t<V() == ValueType::Tuple,
32*4d6fc14bSjoerg                                std::tuple<uint32_t, uint64_t, uint32_t>,
33*4d6fc14bSjoerg                                std::string> > > >;
34*4d6fc14bSjoerg 
35*4d6fc14bSjoerg enum class Order {
36*4d6fc14bSjoerg   Random,
37*4d6fc14bSjoerg   Ascending,
38*4d6fc14bSjoerg   Descending,
39*4d6fc14bSjoerg   SingleElement,
40*4d6fc14bSjoerg   PipeOrgan,
41*4d6fc14bSjoerg   Heap
42*4d6fc14bSjoerg };
43*4d6fc14bSjoerg struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 6> {
44*4d6fc14bSjoerg   static constexpr const char* Names[] = {"Random",     "Ascending",
45*4d6fc14bSjoerg                                           "Descending", "SingleElement",
46*4d6fc14bSjoerg                                           "PipeOrgan",  "Heap"};
47*4d6fc14bSjoerg };
48*4d6fc14bSjoerg 
49*4d6fc14bSjoerg template <typename T>
fillValues(std::vector<T> & V,size_t N,Order O)50*4d6fc14bSjoerg void fillValues(std::vector<T>& V, size_t N, Order O) {
51*4d6fc14bSjoerg   if (O == Order::SingleElement) {
52*4d6fc14bSjoerg     V.resize(N, 0);
53*4d6fc14bSjoerg   } else {
54*4d6fc14bSjoerg     while (V.size() < N)
55*4d6fc14bSjoerg       V.push_back(V.size());
56*4d6fc14bSjoerg   }
57*4d6fc14bSjoerg }
58*4d6fc14bSjoerg 
59*4d6fc14bSjoerg template <typename T>
fillValues(std::vector<std::pair<T,T>> & V,size_t N,Order O)60*4d6fc14bSjoerg void fillValues(std::vector<std::pair<T, T> >& V, size_t N, Order O) {
61*4d6fc14bSjoerg   if (O == Order::SingleElement) {
62*4d6fc14bSjoerg     V.resize(N, std::make_pair(0, 0));
63*4d6fc14bSjoerg   } else {
64*4d6fc14bSjoerg     while (V.size() < N)
65*4d6fc14bSjoerg       // Half of array will have the same first element.
66*4d6fc14bSjoerg       if (V.size() % 2) {
67*4d6fc14bSjoerg         V.push_back(std::make_pair(V.size(), V.size()));
68*4d6fc14bSjoerg       } else {
69*4d6fc14bSjoerg         V.push_back(std::make_pair(0, V.size()));
70*4d6fc14bSjoerg       }
71*4d6fc14bSjoerg   }
72*4d6fc14bSjoerg }
73*4d6fc14bSjoerg 
74*4d6fc14bSjoerg template <typename T1, typename T2, typename T3>
fillValues(std::vector<std::tuple<T1,T2,T3>> & V,size_t N,Order O)75*4d6fc14bSjoerg void fillValues(std::vector<std::tuple<T1, T2, T3> >& V, size_t N, Order O) {
76*4d6fc14bSjoerg   if (O == Order::SingleElement) {
77*4d6fc14bSjoerg     V.resize(N, std::make_tuple(0, 0, 0));
78*4d6fc14bSjoerg   } else {
79*4d6fc14bSjoerg     while (V.size() < N)
80*4d6fc14bSjoerg       // One third of array will have the same first element.
81*4d6fc14bSjoerg       // One third of array will have the same first element and the same second element.
82*4d6fc14bSjoerg       switch (V.size() % 3) {
83*4d6fc14bSjoerg       case 0:
84*4d6fc14bSjoerg         V.push_back(std::make_tuple(V.size(), V.size(), V.size()));
85*4d6fc14bSjoerg         break;
86*4d6fc14bSjoerg       case 1:
87*4d6fc14bSjoerg         V.push_back(std::make_tuple(0, V.size(), V.size()));
88*4d6fc14bSjoerg         break;
89*4d6fc14bSjoerg       case 2:
90*4d6fc14bSjoerg         V.push_back(std::make_tuple(0, 0, V.size()));
91*4d6fc14bSjoerg         break;
92*4d6fc14bSjoerg       }
93*4d6fc14bSjoerg   }
94*4d6fc14bSjoerg }
95*4d6fc14bSjoerg 
fillValues(std::vector<std::string> & V,size_t N,Order O)96*4d6fc14bSjoerg void fillValues(std::vector<std::string>& V, size_t N, Order O) {
97*4d6fc14bSjoerg   if (O == Order::SingleElement) {
98*4d6fc14bSjoerg     V.resize(N, getRandomString(64));
99*4d6fc14bSjoerg   } else {
100*4d6fc14bSjoerg     while (V.size() < N)
101*4d6fc14bSjoerg       V.push_back(getRandomString(64));
102*4d6fc14bSjoerg   }
103*4d6fc14bSjoerg }
104*4d6fc14bSjoerg 
105*4d6fc14bSjoerg template <class T>
sortValues(T & V,Order O)106*4d6fc14bSjoerg void sortValues(T& V, Order O) {
107*4d6fc14bSjoerg   assert(std::is_sorted(V.begin(), V.end()));
108*4d6fc14bSjoerg   switch (O) {
109*4d6fc14bSjoerg   case Order::Random: {
110*4d6fc14bSjoerg     std::random_device R;
111*4d6fc14bSjoerg     std::mt19937 M(R());
112*4d6fc14bSjoerg     std::shuffle(V.begin(), V.end(), M);
113*4d6fc14bSjoerg     break;
114*4d6fc14bSjoerg   }
115*4d6fc14bSjoerg   case Order::Ascending:
116*4d6fc14bSjoerg     std::sort(V.begin(), V.end());
117*4d6fc14bSjoerg     break;
118*4d6fc14bSjoerg   case Order::Descending:
119*4d6fc14bSjoerg     std::sort(V.begin(), V.end(), std::greater<>());
120*4d6fc14bSjoerg     break;
121*4d6fc14bSjoerg   case Order::SingleElement:
122*4d6fc14bSjoerg     // Nothing to do
123*4d6fc14bSjoerg     break;
124*4d6fc14bSjoerg   case Order::PipeOrgan:
125*4d6fc14bSjoerg     std::sort(V.begin(), V.end());
126*4d6fc14bSjoerg     std::reverse(V.begin() + V.size() / 2, V.end());
127*4d6fc14bSjoerg     break;
128*4d6fc14bSjoerg   case Order::Heap:
129*4d6fc14bSjoerg     std::make_heap(V.begin(), V.end());
130*4d6fc14bSjoerg     break;
131*4d6fc14bSjoerg   }
132*4d6fc14bSjoerg }
133*4d6fc14bSjoerg 
134*4d6fc14bSjoerg constexpr size_t TestSetElements =
135*4d6fc14bSjoerg #if !TEST_HAS_FEATURE(memory_sanitizer)
136*4d6fc14bSjoerg     1 << 18;
137*4d6fc14bSjoerg #else
138*4d6fc14bSjoerg     1 << 14;
139*4d6fc14bSjoerg #endif
140*4d6fc14bSjoerg 
141*4d6fc14bSjoerg template <class ValueType>
makeOrderedValues(size_t N,Order O)142*4d6fc14bSjoerg std::vector<std::vector<Value<ValueType> > > makeOrderedValues(size_t N,
143*4d6fc14bSjoerg                                                                Order O) {
144*4d6fc14bSjoerg   std::vector<std::vector<Value<ValueType> > > Ret;
145*4d6fc14bSjoerg   const size_t NumCopies = std::max(size_t{1}, TestSetElements / N);
146*4d6fc14bSjoerg   Ret.resize(NumCopies);
147*4d6fc14bSjoerg   for (auto& V : Ret) {
148*4d6fc14bSjoerg     fillValues(V, N, O);
149*4d6fc14bSjoerg     sortValues(V, O);
150*4d6fc14bSjoerg   }
151*4d6fc14bSjoerg   return Ret;
152*4d6fc14bSjoerg }
153*4d6fc14bSjoerg 
154*4d6fc14bSjoerg template <class T, class U>
resetCopies(benchmark::State & state,T & Copies,U & Orig)155*4d6fc14bSjoerg TEST_ALWAYS_INLINE void resetCopies(benchmark::State& state, T& Copies,
156*4d6fc14bSjoerg                                     U& Orig) {
157*4d6fc14bSjoerg   state.PauseTiming();
158*4d6fc14bSjoerg   for (auto& Copy : Copies)
159*4d6fc14bSjoerg     Copy = Orig;
160*4d6fc14bSjoerg   state.ResumeTiming();
161*4d6fc14bSjoerg }
162*4d6fc14bSjoerg 
163*4d6fc14bSjoerg enum class BatchSize {
164*4d6fc14bSjoerg   CountElements,
165*4d6fc14bSjoerg   CountBatch,
166*4d6fc14bSjoerg };
167*4d6fc14bSjoerg 
168*4d6fc14bSjoerg template <class ValueType, class F>
runOpOnCopies(benchmark::State & state,size_t Quantity,Order O,BatchSize Count,F Body)169*4d6fc14bSjoerg void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O,
170*4d6fc14bSjoerg                    BatchSize Count, F Body) {
171*4d6fc14bSjoerg   auto Copies = makeOrderedValues<ValueType>(Quantity, O);
172*4d6fc14bSjoerg   auto Orig = Copies;
173*4d6fc14bSjoerg 
174*4d6fc14bSjoerg   const size_t Batch = Count == BatchSize::CountElements
175*4d6fc14bSjoerg                            ? Copies.size() * Quantity
176*4d6fc14bSjoerg                            : Copies.size();
177*4d6fc14bSjoerg   while (state.KeepRunningBatch(Batch)) {
178*4d6fc14bSjoerg     for (auto& Copy : Copies) {
179*4d6fc14bSjoerg       Body(Copy);
180*4d6fc14bSjoerg       benchmark::DoNotOptimize(Copy);
181*4d6fc14bSjoerg     }
182*4d6fc14bSjoerg     state.PauseTiming();
183*4d6fc14bSjoerg     Copies = Orig;
184*4d6fc14bSjoerg     state.ResumeTiming();
185*4d6fc14bSjoerg   }
186*4d6fc14bSjoerg }
187*4d6fc14bSjoerg 
188*4d6fc14bSjoerg template <class ValueType, class Order>
189*4d6fc14bSjoerg struct Sort {
190*4d6fc14bSjoerg   size_t Quantity;
191*4d6fc14bSjoerg 
run__anonc233ceb90111::Sort192*4d6fc14bSjoerg   void run(benchmark::State& state) const {
193*4d6fc14bSjoerg     runOpOnCopies<ValueType>(
194*4d6fc14bSjoerg         state, Quantity, Order(), BatchSize::CountElements,
195*4d6fc14bSjoerg         [](auto& Copy) { std::sort(Copy.begin(), Copy.end()); });
196*4d6fc14bSjoerg   }
197*4d6fc14bSjoerg 
skip__anonc233ceb90111::Sort198*4d6fc14bSjoerg   bool skip() const { return Order() == ::Order::Heap; }
199*4d6fc14bSjoerg 
name__anonc233ceb90111::Sort200*4d6fc14bSjoerg   std::string name() const {
201*4d6fc14bSjoerg     return "BM_Sort" + ValueType::name() + Order::name() + "_" +
202*4d6fc14bSjoerg            std::to_string(Quantity);
203*4d6fc14bSjoerg   };
204*4d6fc14bSjoerg };
205*4d6fc14bSjoerg 
206*4d6fc14bSjoerg template <class ValueType, class Order>
207*4d6fc14bSjoerg struct StableSort {
208*4d6fc14bSjoerg   size_t Quantity;
209*4d6fc14bSjoerg 
run__anonc233ceb90111::StableSort210*4d6fc14bSjoerg   void run(benchmark::State& state) const {
211*4d6fc14bSjoerg     runOpOnCopies<ValueType>(
212*4d6fc14bSjoerg         state, Quantity, Order(), BatchSize::CountElements,
213*4d6fc14bSjoerg         [](auto& Copy) { std::stable_sort(Copy.begin(), Copy.end()); });
214*4d6fc14bSjoerg   }
215*4d6fc14bSjoerg 
skip__anonc233ceb90111::StableSort216*4d6fc14bSjoerg   bool skip() const { return Order() == ::Order::Heap; }
217*4d6fc14bSjoerg 
name__anonc233ceb90111::StableSort218*4d6fc14bSjoerg   std::string name() const {
219*4d6fc14bSjoerg     return "BM_StableSort" + ValueType::name() + Order::name() + "_" +
220*4d6fc14bSjoerg            std::to_string(Quantity);
221*4d6fc14bSjoerg   };
222*4d6fc14bSjoerg };
223*4d6fc14bSjoerg 
224*4d6fc14bSjoerg template <class ValueType, class Order>
225*4d6fc14bSjoerg struct MakeHeap {
226*4d6fc14bSjoerg   size_t Quantity;
227*4d6fc14bSjoerg 
run__anonc233ceb90111::MakeHeap228*4d6fc14bSjoerg   void run(benchmark::State& state) const {
229*4d6fc14bSjoerg     runOpOnCopies<ValueType>(
230*4d6fc14bSjoerg         state, Quantity, Order(), BatchSize::CountElements,
231*4d6fc14bSjoerg         [](auto& Copy) { std::make_heap(Copy.begin(), Copy.end()); });
232*4d6fc14bSjoerg   }
233*4d6fc14bSjoerg 
name__anonc233ceb90111::MakeHeap234*4d6fc14bSjoerg   std::string name() const {
235*4d6fc14bSjoerg     return "BM_MakeHeap" + ValueType::name() + Order::name() + "_" +
236*4d6fc14bSjoerg            std::to_string(Quantity);
237*4d6fc14bSjoerg   };
238*4d6fc14bSjoerg };
239*4d6fc14bSjoerg 
240*4d6fc14bSjoerg template <class ValueType>
241*4d6fc14bSjoerg struct SortHeap {
242*4d6fc14bSjoerg   size_t Quantity;
243*4d6fc14bSjoerg 
run__anonc233ceb90111::SortHeap244*4d6fc14bSjoerg   void run(benchmark::State& state) const {
245*4d6fc14bSjoerg     runOpOnCopies<ValueType>(
246*4d6fc14bSjoerg         state, Quantity, Order::Heap, BatchSize::CountElements,
247*4d6fc14bSjoerg         [](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); });
248*4d6fc14bSjoerg   }
249*4d6fc14bSjoerg 
name__anonc233ceb90111::SortHeap250*4d6fc14bSjoerg   std::string name() const {
251*4d6fc14bSjoerg     return "BM_SortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
252*4d6fc14bSjoerg   };
253*4d6fc14bSjoerg };
254*4d6fc14bSjoerg 
255*4d6fc14bSjoerg template <class ValueType, class Order>
256*4d6fc14bSjoerg struct MakeThenSortHeap {
257*4d6fc14bSjoerg   size_t Quantity;
258*4d6fc14bSjoerg 
run__anonc233ceb90111::MakeThenSortHeap259*4d6fc14bSjoerg   void run(benchmark::State& state) const {
260*4d6fc14bSjoerg     runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements,
261*4d6fc14bSjoerg                              [](auto& Copy) {
262*4d6fc14bSjoerg                                std::make_heap(Copy.begin(), Copy.end());
263*4d6fc14bSjoerg                                std::sort_heap(Copy.begin(), Copy.end());
264*4d6fc14bSjoerg                              });
265*4d6fc14bSjoerg   }
266*4d6fc14bSjoerg 
name__anonc233ceb90111::MakeThenSortHeap267*4d6fc14bSjoerg   std::string name() const {
268*4d6fc14bSjoerg     return "BM_MakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
269*4d6fc14bSjoerg            std::to_string(Quantity);
270*4d6fc14bSjoerg   };
271*4d6fc14bSjoerg };
272*4d6fc14bSjoerg 
273*4d6fc14bSjoerg template <class ValueType, class Order>
274*4d6fc14bSjoerg struct PushHeap {
275*4d6fc14bSjoerg   size_t Quantity;
276*4d6fc14bSjoerg 
run__anonc233ceb90111::PushHeap277*4d6fc14bSjoerg   void run(benchmark::State& state) const {
278*4d6fc14bSjoerg     runOpOnCopies<ValueType>(
279*4d6fc14bSjoerg         state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
280*4d6fc14bSjoerg           for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
281*4d6fc14bSjoerg             std::push_heap(Copy.begin(), I + 1);
282*4d6fc14bSjoerg           }
283*4d6fc14bSjoerg         });
284*4d6fc14bSjoerg   }
285*4d6fc14bSjoerg 
skip__anonc233ceb90111::PushHeap286*4d6fc14bSjoerg   bool skip() const { return Order() == ::Order::Heap; }
287*4d6fc14bSjoerg 
name__anonc233ceb90111::PushHeap288*4d6fc14bSjoerg   std::string name() const {
289*4d6fc14bSjoerg     return "BM_PushHeap" + ValueType::name() + Order::name() + "_" +
290*4d6fc14bSjoerg            std::to_string(Quantity);
291*4d6fc14bSjoerg   };
292*4d6fc14bSjoerg };
293*4d6fc14bSjoerg 
294*4d6fc14bSjoerg template <class ValueType>
295*4d6fc14bSjoerg struct PopHeap {
296*4d6fc14bSjoerg   size_t Quantity;
297*4d6fc14bSjoerg 
run__anonc233ceb90111::PopHeap298*4d6fc14bSjoerg   void run(benchmark::State& state) const {
299*4d6fc14bSjoerg     runOpOnCopies<ValueType>(
300*4d6fc14bSjoerg         state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
301*4d6fc14bSjoerg           for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
302*4d6fc14bSjoerg             std::pop_heap(B, I);
303*4d6fc14bSjoerg           }
304*4d6fc14bSjoerg         });
305*4d6fc14bSjoerg   }
306*4d6fc14bSjoerg 
name__anonc233ceb90111::PopHeap307*4d6fc14bSjoerg   std::string name() const {
308*4d6fc14bSjoerg     return "BM_PopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
309*4d6fc14bSjoerg   };
310*4d6fc14bSjoerg };
311*4d6fc14bSjoerg 
312*4d6fc14bSjoerg } // namespace
313*4d6fc14bSjoerg 
main(int argc,char ** argv)314*4d6fc14bSjoerg int main(int argc, char** argv) {
315*4d6fc14bSjoerg   benchmark::Initialize(&argc, argv);
316*4d6fc14bSjoerg   if (benchmark::ReportUnrecognizedArguments(argc, argv))
317*4d6fc14bSjoerg     return 1;
318*4d6fc14bSjoerg 
319*4d6fc14bSjoerg   const std::vector<size_t> Quantities = {1 << 0, 1 << 2,  1 << 4,  1 << 6,
320*4d6fc14bSjoerg                                           1 << 8, 1 << 10, 1 << 14,
321*4d6fc14bSjoerg     // Running each benchmark in parallel consumes too much memory with MSAN
322*4d6fc14bSjoerg     // and can lead to the test process being killed.
323*4d6fc14bSjoerg #if !TEST_HAS_FEATURE(memory_sanitizer)
324*4d6fc14bSjoerg                                           1 << 18
325*4d6fc14bSjoerg #endif
326*4d6fc14bSjoerg   };
327*4d6fc14bSjoerg   makeCartesianProductBenchmark<Sort, AllValueTypes, AllOrders>(Quantities);
328*4d6fc14bSjoerg   makeCartesianProductBenchmark<StableSort, AllValueTypes, AllOrders>(
329*4d6fc14bSjoerg       Quantities);
330*4d6fc14bSjoerg   makeCartesianProductBenchmark<MakeHeap, AllValueTypes, AllOrders>(Quantities);
331*4d6fc14bSjoerg   makeCartesianProductBenchmark<SortHeap, AllValueTypes>(Quantities);
332*4d6fc14bSjoerg   makeCartesianProductBenchmark<MakeThenSortHeap, AllValueTypes, AllOrders>(
333*4d6fc14bSjoerg       Quantities);
334*4d6fc14bSjoerg   makeCartesianProductBenchmark<PushHeap, AllValueTypes, AllOrders>(Quantities);
335*4d6fc14bSjoerg   makeCartesianProductBenchmark<PopHeap, AllValueTypes>(Quantities);
336*4d6fc14bSjoerg   benchmark::RunSpecifiedBenchmarks();
337*4d6fc14bSjoerg }