[libcxx-commits] [libcxx] [libc++] Refactor the sequence container benchmarks (PR #119763)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Dec 12 13:20:45 PST 2024
https://github.com/ldionne created https://github.com/llvm/llvm-project/pull/119763
Rewrite the sequence container benchmarks to only rely on the actual operations specified in SequenceContainer requirements and add benchmarks for std::list, which is also considered a sequence container.
One of the major goals of this refactoring is also to make these container benchmarks run faster so that they can be run more frequently. The existing benchmarks have the significant problem that they take so long to run that they must basically be run overnight. This patch reduces the size of inputs such that the rewritten benchmarks each take at most a minute to run.
This patch doesn't touch the string benchmarks, which were not using the generic container benchmark functions previously.
>From a4d16969950e9ea2e4700d93e34d15a1d54b3a7d Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Thu, 12 Dec 2024 08:25:15 -0500
Subject: [PATCH] [libc++] Refactor the sequence container benchmarks
Rewrite the sequence container benchmarks to only rely on the actual
operations specified in SequenceContainer requirements and add benchmarks
for std::list, which is also considered a sequence container.
One of the major goals of this refactoring is also to make these
container benchmarks run faster so that they can be run more frequently.
The existing benchmarks have the significant problem that they take so
long to run that they must basically be run overnight. This patch reduces
the size of inputs such that the rewritten benchmarks each take at most a
minute to run.
This patch doesn't touch the string benchmarks, which were not using
the generic container benchmark functions previously.
---
libcxx/test/benchmarks/Utilities.h | 37 --
.../containers/ContainerBenchmarks.h | 272 -----------
.../containers/container_benchmarks.h | 435 ++++++++++++++++++
.../benchmarks/containers/deque.bench.cpp | 50 +-
.../test/benchmarks/containers/list.bench.cpp | 25 +
.../unordered_set_operations.bench.cpp | 4 +-
.../benchmarks/containers/vector.bench.cpp | 25 +
.../containers/vector_operations.bench.cpp | 94 ----
8 files changed, 497 insertions(+), 445 deletions(-)
delete mode 100644 libcxx/test/benchmarks/Utilities.h
delete mode 100644 libcxx/test/benchmarks/containers/ContainerBenchmarks.h
create mode 100644 libcxx/test/benchmarks/containers/container_benchmarks.h
create mode 100644 libcxx/test/benchmarks/containers/list.bench.cpp
create mode 100644 libcxx/test/benchmarks/containers/vector.bench.cpp
delete mode 100644 libcxx/test/benchmarks/containers/vector_operations.bench.cpp
diff --git a/libcxx/test/benchmarks/Utilities.h b/libcxx/test/benchmarks/Utilities.h
deleted file mode 100644
index fed16ba51f995f..00000000000000
--- a/libcxx/test/benchmarks/Utilities.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef BENCHMARK_UTILITIES_H
-#define BENCHMARK_UTILITIES_H
-
-#include <cassert>
-#include <type_traits>
-
-#include "benchmark/benchmark.h"
-
-namespace UtilitiesInternal {
-template <class Container>
-auto HaveDataImpl(int) -> decltype((std::declval<Container&>().data(), std::true_type{}));
-template <class Container>
-auto HaveDataImpl(long) -> std::false_type;
-template <class T>
-using HasData = decltype(HaveDataImpl<T>(0));
-} // namespace UtilitiesInternal
-
-template <class Container, std::enable_if_t<UtilitiesInternal::HasData<Container>::value>* = nullptr>
-void DoNotOptimizeData(Container& c) {
- benchmark::DoNotOptimize(c.data());
-}
-
-template <class Container, std::enable_if_t<!UtilitiesInternal::HasData<Container>::value>* = nullptr>
-void DoNotOptimizeData(Container& c) {
- benchmark::DoNotOptimize(&c);
-}
-
-#endif // BENCHMARK_UTILITIES_H
diff --git a/libcxx/test/benchmarks/containers/ContainerBenchmarks.h b/libcxx/test/benchmarks/containers/ContainerBenchmarks.h
deleted file mode 100644
index 6d21e12896ec9e..00000000000000
--- a/libcxx/test/benchmarks/containers/ContainerBenchmarks.h
+++ /dev/null
@@ -1,272 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef BENCHMARK_CONTAINER_BENCHMARKS_H
-#define BENCHMARK_CONTAINER_BENCHMARKS_H
-
-#include <cassert>
-#include <iterator>
-#include <utility>
-
-#include "benchmark/benchmark.h"
-#include "../Utilities.h"
-#include "test_iterators.h"
-
-namespace ContainerBenchmarks {
-
-template <class Container>
-void BM_ConstructSize(benchmark::State& st, Container) {
- auto size = st.range(0);
- for (auto _ : st) {
- Container c(size);
- DoNotOptimizeData(c);
- }
-}
-
-template <class Container>
-void BM_CopyConstruct(benchmark::State& st, Container) {
- auto size = st.range(0);
- Container c(size);
- for (auto _ : st) {
- auto v = c;
- DoNotOptimizeData(v);
- }
-}
-
-template <class Container>
-void BM_Assignment(benchmark::State& st, Container) {
- auto size = st.range(0);
- Container c1;
- Container c2(size);
- for (auto _ : st) {
- c1 = c2;
- DoNotOptimizeData(c1);
- DoNotOptimizeData(c2);
- }
-}
-
-template <std::size_t... sz, typename Container, typename GenInputs>
-void BM_AssignInputIterIter(benchmark::State& st, Container c, GenInputs gen) {
- auto v = gen(1, sz...);
- c.resize(st.range(0), v[0]);
- auto in = gen(st.range(1), sz...);
- benchmark::DoNotOptimize(&in);
- benchmark::DoNotOptimize(&c);
- for (auto _ : st) {
- c.assign(cpp17_input_iterator(in.begin()), cpp17_input_iterator(in.end()));
- benchmark::ClobberMemory();
- }
-}
-
-template <class Container>
-void BM_ConstructSizeValue(benchmark::State& st, Container, typename Container::value_type const& val) {
- const auto size = st.range(0);
- for (auto _ : st) {
- Container c(size, val);
- DoNotOptimizeData(c);
- }
-}
-
-template <class Container, class GenInputs>
-void BM_ConstructIterIter(benchmark::State& st, Container, GenInputs gen) {
- auto in = gen(st.range(0));
- const auto begin = in.begin();
- const auto end = in.end();
- benchmark::DoNotOptimize(&in);
- while (st.KeepRunning()) {
- Container c(begin, end);
- DoNotOptimizeData(c);
- }
-}
-
-template <class Container, class GenInputs>
-void BM_ConstructFromRange(benchmark::State& st, Container, GenInputs gen) {
- auto in = gen(st.range(0));
- benchmark::DoNotOptimize(&in);
- while (st.KeepRunning()) {
- Container c(std::from_range, in);
- DoNotOptimizeData(c);
- }
-}
-
-template <class Container>
-void BM_Pushback_no_grow(benchmark::State& state, Container c) {
- int count = state.range(0);
- c.reserve(count);
- while (state.KeepRunningBatch(count)) {
- c.clear();
- for (int i = 0; i != count; ++i) {
- c.push_back(i);
- }
- benchmark::DoNotOptimize(c.data());
- }
-}
-
-template <class Container, class GenInputs>
-void BM_InsertValue(benchmark::State& st, Container c, GenInputs gen) {
- auto in = gen(st.range(0));
- const auto end = in.end();
- while (st.KeepRunning()) {
- c.clear();
- for (auto it = in.begin(); it != end; ++it) {
- benchmark::DoNotOptimize(&(*c.insert(*it).first));
- }
- benchmark::ClobberMemory();
- }
-}
-
-template <class Container, class GenInputs>
-void BM_InsertValueRehash(benchmark::State& st, Container c, GenInputs gen) {
- auto in = gen(st.range(0));
- const auto end = in.end();
- while (st.KeepRunning()) {
- c.clear();
- c.rehash(16);
- for (auto it = in.begin(); it != end; ++it) {
- benchmark::DoNotOptimize(&(*c.insert(*it).first));
- }
- benchmark::ClobberMemory();
- }
-}
-
-template <class Container, class GenInputs>
-void BM_InsertDuplicate(benchmark::State& st, Container c, GenInputs gen) {
- auto in = gen(st.range(0));
- const auto end = in.end();
- c.insert(in.begin(), in.end());
- benchmark::DoNotOptimize(&c);
- benchmark::DoNotOptimize(&in);
- while (st.KeepRunning()) {
- for (auto it = in.begin(); it != end; ++it) {
- benchmark::DoNotOptimize(&(*c.insert(*it).first));
- }
- benchmark::ClobberMemory();
- }
-}
-
-template <class Container, class GenInputs>
-void BM_EmplaceDuplicate(benchmark::State& st, Container c, GenInputs gen) {
- auto in = gen(st.range(0));
- const auto end = in.end();
- c.insert(in.begin(), in.end());
- benchmark::DoNotOptimize(&c);
- benchmark::DoNotOptimize(&in);
- while (st.KeepRunning()) {
- for (auto it = in.begin(); it != end; ++it) {
- benchmark::DoNotOptimize(&(*c.emplace(*it).first));
- }
- benchmark::ClobberMemory();
- }
-}
-
-template <class Container, class GenInputs>
-void BM_erase_iter_in_middle(benchmark::State& st, Container, GenInputs gen) {
- auto in = gen(st.range(0));
- Container c(in.begin(), in.end());
- assert(c.size() > 2);
- for (auto _ : st) {
- auto mid = std::next(c.begin(), c.size() / 2);
- auto tmp = *mid;
- auto result = c.erase(mid); // erase an element in the middle
- benchmark::DoNotOptimize(result);
- c.push_back(std::move(tmp)); // and then push it back at the end to avoid needing a new container
- }
-}
-
-template <class Container, class GenInputs>
-void BM_erase_iter_at_start(benchmark::State& st, Container, GenInputs gen) {
- auto in = gen(st.range(0));
- Container c(in.begin(), in.end());
- assert(c.size() > 2);
- for (auto _ : st) {
- auto it = c.begin();
- auto tmp = *it;
- auto result = c.erase(it); // erase the first element
- benchmark::DoNotOptimize(result);
- c.push_back(std::move(tmp)); // and then push it back at the end to avoid needing a new container
- }
-}
-
-template <class Container, class GenInputs>
-void BM_Find(benchmark::State& st, Container c, GenInputs gen) {
- auto in = gen(st.range(0));
- c.insert(in.begin(), in.end());
- benchmark::DoNotOptimize(&(*c.begin()));
- const auto end = in.data() + in.size();
- while (st.KeepRunning()) {
- for (auto it = in.data(); it != end; ++it) {
- benchmark::DoNotOptimize(&(*c.find(*it)));
- }
- benchmark::ClobberMemory();
- }
-}
-
-template <class Container, class GenInputs>
-void BM_FindRehash(benchmark::State& st, Container c, GenInputs gen) {
- c.rehash(8);
- auto in = gen(st.range(0));
- c.insert(in.begin(), in.end());
- benchmark::DoNotOptimize(&(*c.begin()));
- const auto end = in.data() + in.size();
- while (st.KeepRunning()) {
- for (auto it = in.data(); it != end; ++it) {
- benchmark::DoNotOptimize(&(*c.find(*it)));
- }
- benchmark::ClobberMemory();
- }
-}
-
-template <class Container, class GenInputs>
-void BM_Rehash(benchmark::State& st, Container c, GenInputs gen) {
- auto in = gen(st.range(0));
- c.max_load_factor(3.0);
- c.insert(in.begin(), in.end());
- benchmark::DoNotOptimize(c);
- const auto bucket_count = c.bucket_count();
- while (st.KeepRunning()) {
- c.rehash(bucket_count + 1);
- c.rehash(bucket_count);
- benchmark::ClobberMemory();
- }
-}
-
-template <class Container, class GenInputs>
-void BM_Compare_same_container(benchmark::State& st, Container, GenInputs gen) {
- auto in = gen(st.range(0));
- Container c1(in.begin(), in.end());
- Container c2 = c1;
-
- benchmark::DoNotOptimize(&(*c1.begin()));
- benchmark::DoNotOptimize(&(*c2.begin()));
- while (st.KeepRunning()) {
- bool res = c1 == c2;
- benchmark::DoNotOptimize(&res);
- benchmark::ClobberMemory();
- }
-}
-
-template <class Container, class GenInputs>
-void BM_Compare_different_containers(benchmark::State& st, Container, GenInputs gen) {
- auto in1 = gen(st.range(0));
- auto in2 = gen(st.range(0));
- Container c1(in1.begin(), in1.end());
- Container c2(in2.begin(), in2.end());
-
- benchmark::DoNotOptimize(&(*c1.begin()));
- benchmark::DoNotOptimize(&(*c2.begin()));
- while (st.KeepRunning()) {
- bool res = c1 == c2;
- benchmark::DoNotOptimize(&res);
- benchmark::ClobberMemory();
- }
-}
-
-} // namespace ContainerBenchmarks
-
-#endif // BENCHMARK_CONTAINER_BENCHMARKS_H
diff --git a/libcxx/test/benchmarks/containers/container_benchmarks.h b/libcxx/test/benchmarks/containers/container_benchmarks.h
new file mode 100644
index 00000000000000..5d476877b0a878
--- /dev/null
+++ b/libcxx/test/benchmarks/containers/container_benchmarks.h
@@ -0,0 +1,435 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_BENCHMARKS_CONTAINERS_CONTAINER_BENCHMARKS_H
+#define TEST_BENCHMARKS_CONTAINERS_CONTAINER_BENCHMARKS_H
+
+#include <cstddef>
+#include <iterator> // for std::next
+#include <ranges> // for std::from_range
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+
+namespace ContainerBenchmarks {
+
+template <class Container>
+void DoNotOptimizeData(Container& c) {
+ if constexpr (requires { c.data(); }) {
+ benchmark::DoNotOptimize(c.data());
+ } else {
+ benchmark::DoNotOptimize(&c);
+ }
+}
+
+//
+// Sequence container operations
+//
+template <class Container>
+void BM_ctor_size(benchmark::State& st) {
+ auto size = st.range(0);
+ char buffer[sizeof(Container)];
+ for (auto _ : st) {
+ std::construct_at(reinterpret_cast<Container*>(buffer), size);
+ benchmark::DoNotOptimize(buffer);
+ st.PauseTiming();
+ std::destroy_at(reinterpret_cast<Container*>(buffer));
+ st.ResumeTiming();
+ }
+}
+
+template <class Container>
+void BM_ctor_size_value(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ const auto size = st.range(0);
+ ValueType value{};
+ benchmark::DoNotOptimize(value);
+ char buffer[sizeof(Container)];
+ for (auto _ : st) {
+ std::construct_at(reinterpret_cast<Container*>(buffer), size, value);
+ benchmark::DoNotOptimize(buffer);
+ st.PauseTiming();
+ std::destroy_at(reinterpret_cast<Container*>(buffer));
+ st.ResumeTiming();
+ }
+}
+
+template <class Container>
+void BM_ctor_iter_iter(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ const auto size = st.range(0);
+ std::vector<ValueType> in(size);
+ const auto begin = in.begin();
+ const auto end = in.end();
+ benchmark::DoNotOptimize(in);
+ char buffer[sizeof(Container)];
+ for (auto _ : st) {
+ std::construct_at(reinterpret_cast<Container*>(buffer), begin, end);
+ benchmark::DoNotOptimize(buffer);
+ st.PauseTiming();
+ std::destroy_at(reinterpret_cast<Container*>(buffer));
+ st.ResumeTiming();
+ }
+}
+
+#if TEST_STD_VER >= 23
+template <class Container>
+void BM_ctor_from_range(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ const auto size = st.range(0);
+ std::vector<ValueType> in(size);
+ benchmark::DoNotOptimize(in);
+ char buffer[sizeof(Container)];
+ for (auto _ : st) {
+ std::construct_at(reinterpret_cast<Container*>(buffer), std::from_range, in);
+ benchmark::DoNotOptimize(buffer);
+ st.PauseTiming();
+ std::destroy_at(reinterpret_cast<Container*>(buffer));
+ st.ResumeTiming();
+ }
+}
+#endif
+
+template <class Container>
+void BM_ctor_copy(benchmark::State& st) {
+ auto size = st.range(0);
+ Container c(size);
+ char buffer[sizeof(Container)];
+ for (auto _ : st) {
+ std::construct_at(reinterpret_cast<Container*>(buffer), c);
+ benchmark::DoNotOptimize(buffer);
+ st.PauseTiming();
+ std::destroy_at(reinterpret_cast<Container*>(buffer));
+ st.ResumeTiming();
+ }
+}
+
+template <class Container>
+void BM_assignment(benchmark::State& st) {
+ auto size = st.range(0);
+ Container c1;
+ Container c2(size);
+ for (auto _ : st) {
+ c1 = c2;
+ DoNotOptimizeData(c1);
+ DoNotOptimizeData(c2);
+ }
+}
+
+template <typename Container>
+void BM_assign_inputiter(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ auto size = st.range(0);
+ std::vector<ValueType> inputs(size);
+ Container c(inputs.begin(), inputs.end());
+ DoNotOptimizeData(c);
+ DoNotOptimizeData(inputs);
+ ValueType* first = inputs.data();
+ ValueType* last = inputs.data() + inputs.size();
+
+ for (auto _ : st) {
+ c.assign(cpp17_input_iterator(first), cpp17_input_iterator(last));
+ benchmark::ClobberMemory();
+ }
+}
+
+template <class Container>
+void BM_insert_middle(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ const int count = st.range(0);
+ std::vector<ValueType> inputs(count);
+ Container c(inputs.begin(), inputs.end());
+ DoNotOptimizeData(c);
+
+ ValueType value{};
+ benchmark::DoNotOptimize(value);
+
+ auto mid = std::next(c.begin(), count / 2);
+ for (auto _ : st) {
+ auto inserted = c.insert(mid, value);
+ DoNotOptimizeData(c);
+
+ st.PauseTiming();
+ mid = c.erase(inserted);
+ st.ResumeTiming();
+ }
+}
+
+template <class Container>
+void BM_insert_start(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ const int count = st.range(0);
+ std::vector<ValueType> inputs(count);
+ Container c(inputs.begin(), inputs.end());
+ DoNotOptimizeData(c);
+
+ ValueType value{};
+ benchmark::DoNotOptimize(value);
+
+ for (auto _ : st) {
+ auto inserted = c.insert(c.begin(), value);
+ DoNotOptimizeData(c);
+
+ st.PauseTiming();
+ c.erase(inserted);
+ st.ResumeTiming();
+ }
+}
+
+template <class Container>
+void BM_erase_middle(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ const int count = st.range(0);
+ std::vector<ValueType> inputs(count);
+ Container c(inputs.begin(), inputs.end());
+ DoNotOptimizeData(c);
+
+ ValueType value{};
+ benchmark::DoNotOptimize(value);
+
+ auto mid = std::next(c.begin(), count / 2);
+ for (auto _ : st) {
+ c.erase(mid);
+ DoNotOptimizeData(c);
+
+ st.PauseTiming();
+ c.insert(c.end(), value); // re-insert an element at the end to avoid needing a new container
+ mid = std::next(c.begin(), c.size() / 2);
+ st.ResumeTiming();
+ }
+}
+
+template <class Container>
+void BM_erase_start(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ const int count = st.range(0);
+ std::vector<ValueType> inputs(count);
+ Container c(inputs.begin(), inputs.end());
+ DoNotOptimizeData(c);
+
+ ValueType value{};
+ benchmark::DoNotOptimize(value);
+ for (auto _ : st) {
+ c.erase(c.begin());
+ DoNotOptimizeData(c);
+
+ st.PauseTiming();
+ c.insert(c.end(), value); // re-insert an element at the end to avoid needing a new container
+ st.ResumeTiming();
+ }
+}
+
+template <class Container>
+void sequence_container_benchmarks(std::string container) {
+ benchmark::RegisterBenchmark(container + "::ctor(size)", BM_ctor_size<Container>)->Arg(1024);
+ benchmark::RegisterBenchmark(container + "::ctor(size, value_type)", BM_ctor_size_value<Container>)->Arg(1024);
+ benchmark::RegisterBenchmark(container + "::ctor(Iterator, Iterator)", BM_ctor_iter_iter<Container>)->Arg(1024);
+#if TEST_STD_VER >= 23
+ benchmark::RegisterBenchmark(container + "::ctor(Range)", BM_ctor_from_range<Container>)->Arg(1024);
+#endif
+ benchmark::RegisterBenchmark(container + "::ctor(const&)", BM_ctor_copy<Container>)->Arg(1024);
+ benchmark::RegisterBenchmark(container + "::operator=", BM_assignment<Container>)->Arg(1024);
+ benchmark::RegisterBenchmark(container + "::assign(input-iter, input-iter)", BM_assign_inputiter<Container>)
+ ->Arg(1024);
+ benchmark::RegisterBenchmark(container + "::insert(start)", BM_insert_start<Container>)->Arg(1024);
+ benchmark::RegisterBenchmark(container + "::insert(middle)", BM_insert_middle<Container>)->Arg(1024);
+ benchmark::RegisterBenchmark(container + "::erase(start)", BM_erase_start<Container>)->Arg(1024);
+ benchmark::RegisterBenchmark(container + "::erase(middle)", BM_erase_middle<Container>)->Arg(1024);
+}
+
+//
+// "Back-insertable" sequence container operations
+//
+template <class Container>
+void BM_push_back(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ const int count = st.range(0);
+ std::vector<ValueType> inputs(count);
+ benchmark::DoNotOptimize(inputs);
+
+ Container c;
+ DoNotOptimizeData(c);
+ while (st.KeepRunningBatch(count)) {
+ c.clear();
+ for (int i = 0; i != count; ++i) {
+ c.push_back(inputs[i]);
+ }
+ DoNotOptimizeData(c);
+ }
+}
+
+template <class Container>
+void BM_push_back_with_reserve(benchmark::State& st) {
+ using ValueType = typename Container::value_type;
+ const int count = st.range(0);
+ std::vector<ValueType> inputs(count);
+ benchmark::DoNotOptimize(inputs);
+
+ Container c;
+ c.reserve(count);
+ DoNotOptimizeData(c);
+ while (st.KeepRunningBatch(count)) {
+ c.clear();
+ for (int i = 0; i != count; ++i) {
+ c.push_back(inputs[i]);
+ }
+ DoNotOptimizeData(c);
+ }
+}
+
+template <class Container>
+void back_insertable_container_benchmarks(std::string container) {
+ sequence_container_benchmarks<Container>(container);
+ benchmark::RegisterBenchmark(container + "::push_back()", BM_push_back<Container>)->Arg(1024);
+ if constexpr (requires(Container c) { c.reserve(0); }) {
+ benchmark::RegisterBenchmark(container + "::push_back() (with reserve)", BM_push_back_with_reserve<Container>)
+ ->Arg(1024);
+ }
+}
+
+//
+// Misc operations
+//
+template <class Container, class GenInputs>
+void BM_InsertValue(benchmark::State& st, Container c, GenInputs gen) {
+ auto in = gen(st.range(0));
+ const auto end = in.end();
+ while (st.KeepRunning()) {
+ c.clear();
+ for (auto it = in.begin(); it != end; ++it) {
+ benchmark::DoNotOptimize(&(*c.insert(*it).first));
+ }
+ benchmark::ClobberMemory();
+ }
+}
+
+template <class Container, class GenInputs>
+void BM_InsertValueRehash(benchmark::State& st, Container c, GenInputs gen) {
+ auto in = gen(st.range(0));
+ const auto end = in.end();
+ while (st.KeepRunning()) {
+ c.clear();
+ c.rehash(16);
+ for (auto it = in.begin(); it != end; ++it) {
+ benchmark::DoNotOptimize(&(*c.insert(*it).first));
+ }
+ benchmark::ClobberMemory();
+ }
+}
+
+template <class Container, class GenInputs>
+void BM_InsertDuplicate(benchmark::State& st, Container c, GenInputs gen) {
+ auto in = gen(st.range(0));
+ const auto end = in.end();
+ c.insert(in.begin(), in.end());
+ benchmark::DoNotOptimize(&c);
+ benchmark::DoNotOptimize(&in);
+ while (st.KeepRunning()) {
+ for (auto it = in.begin(); it != end; ++it) {
+ benchmark::DoNotOptimize(&(*c.insert(*it).first));
+ }
+ benchmark::ClobberMemory();
+ }
+}
+
+template <class Container, class GenInputs>
+void BM_EmplaceDuplicate(benchmark::State& st, Container c, GenInputs gen) {
+ auto in = gen(st.range(0));
+ const auto end = in.end();
+ c.insert(in.begin(), in.end());
+ benchmark::DoNotOptimize(&c);
+ benchmark::DoNotOptimize(&in);
+ while (st.KeepRunning()) {
+ for (auto it = in.begin(); it != end; ++it) {
+ benchmark::DoNotOptimize(&(*c.emplace(*it).first));
+ }
+ benchmark::ClobberMemory();
+ }
+}
+
+template <class Container, class GenInputs>
+void BM_Find(benchmark::State& st, Container c, GenInputs gen) {
+ auto in = gen(st.range(0));
+ c.insert(in.begin(), in.end());
+ benchmark::DoNotOptimize(&(*c.begin()));
+ const auto end = in.data() + in.size();
+ while (st.KeepRunning()) {
+ for (auto it = in.data(); it != end; ++it) {
+ benchmark::DoNotOptimize(&(*c.find(*it)));
+ }
+ benchmark::ClobberMemory();
+ }
+}
+
+template <class Container, class GenInputs>
+void BM_FindRehash(benchmark::State& st, Container c, GenInputs gen) {
+ c.rehash(8);
+ auto in = gen(st.range(0));
+ c.insert(in.begin(), in.end());
+ benchmark::DoNotOptimize(&(*c.begin()));
+ const auto end = in.data() + in.size();
+ while (st.KeepRunning()) {
+ for (auto it = in.data(); it != end; ++it) {
+ benchmark::DoNotOptimize(&(*c.find(*it)));
+ }
+ benchmark::ClobberMemory();
+ }
+}
+
+template <class Container, class GenInputs>
+void BM_Rehash(benchmark::State& st, Container c, GenInputs gen) {
+ auto in = gen(st.range(0));
+ c.max_load_factor(3.0);
+ c.insert(in.begin(), in.end());
+ benchmark::DoNotOptimize(c);
+ const auto bucket_count = c.bucket_count();
+ while (st.KeepRunning()) {
+ c.rehash(bucket_count + 1);
+ c.rehash(bucket_count);
+ benchmark::ClobberMemory();
+ }
+}
+
+template <class Container, class GenInputs>
+void BM_Compare_same_container(benchmark::State& st, Container, GenInputs gen) {
+ auto in = gen(st.range(0));
+ Container c1(in.begin(), in.end());
+ Container c2 = c1;
+
+ benchmark::DoNotOptimize(&(*c1.begin()));
+ benchmark::DoNotOptimize(&(*c2.begin()));
+ while (st.KeepRunning()) {
+ bool res = c1 == c2;
+ benchmark::DoNotOptimize(&res);
+ benchmark::ClobberMemory();
+ }
+}
+
+template <class Container, class GenInputs>
+void BM_Compare_different_containers(benchmark::State& st, Container, GenInputs gen) {
+ auto in1 = gen(st.range(0));
+ auto in2 = gen(st.range(0));
+ Container c1(in1.begin(), in1.end());
+ Container c2(in2.begin(), in2.end());
+
+ benchmark::DoNotOptimize(&(*c1.begin()));
+ benchmark::DoNotOptimize(&(*c2.begin()));
+ while (st.KeepRunning()) {
+ bool res = c1 == c2;
+ benchmark::DoNotOptimize(&res);
+ benchmark::ClobberMemory();
+ }
+}
+
+} // namespace ContainerBenchmarks
+
+#endif // TEST_BENCHMARKS_CONTAINERS_CONTAINER_BENCHMARKS_H
diff --git a/libcxx/test/benchmarks/containers/deque.bench.cpp b/libcxx/test/benchmarks/containers/deque.bench.cpp
index 7ff1093a9391ca..f325e2723ac72f 100644
--- a/libcxx/test/benchmarks/containers/deque.bench.cpp
+++ b/libcxx/test/benchmarks/containers/deque.bench.cpp
@@ -6,50 +6,20 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: c++03, c++11, c++14, c++17
#include <deque>
#include <string>
+#include "container_benchmarks.h"
#include "benchmark/benchmark.h"
-#include "ContainerBenchmarks.h"
-#include "../GenerateInput.h"
+int main(int argc, char** argv) {
+ ContainerBenchmarks::back_insertable_container_benchmarks<std::deque<char>>("std::deque<char>");
+ ContainerBenchmarks::back_insertable_container_benchmarks<std::deque<std::string>>("std::deque<std::string>");
-using namespace ContainerBenchmarks;
-
-constexpr std::size_t TestNumInputs = 1024;
-
-BENCHMARK_CAPTURE(BM_ConstructSize, deque_byte, std::deque<unsigned char>{})->Arg(5140480);
-
-BENCHMARK_CAPTURE(BM_ConstructSizeValue, deque_byte, std::deque<unsigned char>{}, 0)->Arg(5140480);
-
-BENCHMARK_CAPTURE(BM_ConstructIterIter, deque_char, std::deque<char>{}, getRandomIntegerInputs<char>)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructIterIter, deque_size_t, std::deque<size_t>{}, getRandomIntegerInputs<size_t>)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructIterIter, deque_string, std::deque<std::string>{}, getRandomStringInputs)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructFromRange, deque_char, std::deque<char>{}, getRandomIntegerInputs<char>)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructFromRange, deque_size_t, std::deque<size_t>{}, getRandomIntegerInputs<size_t>)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructFromRange, deque_string, std::deque<std::string>{}, getRandomStringInputs)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_erase_iter_in_middle, deque_int, std::deque<int>{}, getRandomIntegerInputs<int>)
- ->Range(TestNumInputs, TestNumInputs * 10);
-BENCHMARK_CAPTURE(BM_erase_iter_in_middle, deque_string, std::deque<std::string>{}, getRandomStringInputs)
- ->Range(TestNumInputs, TestNumInputs * 10);
-
-BENCHMARK_CAPTURE(BM_erase_iter_at_start, deque_int, std::deque<int>{}, getRandomIntegerInputs<int>)
- ->Range(TestNumInputs, TestNumInputs * 10);
-BENCHMARK_CAPTURE(BM_erase_iter_at_start, deque_string, std::deque<std::string>{}, getRandomStringInputs)
- ->Range(TestNumInputs, TestNumInputs * 10);
-
-BENCHMARK_MAIN();
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/containers/list.bench.cpp b/libcxx/test/benchmarks/containers/list.bench.cpp
new file mode 100644
index 00000000000000..3d60c138ca1895
--- /dev/null
+++ b/libcxx/test/benchmarks/containers/list.bench.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <list>
+#include <string>
+
+#include "container_benchmarks.h"
+#include "benchmark/benchmark.h"
+
+int main(int argc, char** argv) {
+ ContainerBenchmarks::sequence_container_benchmarks<std::list<char>>("std::list<char>");
+ ContainerBenchmarks::sequence_container_benchmarks<std::list<std::string>>("std::list<std::string>");
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/containers/unordered_set_operations.bench.cpp b/libcxx/test/benchmarks/containers/unordered_set_operations.bench.cpp
index a8448ef5a0cfb9..ad8d0feaa04365 100644
--- a/libcxx/test/benchmarks/containers/unordered_set_operations.bench.cpp
+++ b/libcxx/test/benchmarks/containers/unordered_set_operations.bench.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: c++03, c++11, c++14, c++17
#include <cstdint>
#include <cstdlib>
@@ -17,7 +17,7 @@
#include "benchmark/benchmark.h"
-#include "ContainerBenchmarks.h"
+#include "container_benchmarks.h"
#include "../GenerateInput.h"
#include "test_macros.h"
diff --git a/libcxx/test/benchmarks/containers/vector.bench.cpp b/libcxx/test/benchmarks/containers/vector.bench.cpp
new file mode 100644
index 00000000000000..440155cfe6296e
--- /dev/null
+++ b/libcxx/test/benchmarks/containers/vector.bench.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <string>
+#include <vector>
+
+#include "container_benchmarks.h"
+#include "benchmark/benchmark.h"
+
+int main(int argc, char** argv) {
+ ContainerBenchmarks::back_insertable_container_benchmarks<std::vector<char>>("std::vector<char>");
+ ContainerBenchmarks::back_insertable_container_benchmarks<std::vector<std::string>>("std::vector<std::string>");
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+ benchmark::Shutdown();
+ return 0;
+}
diff --git a/libcxx/test/benchmarks/containers/vector_operations.bench.cpp b/libcxx/test/benchmarks/containers/vector_operations.bench.cpp
deleted file mode 100644
index 9449bed31ec38c..00000000000000
--- a/libcxx/test/benchmarks/containers/vector_operations.bench.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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, c++20
-
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-#include <deque>
-#include <functional>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "benchmark/benchmark.h"
-#include "ContainerBenchmarks.h"
-#include "../GenerateInput.h"
-
-using namespace ContainerBenchmarks;
-
-constexpr std::size_t TestNumInputs = 1024;
-
-BENCHMARK_CAPTURE(BM_ConstructSize, vector_byte, std::vector<unsigned char>{})->Arg(5140480);
-
-BENCHMARK_CAPTURE(BM_CopyConstruct, vector_int, std::vector<int>{})->Arg(5140480);
-
-BENCHMARK_CAPTURE(BM_Assignment, vector_int, std::vector<int>{})->Arg(5140480);
-
-BENCHMARK_CAPTURE(BM_ConstructSizeValue, vector_byte, std::vector<unsigned char>{}, 0)->Arg(5140480);
-
-BENCHMARK_CAPTURE(BM_ConstructIterIter, vector_char, std::vector<char>{}, getRandomIntegerInputs<char>)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructIterIter, vector_size_t, std::vector<size_t>{}, getRandomIntegerInputs<size_t>)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructIterIter, vector_string, std::vector<std::string>{}, getRandomStringInputs)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructFromRange, vector_char, std::vector<char>{}, getRandomIntegerInputs<char>)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructFromRange, vector_size_t, std::vector<size_t>{}, getRandomIntegerInputs<size_t>)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_ConstructFromRange, vector_string, std::vector<std::string>{}, getRandomStringInputs)
- ->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_Pushback_no_grow, vector_int, std::vector<int>{})->Arg(TestNumInputs);
-
-BENCHMARK_CAPTURE(BM_erase_iter_in_middle, vector_int, std::vector<int>{}, getRandomIntegerInputs<int>)
- ->Range(TestNumInputs, TestNumInputs * 10);
-BENCHMARK_CAPTURE(BM_erase_iter_in_middle, vector_string, std::vector<std::string>{}, getRandomStringInputs)
- ->Range(TestNumInputs, TestNumInputs * 10);
-
-BENCHMARK_CAPTURE(BM_erase_iter_at_start, vector_int, std::vector<int>{}, getRandomIntegerInputs<int>)
- ->Range(TestNumInputs, TestNumInputs * 10);
-BENCHMARK_CAPTURE(BM_erase_iter_at_start, vector_string, std::vector<std::string>{}, getRandomStringInputs)
- ->Range(TestNumInputs, TestNumInputs * 10);
-
-template <class T>
-void bm_grow(benchmark::State& state) {
- for (auto _ : state) {
- std::vector<T> vec;
- benchmark::DoNotOptimize(vec);
- for (size_t i = 0; i != 2048; ++i)
- vec.emplace_back();
- benchmark::DoNotOptimize(vec);
- }
-}
-BENCHMARK(bm_grow<int>);
-BENCHMARK(bm_grow<std::string>);
-BENCHMARK(bm_grow<std::unique_ptr<int>>);
-BENCHMARK(bm_grow<std::deque<int>>);
-
-BENCHMARK_CAPTURE(BM_AssignInputIterIter, vector_int, std::vector<int>{}, getRandomIntegerInputs<int>)
- ->Args({TestNumInputs, TestNumInputs});
-
-BENCHMARK_CAPTURE(
- BM_AssignInputIterIter<32>, vector_string, std::vector<std::string>{}, getRandomStringInputsWithLength)
- ->Args({TestNumInputs, TestNumInputs});
-
-BENCHMARK_CAPTURE(BM_AssignInputIterIter<100>,
- vector_vector_int,
- std::vector<std::vector<int>>{},
- getRandomIntegerInputsWithLength<int>)
- ->Args({TestNumInputs, TestNumInputs});
-
-BENCHMARK_MAIN();
More information about the libcxx-commits
mailing list