diff --git a/libcxx/benchmarks/algorithms.bench.cpp b/libcxx/benchmarks/algorithms.bench.cpp --- a/libcxx/benchmarks/algorithms.bench.cpp +++ b/libcxx/benchmarks/algorithms.bench.cpp @@ -14,14 +14,23 @@ namespace { -enum class ValueType { Uint32, String }; -struct AllValueTypes : EnumValuesAsTuple { - static constexpr const char* Names[] = {"uint32", "string"}; +enum class ValueType { Uint32, Uint64, Pair, Tuple, String }; +struct AllValueTypes : EnumValuesAsTuple { + static constexpr const char* Names[] = { + "uint32", "uint64", "pair", + "tuple", "string"}; }; template -using Value = - std::conditional_t; +using Value = std::conditional_t< + V() == ValueType::Uint32, uint32_t, + std::conditional_t< + V() == ValueType::Uint64, uint64_t, + std::conditional_t< + V() == ValueType::Pair, std::pair, + std::conditional_t, + std::string> > > >; enum class Order { Random, @@ -37,7 +46,8 @@ "PipeOrgan", "Heap"}; }; -void fillValues(std::vector& V, size_t N, Order O) { +template +void fillValues(std::vector& V, size_t N, Order O) { if (O == Order::SingleElement) { V.resize(N, 0); } else { @@ -46,13 +56,49 @@ } } -void fillValues(std::vector& V, size_t N, Order O) { +template +void fillValues(std::vector >& V, size_t N, Order O) { + if (O == Order::SingleElement) { + V.resize(N, std::make_pair(0, 0)); + } else { + while (V.size() < N) + // Half of array will have the same first element. + if (V.size() % 2) { + V.push_back(std::make_pair(V.size(), V.size())); + } else { + V.push_back(std::make_pair(0, V.size())); + } + } +} +template +void fillValues(std::vector >& V, size_t N, Order O) { + if (O == Order::SingleElement) { + V.resize(N, std::make_tuple(0, 0, 0)); + } else { + while (V.size() < N) + // One third of array will have the same first element. + // One third of array will have the same first element and the same second element. + switch (V.size() % 3) { + case 0: + V.push_back(std::make_tuple(V.size(), V.size(), V.size())); + break; + case 1: + V.push_back(std::make_tuple(0, V.size(), V.size())); + break; + case 2: + V.push_back(std::make_tuple(0, 0, V.size())); + break; + } + } +} + +void fillValues(std::vector& V, size_t N, Order O) { if (O == Order::SingleElement) { - V.resize(N, getRandomString(1024)); + V.resize(N, getRandomString(64)); } else { while (V.size() < N) - V.push_back(getRandomString(1024)); + V.push_back(getRandomString(64)); } } @@ -85,21 +131,24 @@ } } +constexpr size_t TestSetElements = +#if !TEST_HAS_FEATURE(memory_sanitizer) + 1 << 18; +#else + 1 << 14; +#endif + template std::vector > > makeOrderedValues(size_t N, Order O) { - // Let's make sure that all random sequences of the same size are the same. - // That way we can compare the different algorithms with the same input. - static std::map, std::vector > > - Cached; - - auto& Values = Cached[{N, O}]; - if (Values.empty()) { - fillValues(Values, N, O); - sortValues(Values, O); - }; - const size_t NumCopies = std::max(size_t{1}, 1000 / N); - return { NumCopies, Values }; + std::vector > > Ret; + const size_t NumCopies = std::max(size_t{1}, TestSetElements / N); + Ret.resize(NumCopies); + for (auto& V : Ret) { + fillValues(V, N, O); + sortValues(V, O); + } + return Ret; } template @@ -111,19 +160,28 @@ state.ResumeTiming(); } +enum class BatchSize { + CountElements, + CountBatch, +}; + template void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O, - bool CountElements, F f) { + BatchSize Count, F Body) { auto Copies = makeOrderedValues(Quantity, O); - const auto Orig = Copies[0]; + auto Orig = Copies; - const size_t Batch = CountElements ? Copies.size() * Quantity : Copies.size(); + const size_t Batch = Count == BatchSize::CountElements + ? Copies.size() * Quantity + : Copies.size(); while (state.KeepRunningBatch(Batch)) { for (auto& Copy : Copies) { - f(Copy); + Body(Copy); benchmark::DoNotOptimize(Copy); } - resetCopies(state, Copies, Orig); + state.PauseTiming(); + Copies = Orig; + state.ResumeTiming(); } } @@ -132,9 +190,9 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), false, [](auto& Copy) { - std::sort(Copy.begin(), Copy.end()); - }); + runOpOnCopies( + state, Quantity, Order(), BatchSize::CountElements, + [](auto& Copy) { std::sort(Copy.begin(), Copy.end()); }); } bool skip() const { return Order() == ::Order::Heap; } @@ -150,9 +208,9 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), false, [](auto& Copy) { - std::stable_sort(Copy.begin(), Copy.end()); - }); + runOpOnCopies( + state, Quantity, Order(), BatchSize::CountElements, + [](auto& Copy) { std::stable_sort(Copy.begin(), Copy.end()); }); } bool skip() const { return Order() == ::Order::Heap; } @@ -168,9 +226,9 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), false, [](auto& Copy) { - std::make_heap(Copy.begin(), Copy.end()); - }); + runOpOnCopies( + state, Quantity, Order(), BatchSize::CountElements, + [](auto& Copy) { std::make_heap(Copy.begin(), Copy.end()); }); } std::string name() const { @@ -185,7 +243,7 @@ void run(benchmark::State& state) const { runOpOnCopies( - state, Quantity, Order::Heap, false, + state, Quantity, Order::Heap, BatchSize::CountElements, [](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); }); } @@ -199,10 +257,11 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), false, [](auto& Copy) { - std::make_heap(Copy.begin(), Copy.end()); - std::sort_heap(Copy.begin(), Copy.end()); - }); + runOpOnCopies(state, Quantity, Order(), BatchSize::CountElements, + [](auto& Copy) { + std::make_heap(Copy.begin(), Copy.end()); + std::sort_heap(Copy.begin(), Copy.end()); + }); } std::string name() const { @@ -216,11 +275,12 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), true, [](auto& Copy) { - for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) { - std::push_heap(Copy.begin(), I + 1); - } - }); + runOpOnCopies( + state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) { + for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) { + std::push_heap(Copy.begin(), I + 1); + } + }); } bool skip() const { return Order() == ::Order::Heap; } @@ -236,11 +296,12 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), true, [](auto& Copy) { - for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) { - std::pop_heap(B, I); - } - }); + runOpOnCopies( + state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) { + for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) { + std::pop_heap(B, I); + } + }); } std::string name() const { @@ -273,4 +334,4 @@ makeCartesianProductBenchmark(Quantities); makeCartesianProductBenchmark(Quantities); benchmark::RunSpecifiedBenchmarks(); -} +} \ No newline at end of file