|
| 1 | +// Copyright (c) Microsoft Corporation. |
| 2 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 3 | + |
| 4 | +#include<algorithm> |
| 5 | +#include<benchmark/benchmark.h> |
| 6 | +#include<cstddef> |
| 7 | +#include<cstdint> |
| 8 | +#include<cstdlib> |
| 9 | +#include<iostream> |
| 10 | +#include<random> |
| 11 | +#include<ranges> |
| 12 | +#include<type_traits> |
| 13 | +#include<vector> |
| 14 | + |
| 15 | +#include"skewed_allocator.hpp" |
| 16 | +#include"utility.hpp" |
| 17 | + |
| 18 | +usingnamespacestd; |
| 19 | + |
| 20 | +enumclassalg_type { std_fn, rng }; |
| 21 | + |
| 22 | +enumclassneedle_spread { dense, dense_random, sparse, sparse_random }; |
| 23 | + |
| 24 | +template<classT, alg_type Alg> |
| 25 | +voidbm_includes(benchmark::State& state) { |
| 26 | +constauto hay_size =static_cast<size_t>(state.range(0)); |
| 27 | +constauto needle_size =static_cast<size_t>(state.range(1)); |
| 28 | +constauto spread =static_cast<needle_spread>(state.range(2)); |
| 29 | +constauto expected_match =static_cast<bool>(state.range(3)); |
| 30 | + |
| 31 | +auto hay = random_vector<T, not_highly_aligned_allocator>(hay_size); |
| 32 | +ranges::sort(hay); |
| 33 | + |
| 34 | + vector<T, not_highly_aligned_allocator<T>> needle; |
| 35 | +switch (spread) { |
| 36 | +case needle_spread::dense: |
| 37 | + needle.assign(hay.begin() + hay_size /2 - needle_size /2, hay.begin() + hay_size /2 + (needle_size +1) /2); |
| 38 | +break; |
| 39 | + |
| 40 | +case needle_spread::dense_random: |
| 41 | + { |
| 42 | + mt19937 gen{}; |
| 43 | + geometric_distribution<size_t> dis_dis{}; |
| 44 | + vector<size_t>idx(needle_size); |
| 45 | +constsize_t mid = needle_size /2; |
| 46 | + idx[mid] = hay_size /2; |
| 47 | + |
| 48 | +constsize_t max_shift = hay_size / needle_size; |
| 49 | + |
| 50 | +for (size_t i = mid; i !=0; --i) { |
| 51 | + idx[i -1] = idx[i] -min(dis_dis(gen) +1, max_shift); |
| 52 | + } |
| 53 | + |
| 54 | +for (size_t i = mid; i != needle_size -1; ++i) { |
| 55 | + idx[i +1] = idx[i] +min(dis_dis(gen) +1, max_shift); |
| 56 | + } |
| 57 | + |
| 58 | + needle.assign_range(idx |views::transform([&hay](constsize_t i) {return hay[i]; })); |
| 59 | + } |
| 60 | +break; |
| 61 | + |
| 62 | +case needle_spread::sparse: |
| 63 | + needle.resize(needle_size); |
| 64 | +for (size_t i =0; i != needle_size; ++i) { |
| 65 | + needle[i] = hay[hay_size * i / needle_size + hay_size / (needle_size *2)]; |
| 66 | + } |
| 67 | +break; |
| 68 | + |
| 69 | +case needle_spread::sparse_random: |
| 70 | + needle.resize(needle_size); |
| 71 | +ranges::sample(hay, needle.begin(), needle_size, mt19937{}); |
| 72 | +break; |
| 73 | + } |
| 74 | + |
| 75 | +if (!expected_match) { |
| 76 | +const T v = needle[needle_size /2]; |
| 77 | +const T r =static_cast<T>(static_cast<make_unsigned_t<T>>(v) +1); |
| 78 | +ranges::replace(hay, v, r); |
| 79 | +ranges::sort(hay); |
| 80 | + } |
| 81 | + |
| 82 | +for (auto _ : state) { |
| 83 | +benchmark::DoNotOptimize(hay); |
| 84 | +benchmark::DoNotOptimize(needle); |
| 85 | +bool found; |
| 86 | +ifconstexpr (Alg == alg_type::rng) { |
| 87 | + found =ranges::includes(hay, needle); |
| 88 | + }else { |
| 89 | + found =includes(hay.begin(), hay.end(), needle.begin(), needle.end()); |
| 90 | + } |
| 91 | +benchmark::DoNotOptimize(found); |
| 92 | +if (found != expected_match) { |
| 93 | + cerr <<"Unexpected 'includes' result:" << found <<'\n'; |
| 94 | +abort(); |
| 95 | + } |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +voidcommon_args(auto bm) { |
| 100 | +for (constauto& spread : |
| 101 | + {needle_spread::dense, needle_spread::dense_random, needle_spread::sparse, needle_spread::sparse_random}) { |
| 102 | +for (constauto& expected_match : {true,false}) { |
| 103 | +for (constauto& needle_size : {3,22,105,1504,2750}) { |
| 104 | + bm->Args({3000, needle_size,static_cast<underlying_type_t<needle_spread>>(spread), expected_match}); |
| 105 | + } |
| 106 | + |
| 107 | +for (constauto& needle_size : {3,22,105,290}) { |
| 108 | + bm->Args({300, needle_size,static_cast<underlying_type_t<needle_spread>>(spread), expected_match}); |
| 109 | + } |
| 110 | + } |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +BENCHMARK(bm_includes<int8_t, alg_type::std_fn>)->Apply(common_args); |
| 115 | +BENCHMARK(bm_includes<int16_t, alg_type::std_fn>)->Apply(common_args); |
| 116 | +BENCHMARK(bm_includes<int32_t, alg_type::std_fn>)->Apply(common_args); |
| 117 | +BENCHMARK(bm_includes<int64_t, alg_type::std_fn>)->Apply(common_args); |
| 118 | + |
| 119 | +BENCHMARK(bm_includes<int8_t, alg_type::rng>)->Apply(common_args); |
| 120 | +BENCHMARK(bm_includes<int16_t, alg_type::rng>)->Apply(common_args); |
| 121 | +BENCHMARK(bm_includes<int32_t, alg_type::rng>)->Apply(common_args); |
| 122 | +BENCHMARK(bm_includes<int64_t, alg_type::rng>)->Apply(common_args); |
| 123 | + |
| 124 | +BENCHMARK_MAIN(); |