| | #include <array> |
| | #include <algorithm> |
| | #include <cassert> |
| | #include <cstdint> |
| | #include <tuple> |
| | #include <vector> |
| |
|
| | #include "benchmark/benchmark.h" |
| |
|
| | #include "CartesianBenchmarks.h" |
| | #include "GenerateInput.h" |
| |
|
| | namespace { |
| |
|
| | template <typename I, typename N> |
| | std::array<I, 10> every_10th_percentile_N(I first, N n) { |
| | N step = n / 10; |
| | std::array<I, 10> res; |
| |
|
| | for (size_t i = 0; i < 10; ++i) { |
| | res[i] = first; |
| | std::advance(first, step); |
| | } |
| |
|
| | return res; |
| | } |
| |
|
| | template <class IntT> |
| | struct TestIntBase { |
| | static std::vector<IntT> generateInput(size_t size) { |
| | std::vector<IntT> Res(size); |
| | std::generate(Res.begin(), Res.end(), |
| | [] { return getRandomInteger<IntT>(); }); |
| | return Res; |
| | } |
| | }; |
| |
|
| | struct TestInt32 : TestIntBase<std::int32_t> { |
| | static constexpr const char* Name = "TestInt32"; |
| | }; |
| |
|
| | struct TestInt64 : TestIntBase<std::int64_t> { |
| | static constexpr const char* Name = "TestInt64"; |
| | }; |
| |
|
| | struct TestUint32 : TestIntBase<std::uint32_t> { |
| | static constexpr const char* Name = "TestUint32"; |
| | }; |
| |
|
| | struct TestMediumString { |
| | static constexpr const char* Name = "TestMediumString"; |
| | static constexpr size_t StringSize = 32; |
| |
|
| | static std::vector<std::string> generateInput(size_t size) { |
| | std::vector<std::string> Res(size); |
| | std::generate(Res.begin(), Res.end(), [] { return getRandomString(StringSize); }); |
| | return Res; |
| | } |
| | }; |
| |
|
| | using AllTestTypes = std::tuple<TestInt32, TestInt64, TestUint32, TestMediumString>; |
| |
|
| | struct LowerBoundAlg { |
| | template <class I, class V> |
| | I operator()(I first, I last, const V& value) const { |
| | return std::lower_bound(first, last, value); |
| | } |
| |
|
| | static constexpr const char* Name = "LowerBoundAlg"; |
| | }; |
| |
|
| | struct UpperBoundAlg { |
| | template <class I, class V> |
| | I operator()(I first, I last, const V& value) const { |
| | return std::upper_bound(first, last, value); |
| | } |
| |
|
| | static constexpr const char* Name = "UpperBoundAlg"; |
| | }; |
| |
|
| | struct EqualRangeAlg { |
| | template <class I, class V> |
| | std::pair<I, I> operator()(I first, I last, const V& value) const { |
| | return std::equal_range(first, last, value); |
| | } |
| |
|
| | static constexpr const char* Name = "EqualRangeAlg"; |
| | }; |
| |
|
| | using AllAlgs = std::tuple<LowerBoundAlg, UpperBoundAlg, EqualRangeAlg>; |
| |
|
| | template <class Alg, class TestType> |
| | struct PartitionPointBench { |
| | size_t Quantity; |
| |
|
| | std::string name() const { |
| | return std::string("PartitionPointBench_") + Alg::Name + "_" + |
| | TestType::Name + '/' + std::to_string(Quantity); |
| | } |
| |
|
| | void run(benchmark::State& state) const { |
| | auto Data = TestType::generateInput(Quantity); |
| | std::sort(Data.begin(), Data.end()); |
| | auto Every10Percentile = every_10th_percentile_N(Data.begin(), Data.size()); |
| |
|
| | for (auto _ : state) { |
| | for (auto Test : Every10Percentile) |
| | benchmark::DoNotOptimize(Alg{}(Data.begin(), Data.end(), *Test)); |
| | } |
| | } |
| | }; |
| |
|
| | } |
| |
|
| | int main(int argc, char** argv) { |
| | benchmark::Initialize(&argc, argv); |
| | if (benchmark::ReportUnrecognizedArguments(argc, argv)) |
| | return 1; |
| |
|
| | const std::vector<size_t> Quantities = {1 << 8, 1 << 10, 1 << 20}; |
| | makeCartesianProductBenchmark<PartitionPointBench, AllAlgs, AllTestTypes>( |
| | Quantities); |
| | benchmark::RunSpecifiedBenchmarks(); |
| | } |
| |
|