10 #include "CartesianBenchmarks.h"
11 #include "GenerateInput.h"
12 #include "benchmark/benchmark.h"
13 #include "test_macros.h"
17 enum class ValueType
{ Uint32
, Uint64
, Pair
, Tuple
, String
};
18 struct AllValueTypes
: EnumValuesAsTuple
<AllValueTypes
, ValueType
, 5> {
19 static constexpr const char* Names
[] = {
20 "uint32", "uint64", "pair<uint32, uint32>",
21 "tuple<uint32, uint64, uint32>", "string"};
25 using Value
= std::conditional_t
<
26 V() == ValueType::Uint32
, uint32_t,
28 V() == ValueType::Uint64
, uint64_t,
30 V() == ValueType::Pair
, std::pair
<uint32_t, uint32_t>,
31 std::conditional_t
<V() == ValueType::Tuple
,
32 std::tuple
<uint32_t, uint64_t, uint32_t>,
43 struct AllOrders
: EnumValuesAsTuple
<AllOrders
, Order
, 6> {
44 static constexpr const char* Names
[] = {"Random", "Ascending",
45 "Descending", "SingleElement",
50 void fillValues(std::vector
<T
>& V
, size_t N
, Order O
) {
51 if (O
== Order::SingleElement
) {
55 V
.push_back(V
.size());
60 void fillValues(std::vector
<std::pair
<T
, T
> >& V
, size_t N
, Order O
) {
61 if (O
== Order::SingleElement
) {
62 V
.resize(N
, std::make_pair(0, 0));
65 // Half of array will have the same first element.
67 V
.push_back(std::make_pair(V
.size(), V
.size()));
69 V
.push_back(std::make_pair(0, V
.size()));
74 template <typename T1
, typename T2
, typename T3
>
75 void fillValues(std::vector
<std::tuple
<T1
, T2
, T3
> >& V
, size_t N
, Order O
) {
76 if (O
== Order::SingleElement
) {
77 V
.resize(N
, std::make_tuple(0, 0, 0));
80 // One third of array will have the same first element.
81 // One third of array will have the same first element and the same second element.
82 switch (V
.size() % 3) {
84 V
.push_back(std::make_tuple(V
.size(), V
.size(), V
.size()));
87 V
.push_back(std::make_tuple(0, V
.size(), V
.size()));
90 V
.push_back(std::make_tuple(0, 0, V
.size()));
96 void fillValues(std::vector
<std::string
>& V
, size_t N
, Order O
) {
97 if (O
== Order::SingleElement
) {
98 V
.resize(N
, getRandomString(64));
101 V
.push_back(getRandomString(64));
106 void sortValues(T
& V
, Order O
) {
107 assert(std::is_sorted(V
.begin(), V
.end()));
109 case Order::Random
: {
110 std::random_device R
;
112 std::shuffle(V
.begin(), V
.end(), M
);
115 case Order::Ascending
:
116 std::sort(V
.begin(), V
.end());
118 case Order::Descending
:
119 std::sort(V
.begin(), V
.end(), std::greater
<>());
121 case Order::SingleElement
:
124 case Order::PipeOrgan
:
125 std::sort(V
.begin(), V
.end());
126 std::reverse(V
.begin() + V
.size() / 2, V
.end());
129 std::make_heap(V
.begin(), V
.end());
134 constexpr size_t TestSetElements
=
135 #if !TEST_HAS_FEATURE(memory_sanitizer)
141 template <class ValueType
>
142 std::vector
<std::vector
<Value
<ValueType
> > > makeOrderedValues(size_t N
,
144 std::vector
<std::vector
<Value
<ValueType
> > > Ret
;
145 const size_t NumCopies
= std::max(size_t{1}, TestSetElements
/ N
);
146 Ret
.resize(NumCopies
);
147 for (auto& V
: Ret
) {
154 template <class T
, class U
>
155 TEST_ALWAYS_INLINE
void resetCopies(benchmark::State
& state
, T
& Copies
,
158 for (auto& Copy
: Copies
)
160 state
.ResumeTiming();
163 enum class BatchSize
{
168 template <class ValueType
, class F
>
169 void runOpOnCopies(benchmark::State
& state
, size_t Quantity
, Order O
,
170 BatchSize Count
, F Body
) {
171 auto Copies
= makeOrderedValues
<ValueType
>(Quantity
, O
);
174 const size_t Batch
= Count
== BatchSize::CountElements
175 ? Copies
.size() * Quantity
177 while (state
.KeepRunningBatch(Batch
)) {
178 for (auto& Copy
: Copies
) {
180 benchmark::DoNotOptimize(Copy
);
184 state
.ResumeTiming();
188 template <class ValueType
, class Order
>
192 void run(benchmark::State
& state
) const {
193 runOpOnCopies
<ValueType
>(
194 state
, Quantity
, Order(), BatchSize::CountElements
,
195 [](auto& Copy
) { std::sort(Copy
.begin(), Copy
.end()); });
198 bool skip() const { return Order() == ::Order::Heap
; }
200 std::string
name() const {
201 return "BM_Sort" + ValueType::name() + Order::name() + "_" +
202 std::to_string(Quantity
);
206 template <class ValueType
, class Order
>
210 void run(benchmark::State
& state
) const {
211 runOpOnCopies
<ValueType
>(
212 state
, Quantity
, Order(), BatchSize::CountElements
,
213 [](auto& Copy
) { std::stable_sort(Copy
.begin(), Copy
.end()); });
216 bool skip() const { return Order() == ::Order::Heap
; }
218 std::string
name() const {
219 return "BM_StableSort" + ValueType::name() + Order::name() + "_" +
220 std::to_string(Quantity
);
224 template <class ValueType
, class Order
>
228 void run(benchmark::State
& state
) const {
229 runOpOnCopies
<ValueType
>(
230 state
, Quantity
, Order(), BatchSize::CountElements
,
231 [](auto& Copy
) { std::make_heap(Copy
.begin(), Copy
.end()); });
234 std::string
name() const {
235 return "BM_MakeHeap" + ValueType::name() + Order::name() + "_" +
236 std::to_string(Quantity
);
240 template <class ValueType
>
244 void run(benchmark::State
& state
) const {
245 runOpOnCopies
<ValueType
>(
246 state
, Quantity
, Order::Heap
, BatchSize::CountElements
,
247 [](auto& Copy
) { std::sort_heap(Copy
.begin(), Copy
.end()); });
250 std::string
name() const {
251 return "BM_SortHeap" + ValueType::name() + "_" + std::to_string(Quantity
);
255 template <class ValueType
, class Order
>
256 struct MakeThenSortHeap
{
259 void run(benchmark::State
& state
) const {
260 runOpOnCopies
<ValueType
>(state
, Quantity
, Order(), BatchSize::CountElements
,
262 std::make_heap(Copy
.begin(), Copy
.end());
263 std::sort_heap(Copy
.begin(), Copy
.end());
267 std::string
name() const {
268 return "BM_MakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
269 std::to_string(Quantity
);
273 template <class ValueType
, class Order
>
277 void run(benchmark::State
& state
) const {
278 runOpOnCopies
<ValueType
>(
279 state
, Quantity
, Order(), BatchSize::CountElements
, [](auto& Copy
) {
280 for (auto I
= Copy
.begin(), E
= Copy
.end(); I
!= E
; ++I
) {
281 std::push_heap(Copy
.begin(), I
+ 1);
286 bool skip() const { return Order() == ::Order::Heap
; }
288 std::string
name() const {
289 return "BM_PushHeap" + ValueType::name() + Order::name() + "_" +
290 std::to_string(Quantity
);
294 template <class ValueType
>
298 void run(benchmark::State
& state
) const {
299 runOpOnCopies
<ValueType
>(
300 state
, Quantity
, Order(), BatchSize::CountElements
, [](auto& Copy
) {
301 for (auto B
= Copy
.begin(), I
= Copy
.end(); I
!= B
; --I
) {
307 std::string
name() const {
308 return "BM_PopHeap" + ValueType::name() + "_" + std::to_string(Quantity
);
314 int main(int argc
, char** argv
) {
315 benchmark::Initialize(&argc
, argv
);
316 if (benchmark::ReportUnrecognizedArguments(argc
, argv
))
319 const std::vector
<size_t> Quantities
= {1 << 0, 1 << 2, 1 << 4, 1 << 6,
320 1 << 8, 1 << 10, 1 << 14,
321 // Running each benchmark in parallel consumes too much memory with MSAN
322 // and can lead to the test process being killed.
323 #if !TEST_HAS_FEATURE(memory_sanitizer)
327 makeCartesianProductBenchmark
<Sort
, AllValueTypes
, AllOrders
>(Quantities
);
328 makeCartesianProductBenchmark
<StableSort
, AllValueTypes
, AllOrders
>(
330 makeCartesianProductBenchmark
<MakeHeap
, AllValueTypes
, AllOrders
>(Quantities
);
331 makeCartesianProductBenchmark
<SortHeap
, AllValueTypes
>(Quantities
);
332 makeCartesianProductBenchmark
<MakeThenSortHeap
, AllValueTypes
, AllOrders
>(
334 makeCartesianProductBenchmark
<PushHeap
, AllValueTypes
, AllOrders
>(Quantities
);
335 makeCartesianProductBenchmark
<PopHeap
, AllValueTypes
>(Quantities
);
336 benchmark::RunSpecifiedBenchmarks();