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, getRandomString(1024)); + V.resize(N, std::make_tuple(0, 0, 0)); } else { while (V.size() < N) - V.push_back(getRandomString(1024)); + // 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(64)); + } else { + while (V.size() < N) + 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 @@ -115,7 +164,7 @@ void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O, bool CountElements, F f) { auto Copies = makeOrderedValues(Quantity, O); - const auto Orig = Copies[0]; + auto Orig = Copies; const size_t Batch = CountElements ? Copies.size() * Quantity : Copies.size(); while (state.KeepRunningBatch(Batch)) { @@ -123,7 +172,9 @@ f(Copy); benchmark::DoNotOptimize(Copy); } - resetCopies(state, Copies, Orig); + state.PauseTiming(); + Copies = Orig; + state.ResumeTiming(); } } @@ -132,7 +183,7 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), false, [](auto& Copy) { + runOpOnCopies(state, Quantity, Order(), true, [](auto& Copy) { std::sort(Copy.begin(), Copy.end()); }); } @@ -150,7 +201,7 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), false, [](auto& Copy) { + runOpOnCopies(state, Quantity, Order(), true, [](auto& Copy) { std::stable_sort(Copy.begin(), Copy.end()); }); } @@ -168,7 +219,7 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), false, [](auto& Copy) { + runOpOnCopies(state, Quantity, Order(), true, [](auto& Copy) { std::make_heap(Copy.begin(), Copy.end()); }); } @@ -185,7 +236,7 @@ void run(benchmark::State& state) const { runOpOnCopies( - state, Quantity, Order::Heap, false, + state, Quantity, Order::Heap, true, [](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); }); } @@ -199,7 +250,7 @@ size_t Quantity; void run(benchmark::State& state) const { - runOpOnCopies(state, Quantity, Order(), false, [](auto& Copy) { + runOpOnCopies(state, Quantity, Order(), true, [](auto& Copy) { std::make_heap(Copy.begin(), Copy.end()); std::sort_heap(Copy.begin(), Copy.end()); }); @@ -273,4 +324,4 @@ makeCartesianProductBenchmark(Quantities); makeCartesianProductBenchmark(Quantities); benchmark::RunSpecifiedBenchmarks(); -} +} \ No newline at end of file