[libcxx-commits] [libcxx] [libc++] Rewrite the set_intersection benchmark without CartesianBenchmarks (PR #214302)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Aug 10 00:42:17 PDT 2026
================
@@ -0,0 +1,209 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cstddef>
+#include <deque>
+#include <iterator>
+#include <set>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "../../GenerateInput.h"
+
+// Each benchmarking scenario produces the two sorted ranges to intersect, with `n` the size of the
+// larger of the two. The size of the smaller range is derived from `n`, and the ratio between the
+// two appears in the benchmark's name. That ratio is used to exercise implementation choices that
+// make a difference when the two ranges have very different sizes.
+
+// Generate `n` random values and return two independently allocated sorted copies of them.
+//
+// The copy is made before sorting, so that the two copies don't end up with their out-of-line
+// storage laid out in the same order.
+template <class T>
+std::pair<std::vector<T>, std::vector<T>> two_sorted_copies(std::size_t n) {
+ std::vector<T> a(n);
+ std::generate_n(a.begin(), n, [] { return Generate<T>::random(); });
+ std::vector<T> b = a;
+ std::sort(a.begin(), a.end());
+ std::sort(b.begin(), b.end());
+ return std::make_pair(std::move(a), std::move(b));
+}
+
+// Generate two ranges where the larger range holds `n` elements and the smaller one holds every `ratio`th
+// element of it, so the whole smaller range matches and the matches are spread evenly through the larger
+// one. Whether searching within the larger range beats scanning it depends on how far apart the matches
+// are, which is why this scenario is instantiated with several ratios. With a ratio of 1 the two ranges
+// are identical, which is the worst case for the number of elements written to the output.
+template <class T>
+std::pair<std::vector<T>, std::vector<T>> spread(std::size_t n, std::size_t ratio) {
+ auto [large, sampled] = two_sorted_copies<T>(n);
+ std::vector<T> small;
+ small.reserve(n / ratio + 1);
+ for (std::size_t i = 0; i < n; i += ratio)
+ small.push_back(std::move(sampled[i]));
+ return std::make_pair(std::move(large), std::move(small));
+}
+
+int main(int argc, char** argv) {
+ auto bm = []<class Container>(std::string name, auto generate) {
+ return benchmark::RegisterBenchmark(name, [generate](auto& st) {
+ using ValueType = typename Container::value_type;
+ std::size_t const size = st.range(0);
+
+ // Generate the values, then shuffle them so we don't insert into the containers in sorted order.
+ // Otherwise, node-based containers end up with an artificially good memory layout.
+ auto [values1, values2] = generate(std::type_identity<ValueType>{}, size);
+ std::shuffle(values1.begin(), values1.end(), getRandomEngine());
+ std::shuffle(values2.begin(), values2.end(), getRandomEngine());
----------------
philnik777 wrote:
Why do we shuffle if we just sort again?
https://github.com/llvm/llvm-project/pull/214302
More information about the libcxx-commits
mailing list