Skip to content

Commit 450f5ce

Browse files
committed
General improvements to benchmark, including simplifying and slimming it down for faster runs, and including comparison counter.
1 parent 46cc95f commit 450f5ce

File tree

1 file changed

+27
-45
lines changed

1 file changed

+27
-45
lines changed

libcxx/benchmarks/algorithms/set_intersection.bench.cpp

Lines changed: 27 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
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
4436
enum 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
5648
template <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>
137105
std::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

Comments
 (0)