Skip to content

Commit c0515fc

Browse files
committed
[libc++] Add benchmarks for partitioning algorithms
This patch adds benchmarks for std::partition, is_partitioned, etc and their ranges:: variants.
1 parent 4d4d9d5 commit c0515fc

File tree

6 files changed

+397
-131
lines changed

6 files changed

+397
-131
lines changed

libcxx/test/benchmarks/algorithms/algorithms.partition_point.bench.cpp

Lines changed: 0 additions & 131 deletions
This file was deleted.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
11+
#include <algorithm>
12+
#include <cassert>
13+
#include <deque>
14+
#include <iterator>
15+
#include <list>
16+
#include <string>
17+
#include <vector>
18+
19+
#include "benchmark/benchmark.h"
20+
#include "../../GenerateInput.h"
21+
22+
auto compute_median(auto first, auto last) {
23+
std::vector v(first, last);
24+
auto middle = v.begin() + v.size() / 2;
25+
std::nth_element(v.begin(), middle, v.end());
26+
return *middle;
27+
}
28+
29+
template <class Container, bool Partitioned, class Operation>
30+
void bm(std::string operation_name, Operation is_partitioned) {
31+
auto bench = [is_partitioned](auto& st) {
32+
auto const size = st.range(0);
33+
using ValueType = typename Container::value_type;
34+
Container c;
35+
std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
36+
37+
// Partition the container in two equally-sized halves, ensuring the median
38+
// value appears in the left half. Note that the median value isn't located
39+
// in the middle -- this isn't std::nth_element.
40+
ValueType median = compute_median(c.begin(), c.end());
41+
auto pred = [median](auto const& element) { return element <= median; };
42+
std::partition(c.begin(), c.end(), pred);
43+
assert(std::is_partitioned(c.begin(), c.end(), pred));
44+
45+
if constexpr (!Partitioned) {
46+
// De-partition the container by swapping the element containing the median
47+
// value with the last one.
48+
auto median_it = std::find(c.begin(), c.end(), median);
49+
auto last_it = std::next(c.begin(), c.size() - 1);
50+
std::iter_swap(median_it, last_it);
51+
assert(!std::is_partitioned(c.begin(), c.end(), pred));
52+
}
53+
54+
for ([[maybe_unused]] auto _ : st) {
55+
auto result = is_partitioned(c.begin(), c.end(), pred);
56+
benchmark::DoNotOptimize(result);
57+
benchmark::DoNotOptimize(c);
58+
benchmark::ClobberMemory();
59+
}
60+
};
61+
benchmark::RegisterBenchmark(operation_name, bench)->Arg(32)->Arg(1024)->Arg(8192);
62+
}
63+
64+
int main(int argc, char** argv) {
65+
auto std_is_partitioned = [](auto first, auto last, auto pred) { return std::is_partitioned(first, last, pred); };
66+
auto ranges_is_partitioned = [](auto first, auto last, auto pred) {
67+
return std::ranges::is_partitioned(first, last, pred);
68+
};
69+
70+
// std::is_partitioned
71+
bm<std::vector<int>, true>("std::is_partitioned(vector<int>) (partitioned)", std_is_partitioned);
72+
bm<std::vector<int>, false>("std::is_partitioned(vector<int>) (not partitioned)", std_is_partitioned);
73+
74+
bm<std::deque<int>, true>("std::is_partitioned(deque<int>) (partitioned)", std_is_partitioned);
75+
bm<std::deque<int>, false>("std::is_partitioned(deque<int>) (not partitioned)", std_is_partitioned);
76+
77+
bm<std::list<int>, true>("std::is_partitioned(list<int>) (partitioned)", std_is_partitioned);
78+
bm<std::list<int>, false>("std::is_partitioned(list<int>) (not partitioned)", std_is_partitioned);
79+
80+
// ranges::is_partitioned
81+
bm<std::vector<int>, true>("ranges::is_partitioned(vector<int>) (partitioned)", ranges_is_partitioned);
82+
bm<std::vector<int>, false>("ranges::is_partitioned(vector<int>) (not partitioned)", ranges_is_partitioned);
83+
84+
bm<std::deque<int>, true>("ranges::is_partitioned(deque<int>) (partitioned)", ranges_is_partitioned);
85+
bm<std::deque<int>, false>("ranges::is_partitioned(deque<int>) (not partitioned)", ranges_is_partitioned);
86+
87+
bm<std::list<int>, true>("ranges::is_partitioned(list<int>) (partitioned)", ranges_is_partitioned);
88+
bm<std::list<int>, false>("ranges::is_partitioned(list<int>) (not partitioned)", ranges_is_partitioned);
89+
90+
benchmark::Initialize(&argc, argv);
91+
benchmark::RunSpecifiedBenchmarks();
92+
benchmark::Shutdown();
93+
return 0;
94+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
11+
#include <algorithm>
12+
#include <deque>
13+
#include <iterator>
14+
#include <list>
15+
#include <string>
16+
#include <vector>
17+
18+
#include "benchmark/benchmark.h"
19+
#include "../../GenerateInput.h"
20+
21+
auto compute_median(auto first, auto last) {
22+
std::vector v(first, last);
23+
auto middle = v.begin() + v.size() / 2;
24+
std::nth_element(v.begin(), middle, v.end());
25+
return *middle;
26+
}
27+
28+
template <class Container, class Operation>
29+
void bm(std::string operation_name, Operation partition) {
30+
auto bench = [partition](auto& st) {
31+
auto const size = st.range(0);
32+
using ValueType = typename Container::value_type;
33+
Container c;
34+
std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
35+
36+
std::vector<ValueType> yes(size), no(size);
37+
ValueType median = compute_median(c.begin(), c.end());
38+
auto pred1 = [median](auto const& element) { return element < median; };
39+
auto pred2 = [median](auto const& element) { return element > median; };
40+
bool toggle = false;
41+
42+
for ([[maybe_unused]] auto _ : st) {
43+
if (toggle) {
44+
auto result = partition(c.begin(), c.end(), pred1);
45+
benchmark::DoNotOptimize(result);
46+
} else {
47+
auto result = partition(c.begin(), c.end(), pred2);
48+
benchmark::DoNotOptimize(result);
49+
}
50+
toggle = !toggle;
51+
52+
benchmark::DoNotOptimize(c);
53+
benchmark::ClobberMemory();
54+
}
55+
};
56+
benchmark::RegisterBenchmark(operation_name, bench)->Arg(32)->Arg(1024)->Arg(8192);
57+
}
58+
59+
int main(int argc, char** argv) {
60+
auto std_partition = [](auto first, auto last, auto pred) { return std::partition(first, last, pred); };
61+
auto ranges_partition = [](auto first, auto last, auto pred) { return std::ranges::partition(first, last, pred); };
62+
63+
// std::partition
64+
bm<std::vector<int>>("std::partition(vector<int>)", std_partition);
65+
bm<std::deque<int>>("std::partition(deque<int>)", std_partition);
66+
bm<std::list<int>>("std::partition(list<int>)", std_partition);
67+
68+
// ranges::partition
69+
bm<std::vector<int>>("ranges::partition(vector<int>)", ranges_partition);
70+
bm<std::deque<int>>("ranges::partition(deque<int>)", ranges_partition);
71+
bm<std::list<int>>("ranges::partition(list<int>)", ranges_partition);
72+
73+
benchmark::Initialize(&argc, argv);
74+
benchmark::RunSpecifiedBenchmarks();
75+
benchmark::Shutdown();
76+
return 0;
77+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
11+
#include <algorithm>
12+
#include <deque>
13+
#include <iterator>
14+
#include <list>
15+
#include <string>
16+
#include <vector>
17+
18+
#include "benchmark/benchmark.h"
19+
#include "../../GenerateInput.h"
20+
21+
auto compute_median(auto first, auto last) {
22+
std::vector v(first, last);
23+
auto middle = v.begin() + v.size() / 2;
24+
std::nth_element(v.begin(), middle, v.end());
25+
return *middle;
26+
}
27+
28+
template <class Container, class Operation>
29+
void bm(std::string operation_name, Operation partition_copy) {
30+
auto bench = [partition_copy](auto& st) {
31+
auto const size = st.range(0);
32+
using ValueType = typename Container::value_type;
33+
Container c;
34+
std::generate_n(std::back_inserter(c), size, [] { return Generate<ValueType>::random(); });
35+
36+
std::vector<ValueType> yes(size), no(size);
37+
ValueType median = compute_median(c.begin(), c.end());
38+
auto pred = [median](auto const& element) { return element < median; };
39+
40+
for ([[maybe_unused]] auto _ : st) {
41+
auto result = partition_copy(c.begin(), c.end(), yes.begin(), no.begin(), pred);
42+
benchmark::DoNotOptimize(yes);
43+
benchmark::DoNotOptimize(no);
44+
benchmark::DoNotOptimize(result);
45+
benchmark::DoNotOptimize(c);
46+
benchmark::ClobberMemory();
47+
}
48+
};
49+
benchmark::RegisterBenchmark(operation_name, bench)->Arg(32)->Arg(1024)->Arg(8192);
50+
}
51+
52+
int main(int argc, char** argv) {
53+
auto std_partition_copy = [](auto first, auto last, auto out_yes, auto out_no, auto pred) {
54+
return std::partition_copy(first, last, out_yes, out_no, pred);
55+
};
56+
auto ranges_partition_copy = [](auto first, auto last, auto out_yes, auto out_no, auto pred) {
57+
return std::ranges::partition_copy(first, last, out_yes, out_no, pred);
58+
};
59+
60+
// std::partition_copy
61+
bm<std::vector<int>>("std::partition_copy(vector<int>)", std_partition_copy);
62+
bm<std::deque<int>>("std::partition_copy(deque<int>)", std_partition_copy);
63+
bm<std::list<int>>("std::partition_copy(list<int>)", std_partition_copy);
64+
65+
// ranges::partition_copy
66+
bm<std::vector<int>>("ranges::partition_copy(vector<int>)", ranges_partition_copy);
67+
bm<std::deque<int>>("ranges::partition_copy(deque<int>)", ranges_partition_copy);
68+
bm<std::list<int>>("ranges::partition_copy(list<int>)", ranges_partition_copy);
69+
70+
benchmark::Initialize(&argc, argv);
71+
benchmark::RunSpecifiedBenchmarks();
72+
benchmark::Shutdown();
73+
return 0;
74+
}

0 commit comments

Comments
 (0)