77// ===----------------------------------------------------------------------===//
88
99#include < algorithm>
10- #include < forward_list>
1110#include < iterator>
1211#include < set>
1312#include < vector>
@@ -31,57 +30,26 @@ struct SetContainer {
3130 static constexpr const char * Name = " Set" ;
3231};
3332
34- struct ForwardListContainer {
35- template <typename ... Args>
36- using type = std::forward_list<Args...>;
37-
38- static constexpr const char * Name = " ForwardList" ;
39- };
40-
41- using AllContainerTypes = std::tuple<VectorContainer, SetContainer, ForwardListContainer>;
33+ using AllContainerTypes = std::tuple<VectorContainer, SetContainer>;
4234
4335// set_intersection performance may depend on where matching values lie
4436enum class OverlapPosition {
4537 None,
4638 Front,
47- Back,
39+ // performance-wise, matches at the back are identical to ones at the front
4840 Interlaced,
4941};
5042
51- struct AllOverlapPositions : EnumValuesAsTuple<AllOverlapPositions, OverlapPosition, 4 > {
52- static constexpr const char * Names[] = {" None" , " Front" , " Back " , " Interlaced" };
43+ struct AllOverlapPositions : EnumValuesAsTuple<AllOverlapPositions, OverlapPosition, 3 > {
44+ static constexpr const char * Names[] = {" None" , " Front" , " Interlaced" };
5345};
5446
5547// functor that moves elements from an iterator range into a new Container instance
5648template <typename Container>
57- struct MoveInto {};
58-
59- template <typename T>
60- struct MoveInto <std::vector<T>> {
61- template <class It >
62- [[nodiscard]] static std::vector<T> operator ()(It first, It last) {
63- std::vector<T> out;
64- std::move (first, last, std::back_inserter (out));
65- return out;
66- }
67- };
68-
69- template <typename T>
70- struct MoveInto <std::forward_list<T>> {
49+ struct MoveInto {
7150 template <class It >
72- [[nodiscard]] static std::forward_list<T> operator ()(It first, It last) {
73- std::forward_list<T> out;
74- std::move (first, last, std::front_inserter (out));
75- out.reverse ();
76- return out;
77- }
78- };
79-
80- template <typename T>
81- struct MoveInto <std::set<T>> {
82- template <class It >
83- [[nodiscard]] static std::set<T> operator ()(It first, It last) {
84- std::set<T> out;
51+ [[nodiscard]] static Container operator ()(It first, It last) {
52+ Container out;
8553 std::move (first, last, std::inserter (out, out.begin ()));
8654 return out;
8755 }
@@ -137,7 +105,7 @@ template <class Container>
137105std::pair<Container, Container> genCacheUnfriendlyData (size_t size1, size_t size2, OverlapPosition pos) {
138106 using ValueType = typename Container::value_type;
139107 const MoveInto<Container> move_into;
140- const auto src_size = pos == OverlapPosition::None ? size1 + size2 : std::max (size1, size2);
108+ const auto src_size = pos == OverlapPosition::None ? size1 + size2 : std::max (size1, size2);
141109 std::vector<ValueType> src = getVectorOfRandom<ValueType>(src_size);
142110
143111 if (pos == OverlapPosition::None) {
@@ -159,10 +127,6 @@ std::pair<Container, Container> genCacheUnfriendlyData(size_t size1, size_t size
159127 case OverlapPosition::Front:
160128 return std::make_pair (move_into (src.begin (), src.begin () + size1), move_into (copy.begin (), copy.begin () + size2));
161129
162- case OverlapPosition::Back:
163- return std::make_pair (move_into (src.begin () + (src.size () - size1), src.end ()),
164- move_into (copy.begin () + (copy.size () - size2), copy.end ()));
165-
166130 case OverlapPosition::Interlaced:
167131 const auto stride1 = size1 < size2 ? size2 / size1 : 1 ;
168132 const auto stride2 = size2 < size1 ? size1 / size2 : 1 ;
@@ -181,6 +145,11 @@ struct SetIntersection {
181145
182146 SetIntersection (size_t size1, size_t size2) : size1_(size1), size2_(size2) {}
183147
148+ bool skip () const noexcept {
149+ // let's save some time and skip simmetrical runs
150+ return size1_ <= size2_;
151+ }
152+
184153 void run (benchmark::State& state) const {
185154 state.PauseTiming ();
186155 auto input = genCacheUnfriendlyData<ContainerType>(size1_, size2_, Overlap ());
@@ -192,12 +161,13 @@ struct SetIntersection {
192161 return std::less<Value<ValueType>>{}(lhs, rhs);
193162 };
194163
195- const auto BATCH_SIZE = std::max (size_t {16 }, (2 * TestSetElements) / (size1_ + size2_));
164+ const auto BATCH_SIZE = std::max (size_t {512 }, (2 * TestSetElements) / (size1_ + size2_));
196165 state.ResumeTiming ();
197166
198167 for (const auto & _ : state) {
199168 while (state.KeepRunningBatch (BATCH_SIZE)) {
200169 for (unsigned i = 0 ; i < BATCH_SIZE; ++i) {
170+ cmp = 0 ;
201171 const auto & [c1, c2] = input;
202172 auto res = std::set_intersection (c1.begin (), c1.end (), c2.begin (), c2.end (), out.begin (), tracking_less);
203173 benchmark::DoNotOptimize (res);
@@ -219,6 +189,18 @@ int main(int argc, char** argv) { /**/
219189 benchmark::Initialize (&argc, argv);
220190 if (benchmark::ReportUnrecognizedArguments (argc, argv))
221191 return 1 ;
192+ const std::vector<size_t > Quantities = {
193+ 1 << 0 ,
194+ 1 << 4 ,
195+ 1 << 8 ,
196+ 1 << 14 ,
197+ // Running each benchmark in parallel consumes too much memory with MSAN
198+ // and can lead to the test process being killed.
199+ #if !TEST_HAS_FEATURE(memory_sanitizer)
200+ 1 << 18
201+ #endif
202+ };
203+
222204 makeCartesianProductBenchmark<SetIntersection, AllValueTypes, AllContainerTypes, AllOverlapPositions>(
223205 Quantities, Quantities);
224206 benchmark::RunSpecifiedBenchmarks ();
0 commit comments