diff --git a/libcxx/test/benchmarks/GenerateInput.h b/libcxx/test/benchmarks/GenerateInput.h index 081631a32b21d..c87fd69162e9d 100644 --- a/libcxx/test/benchmarks/GenerateInput.h +++ b/libcxx/test/benchmarks/GenerateInput.h @@ -190,6 +190,7 @@ struct Generate { static T arbitrary() { return 42; } static T cheap() { return 42; } static T expensive() { return 42; } + static T random() { return getRandomInteger(std::numeric_limits::min(), std::numeric_limits::max()); } }; template <> @@ -197,6 +198,10 @@ struct Generate { static std::string arbitrary() { return "hello world"; } static std::string cheap() { return "small"; } static std::string expensive() { return std::string(256, 'x'); } + static std::string random() { + auto length = getRandomInteger(1, 1024); + return getRandomString(length); + } }; #endif // BENCHMARK_GENERATE_INPUT_H diff --git a/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h b/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h new file mode 100644 index 0000000000000..fb4455c4aa9da --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h @@ -0,0 +1,512 @@ +//===----------------------------------------------------------------------===// +// +// 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_ASSOCIATIVE_CONTAINER_BENCHMARKS_H +#define TEST_BENCHMARKS_CONTAINERS_ASSOCIATIVE_CONTAINER_BENCHMARKS_H + +#include +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "../../GenerateInput.h" + +namespace support { + +template +struct adapt_operations { + // using ValueType = ...; + // using KeyType = ...; + // static ValueType value_from_key(KeyType const& k); + // static KeyType key_from_value(ValueType const& value); + + // using InsertionResult = ...; + // static Container::iterator get_iterator(InsertionResult const&); +}; + +template +void associative_container_benchmarks(std::string container) { + using Key = typename Container::key_type; + using Value = typename Container::value_type; + + auto generate_unique_keys = [=](std::size_t n) { + std::set keys; + while (keys.size() < n) { + Key k = Generate::random(); + keys.insert(k); + } + return std::vector(keys.begin(), keys.end()); + }; + + auto make_value_types = [](std::vector const& keys) { + std::vector kv; + for (Key const& k : keys) + kv.push_back(adapt_operations::value_from_key(k)); + return kv; + }; + + auto get_key = [](Value const& v) { return adapt_operations::key_from_value(v); }; + + auto bench = [&](std::string operation, auto f) { + benchmark::RegisterBenchmark(container + "::" + operation, f)->Arg(32)->Arg(1024)->Arg(8192); + }; + + static constexpr bool is_multi_key_container = + !std::is_same_v::InsertionResult, + std::pair>; + + static constexpr bool is_ordered_container = requires(Container c, Key k) { c.lower_bound(k); }; + + // These benchmarks are structured to perform the operation being benchmarked + // a small number of times at each iteration, in order to offset the cost of + // PauseTiming() and ResumeTiming(). + static constexpr std::size_t BatchSize = 32; + + struct alignas(Container) ScratchSpace { + char storage[sizeof(Container)]; + }; + + ///////////////////////// + // Constructors + ///////////////////////// + bench("ctor(const&)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size)); + Container src(in.begin(), in.end()); + ScratchSpace c[BatchSize]; + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + new (c + i) Container(src); + benchmark::DoNotOptimize(c + i); + benchmark::ClobberMemory(); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + reinterpret_cast(c + i)->~Container(); + } + st.ResumeTiming(); + } + }); + + bench("ctor(iterator, iterator) (unsorted sequence)", [=](auto& st) { + const std::size_t size = st.range(0); + std::mt19937 randomness; + std::vector keys = generate_unique_keys(size); + std::shuffle(keys.begin(), keys.end(), randomness); + std::vector in = make_value_types(keys); + ScratchSpace c[BatchSize]; + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + new (c + i) Container(in.begin(), in.end()); + benchmark::DoNotOptimize(c + i); + benchmark::ClobberMemory(); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + reinterpret_cast(c + i)->~Container(); + } + st.ResumeTiming(); + } + }); + + bench("ctor(iterator, iterator) (sorted sequence)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector keys = generate_unique_keys(size); + std::sort(keys.begin(), keys.end()); + std::vector in = make_value_types(keys); + ScratchSpace c[BatchSize]; + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + new (c + i) Container(in.begin(), in.end()); + benchmark::DoNotOptimize(c + i); + benchmark::ClobberMemory(); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + reinterpret_cast(c + i)->~Container(); + } + st.ResumeTiming(); + } + }); + + ///////////////////////// + // Assignment + ///////////////////////// + bench("operator=(const&)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size)); + Container src(in.begin(), in.end()); + Container c[BatchSize]; + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i] = src; + benchmark::DoNotOptimize(c[i]); + benchmark::ClobberMemory(); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i].clear(); + } + st.ResumeTiming(); + } + }); + + ///////////////////////// + // Insertion + ///////////////////////// + bench("insert(value) (already present)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size)); + Value to_insert = in[in.size() / 2]; // pick any existing value + std::vector c(BatchSize, Container(in.begin(), in.end())); + typename Container::iterator inserted[BatchSize]; + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + inserted[i] = adapt_operations::get_iterator(c[i].insert(to_insert)); + benchmark::DoNotOptimize(inserted[i]); + benchmark::DoNotOptimize(c[i]); + benchmark::ClobberMemory(); + } + + if constexpr (is_multi_key_container) { + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i].erase(inserted[i]); + } + st.ResumeTiming(); + } + } + }); + + bench("insert(value) (new value)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size + 1)); + Value to_insert = in.back(); + in.pop_back(); + std::vector c(BatchSize, Container(in.begin(), in.end())); + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + auto result = c[i].insert(to_insert); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(c[i]); + benchmark::ClobberMemory(); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i].erase(get_key(to_insert)); + } + st.ResumeTiming(); + } + }); + + // The insert(hint, ...) methods are only relevant for ordered containers, and we lack + // a good way to compute a hint for unordered ones. + if constexpr (is_ordered_container) { + bench("insert(hint, value) (good hint)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size + 1)); + Value to_insert = in.back(); + in.pop_back(); + + std::vector c(BatchSize, Container(in.begin(), in.end())); + typename Container::iterator hints[BatchSize]; + for (std::size_t i = 0; i != BatchSize; ++i) { + hints[i] = c[i].lower_bound(get_key(to_insert)); + } + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + auto result = c[i].insert(hints[i], to_insert); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(c[i]); + benchmark::ClobberMemory(); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i].erase(get_key(to_insert)); + hints[i] = c[i].lower_bound(get_key(to_insert)); // refresh hints in case of invalidation + } + st.ResumeTiming(); + } + }); + + bench("insert(hint, value) (bad hint)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size + 1)); + Value to_insert = in.back(); + in.pop_back(); + std::vector c(BatchSize, Container(in.begin(), in.end())); + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + auto result = c[i].insert(c[i].begin(), to_insert); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(c[i]); + benchmark::ClobberMemory(); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i].erase(get_key(to_insert)); + } + st.ResumeTiming(); + } + }); + } + + bench("insert(iterator, iterator) (all new keys)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size + (size / 10))); + + // Populate a container with a small number of elements, that's what containers will start with. + std::vector small; + for (std::size_t i = 0; i != (size / 10); ++i) { + small.push_back(in.back()); + in.pop_back(); + } + Container c(small.begin(), small.end()); + + for ([[maybe_unused]] auto _ : st) { + c.insert(in.begin(), in.end()); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + + st.PauseTiming(); + c = Container(small.begin(), small.end()); + st.ResumeTiming(); + } + }); + + bench("insert(iterator, iterator) (half new keys)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size)); + + // Populate a container that already contains half the elements we'll try inserting, + // that's what our container will start with. + std::vector small; + for (std::size_t i = 0; i != size / 2; ++i) { + small.push_back(in.at(i * 2)); + } + Container c(small.begin(), small.end()); + + for ([[maybe_unused]] auto _ : st) { + c.insert(in.begin(), in.end()); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + + st.PauseTiming(); + c = Container(small.begin(), small.end()); + st.ResumeTiming(); + } + }); + + ///////////////////////// + // Erasure + ///////////////////////// + bench("erase(key) (existent)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size)); + Value element = in[in.size() / 2]; // pick any element + std::vector c(BatchSize, Container(in.begin(), in.end())); + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + auto result = c[i].erase(get_key(element)); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(c[i]); + benchmark::ClobberMemory(); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + c[i].insert(element); + } + st.ResumeTiming(); + } + }); + + bench("erase(key) (non-existent)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size + BatchSize)); + std::vector keys; + for (std::size_t i = 0; i != BatchSize; ++i) { + keys.push_back(get_key(in.back())); + in.pop_back(); + } + Container c(in.begin(), in.end()); + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + auto result = c.erase(keys[i]); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + } + + // no cleanup required because we erased a non-existent element + } + }); + + bench("erase(iterator)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size)); + Value element = in[in.size() / 2]; // pick any element + + std::vector c; + std::vector iterators; + for (std::size_t i = 0; i != BatchSize; ++i) { + c.push_back(Container(in.begin(), in.end())); + iterators.push_back(c[i].find(get_key(element))); + } + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + auto result = c[i].erase(iterators[i]); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(c[i]); + benchmark::ClobberMemory(); + } + + st.PauseTiming(); + for (std::size_t i = 0; i != BatchSize; ++i) { + iterators[i] = adapt_operations::get_iterator(c[i].insert(element)); + } + st.ResumeTiming(); + } + }); + + bench("erase(iterator, iterator) (erase half the container)", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size)); + Container c(in.begin(), in.end()); + + auto first = std::next(c.begin(), c.size() / 4); + auto last = std::next(c.begin(), 3 * (c.size() / 4)); + for ([[maybe_unused]] auto _ : st) { + auto result = c.erase(first, last); + benchmark::DoNotOptimize(result); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + + st.PauseTiming(); + c = Container(in.begin(), in.end()); + first = std::next(c.begin(), c.size() / 4); + last = std::next(c.begin(), 3 * (c.size() / 4)); + st.ResumeTiming(); + } + }); + + bench("clear()", [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size)); + Container c(in.begin(), in.end()); + + for ([[maybe_unused]] auto _ : st) { + c.clear(); + benchmark::DoNotOptimize(c); + benchmark::ClobberMemory(); + + st.PauseTiming(); + c = Container(in.begin(), in.end()); + st.ResumeTiming(); + } + }); + + ///////////////////////// + // Query + ///////////////////////// + auto with_existent_key = [=](auto func) { + return [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size)); + // Pick any `BatchSize` number of elements + std::vector keys; + for (std::size_t i = 0; i < in.size(); i += (in.size() / BatchSize)) { + keys.push_back(get_key(in.at(i))); + } + Container c(in.begin(), in.end()); + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + auto result = func(c, keys[i]); + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(result); + benchmark::ClobberMemory(); + } + } + }; + }; + + auto with_nonexistent_key = [=](auto func) { + return [=](auto& st) { + const std::size_t size = st.range(0); + std::vector in = make_value_types(generate_unique_keys(size + BatchSize)); + std::vector keys; + for (std::size_t i = 0; i != BatchSize; ++i) { + keys.push_back(get_key(in.back())); + in.pop_back(); + } + Container c(in.begin(), in.end()); + + while (st.KeepRunningBatch(BatchSize)) { + for (std::size_t i = 0; i != BatchSize; ++i) { + auto result = func(c, keys[i]); + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(result); + benchmark::ClobberMemory(); + } + } + }; + }; + + auto find = [](Container const& c, Key const& key) { return c.find(key); }; + bench("find(key) (existent)", with_existent_key(find)); + bench("find(key) (non-existent)", with_nonexistent_key(find)); + + auto count = [](Container const& c, Key const& key) { return c.count(key); }; + bench("count(key) (existent)", with_existent_key(count)); + bench("count(key) (non-existent)", with_nonexistent_key(count)); + + auto contains = [](Container const& c, Key const& key) { return c.contains(key); }; + bench("contains(key) (existent)", with_existent_key(contains)); + bench("contains(key) (non-existent)", with_nonexistent_key(contains)); + + if constexpr (is_ordered_container) { + auto lower_bound = [](Container const& c, Key const& key) { return c.lower_bound(key); }; + bench("lower_bound(key) (existent)", with_existent_key(lower_bound)); + bench("lower_bound(key) (non-existent)", with_nonexistent_key(lower_bound)); + + auto upper_bound = [](Container const& c, Key const& key) { return c.upper_bound(key); }; + bench("upper_bound(key) (existent)", with_existent_key(upper_bound)); + bench("upper_bound(key) (non-existent)", with_nonexistent_key(upper_bound)); + + auto equal_range = [](Container const& c, Key const& key) { return c.equal_range(key); }; + bench("equal_range(key) (existent)", with_existent_key(equal_range)); + bench("equal_range(key) (non-existent)", with_nonexistent_key(equal_range)); + } +} + +} // namespace support + +#endif // TEST_BENCHMARKS_CONTAINERS_ASSOCIATIVE_CONTAINER_BENCHMARKS_H diff --git a/libcxx/test/benchmarks/containers/associative/flat_map.bench.cpp b/libcxx/test/benchmarks/containers/associative/flat_map.bench.cpp new file mode 100644 index 0000000000000..82902d50f31e6 --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/flat_map.bench.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +#include +#include + +#include "associative_container_benchmarks.h" +#include "../../GenerateInput.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::flat_map::value_type; + using KeyType = typename std::flat_map::key_type; + static ValueType value_from_key(KeyType const& k) { return {k, Generate::arbitrary()}; } + static KeyType key_from_value(ValueType const& value) { return value.first; } + + using InsertionResult = std::pair::iterator, bool>; + static auto get_iterator(InsertionResult const& result) { return result.first; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::flat_map"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/associative/flat_multimap.bench.cpp b/libcxx/test/benchmarks/containers/associative/flat_multimap.bench.cpp new file mode 100644 index 0000000000000..f752f79b3b454 --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/flat_multimap.bench.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +#include + +#include "associative_container_benchmarks.h" +#include "../../GenerateInput.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::flat_multimap::value_type; + using KeyType = typename std::flat_multimap::key_type; + static ValueType value_from_key(KeyType const& k) { return {k, Generate::arbitrary()}; } + static KeyType key_from_value(ValueType const& value) { return value.first; } + + using InsertionResult = typename std::flat_multimap::iterator; + static auto get_iterator(InsertionResult const& result) { return result; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::flat_multimap"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/associative/map.bench.cpp b/libcxx/test/benchmarks/containers/associative/map.bench.cpp new file mode 100644 index 0000000000000..cee669ae0a667 --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/map.bench.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "associative_container_benchmarks.h" +#include "../../GenerateInput.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::map::value_type; + using KeyType = typename std::map::key_type; + static ValueType value_from_key(KeyType const& k) { return {k, Generate::arbitrary()}; } + static KeyType key_from_value(ValueType const& value) { return value.first; } + + using InsertionResult = std::pair::iterator, bool>; + static auto get_iterator(InsertionResult const& result) { return result.first; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::map"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/associative/multimap.bench.cpp b/libcxx/test/benchmarks/containers/associative/multimap.bench.cpp new file mode 100644 index 0000000000000..6ae93f06aa363 --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/multimap.bench.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "associative_container_benchmarks.h" +#include "../../GenerateInput.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::multimap::value_type; + using KeyType = typename std::multimap::key_type; + static ValueType value_from_key(KeyType const& k) { return {k, Generate::arbitrary()}; } + static KeyType key_from_value(ValueType const& value) { return value.first; } + + using InsertionResult = typename std::multimap::iterator; + static auto get_iterator(InsertionResult const& result) { return result; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::multimap"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/associative/multiset.bench.cpp b/libcxx/test/benchmarks/containers/associative/multiset.bench.cpp new file mode 100644 index 0000000000000..894f159a52e4a --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/multiset.bench.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "associative_container_benchmarks.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::multiset::value_type; + using KeyType = typename std::multiset::key_type; + static ValueType value_from_key(KeyType const& k) { return k; } + static KeyType key_from_value(ValueType const& value) { return value; } + + using InsertionResult = typename std::multiset::iterator; + static auto get_iterator(InsertionResult const& result) { return result; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::multiset"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/associative/set.bench.cpp b/libcxx/test/benchmarks/containers/associative/set.bench.cpp new file mode 100644 index 0000000000000..6b7b142c792ba --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/set.bench.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "associative_container_benchmarks.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::set::value_type; + using KeyType = typename std::set::key_type; + static ValueType value_from_key(KeyType const& k) { return k; } + static KeyType key_from_value(ValueType const& value) { return value; } + + using InsertionResult = std::pair::iterator, bool>; + static auto get_iterator(InsertionResult const& result) { return result.first; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::set"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/associative/unordered_map.bench.cpp b/libcxx/test/benchmarks/containers/associative/unordered_map.bench.cpp new file mode 100644 index 0000000000000..57adec2d214d4 --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/unordered_map.bench.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "associative_container_benchmarks.h" +#include "../../GenerateInput.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::unordered_map::value_type; + using KeyType = typename std::unordered_map::key_type; + static ValueType value_from_key(KeyType const& k) { return {k, Generate::arbitrary()}; } + static KeyType key_from_value(ValueType const& value) { return value.first; } + + using InsertionResult = std::pair::iterator, bool>; + static auto get_iterator(InsertionResult const& result) { return result.first; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::unordered_map"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/associative/unordered_multimap.bench.cpp b/libcxx/test/benchmarks/containers/associative/unordered_multimap.bench.cpp new file mode 100644 index 0000000000000..8738ca4bf9f0c --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/unordered_multimap.bench.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "associative_container_benchmarks.h" +#include "../../GenerateInput.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::unordered_multimap::value_type; + using KeyType = typename std::unordered_multimap::key_type; + static ValueType value_from_key(KeyType const& k) { return {k, Generate::arbitrary()}; } + static KeyType key_from_value(ValueType const& value) { return value.first; } + + using InsertionResult = typename std::unordered_multimap::iterator; + static auto get_iterator(InsertionResult const& result) { return result; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::unordered_multimap"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/associative/unordered_multiset.bench.cpp b/libcxx/test/benchmarks/containers/associative/unordered_multiset.bench.cpp new file mode 100644 index 0000000000000..4888b01bfeba0 --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/unordered_multiset.bench.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "associative_container_benchmarks.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::unordered_multiset::value_type; + using KeyType = typename std::unordered_multiset::key_type; + static ValueType value_from_key(KeyType const& k) { return k; } + static KeyType key_from_value(ValueType const& value) { return value; } + + using InsertionResult = typename std::unordered_multiset::iterator; + static auto get_iterator(InsertionResult const& result) { return result; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::unordered_multiset"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/associative/unordered_set.bench.cpp b/libcxx/test/benchmarks/containers/associative/unordered_set.bench.cpp new file mode 100644 index 0000000000000..56420bdaadfbf --- /dev/null +++ b/libcxx/test/benchmarks/containers/associative/unordered_set.bench.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "associative_container_benchmarks.h" +#include "benchmark/benchmark.h" + +template +struct support::adapt_operations> { + using ValueType = typename std::unordered_set::value_type; + using KeyType = typename std::unordered_set::key_type; + static ValueType value_from_key(KeyType const& k) { return k; } + static KeyType key_from_value(ValueType const& value) { return value; } + + using InsertionResult = std::pair::iterator, bool>; + static auto get_iterator(InsertionResult const& result) { return result.first; } +}; + +int main(int argc, char** argv) { + support::associative_container_benchmarks>("std::unordered_set"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/map.bench.cpp b/libcxx/test/benchmarks/containers/map.bench.cpp deleted file mode 100644 index e37c7d8d55163..0000000000000 --- a/libcxx/test/benchmarks/containers/map.bench.cpp +++ /dev/null @@ -1,949 +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 - -#include -#include -#include -#include -#include - -#include "../CartesianBenchmarks.h" -#include "benchmark/benchmark.h" -#include "test_macros.h" - -// When VALIDATE is defined the benchmark will run to validate the benchmarks. -// The time taken by several operations depend on whether or not an element -// exists. To avoid errors in the benchmark these operations have a validation -// mode to test the benchmark. Since they are not meant to be benchmarked the -// number of sizes tested is limited to 1. -// #define VALIDATE - -namespace { - -enum class Mode { Hit, Miss }; - -struct AllModes : EnumValuesAsTuple { - static constexpr const char* Names[] = {"ExistingElement", "NewElement"}; -}; - -// The positions of the hints to pick: -// - Begin picks the first item. The item cannot be put before this element. -// - Thrid picks the third item. This is just an element with a valid entry -// before and after it. -// - Correct contains the correct hint. -// - End contains a hint to the end of the map. -enum class Hint { Begin, Third, Correct, End }; -struct AllHints : EnumValuesAsTuple { - static constexpr const char* Names[] = {"Begin", "Third", "Correct", "End"}; -}; - -enum class Order { Sorted, Random }; -struct AllOrders : EnumValuesAsTuple { - static constexpr const char* Names[] = {"Sorted", "Random"}; -}; - -struct TestSets { - std::vector Keys; - std::vector > Maps; - std::vector::const_iterator> > Hints; -}; - -enum class Shuffle { None, Keys, Hints }; - -TestSets makeTestingSets(size_t MapSize, Mode mode, Shuffle shuffle, size_t max_maps) { - /* - * The shuffle does not retain the random number generator to use the same - * set of random numbers for every iteration. - */ - TestSets R; - - int MapCount = std::min(max_maps, 1000000 / MapSize); - - for (uint64_t I = 0; I < MapSize; ++I) { - R.Keys.push_back(mode == Mode::Hit ? 2 * I + 2 : 2 * I + 1); - } - if (shuffle == Shuffle::Keys) - std::shuffle(R.Keys.begin(), R.Keys.end(), std::mt19937()); - - for (int M = 0; M < MapCount; ++M) { - auto& map = R.Maps.emplace_back(); - auto& hints = R.Hints.emplace_back(); - for (uint64_t I = 0; I < MapSize; ++I) { - hints.push_back(map.insert(std::make_pair(2 * I + 2, 0)).first); - } - if (shuffle == Shuffle::Hints) - std::shuffle(hints.begin(), hints.end(), std::mt19937()); - } - - return R; -} - -struct Base { - size_t MapSize; - Base(size_t T) : MapSize(T) {} - - std::string baseName() const { return "_MapSize=" + std::to_string(MapSize); } -}; - -//*******************************************************************| -// Member functions | -//*******************************************************************| - -struct ConstructorDefault { - void run(benchmark::State& State) const { - for (auto _ : State) { - benchmark::DoNotOptimize(std::map()); - } - } - - std::string name() const { return "BM_ConstructorDefault"; } -}; - -struct ConstructorIterator : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1); - auto& Map = Data.Maps.front(); - while (State.KeepRunningBatch(MapSize)) { -#ifndef VALIDATE - benchmark::DoNotOptimize(std::map(Map.begin(), Map.end())); -#else - std::map M{Map.begin(), Map.end()}; - if (M != Map) - State.SkipWithError("Map copy not identical"); -#endif - } - } - - std::string name() const { return "BM_ConstructorIterator" + baseName(); } -}; - -struct ConstructorCopy : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1); - auto& Map = Data.Maps.front(); - while (State.KeepRunningBatch(MapSize)) { -#ifndef VALIDATE - std::map M(Map); - benchmark::DoNotOptimize(M); -#else - std::map M(Map); - if (M != Map) - State.SkipWithError("Map copy not identical"); -#endif - } - } - - std::string name() const { return "BM_ConstructorCopy" + baseName(); } -}; - -struct ConstructorMove : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (auto& Map : Data.Maps) { - std::map M(std::move(Map)); - benchmark::DoNotOptimize(M); - } - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - std::string name() const { return "BM_ConstructorMove" + baseName(); } -}; - -//*******************************************************************| -// Capacity | -//*******************************************************************| - -struct Empty : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1); - auto& Map = Data.Maps.front(); - for (auto _ : State) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.empty()); -#else - if (Map.empty()) - State.SkipWithError("Map contains an invalid number of elements."); -#endif - } - } - - std::string name() const { return "BM_Empty" + baseName(); } -}; - -struct Size : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1); - auto& Map = Data.Maps.front(); - for (auto _ : State) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.size()); -#else - if (Map.size() != MapSize) - State.SkipWithError("Map contains an invalid number of elements."); -#endif - } - } - - std::string name() const { return "BM_Size" + baseName(); } -}; - -//*******************************************************************| -// Modifiers | -//*******************************************************************| - -struct Clear : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (auto& Map : Data.Maps) { - Map.clear(); - benchmark::DoNotOptimize(Map); - } - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - std::string name() const { return "BM_Clear" + baseName(); } -}; - -template -struct Insert : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (auto& Map : Data.Maps) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.insert(std::make_pair(K, 1))); -#else - bool Inserted = Map.insert(std::make_pair(K, 1)).second; - if (Mode() == ::Mode::Hit) { - if (Inserted) - State.SkipWithError("Inserted a duplicate element"); - } else { - if (!Inserted) - State.SkipWithError("Failed to insert e new element"); - } -#endif - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - std::string name() const { return "BM_Insert" + baseName() + Mode::name() + Order::name(); } -}; - -template -struct InsertHint : Base { - using Base::Base; - - template < ::Hint hint> - typename std::enable_if::type run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (size_t I = 0; I < Data.Maps.size(); ++I) { - auto& Map = Data.Maps[I]; - auto H = Data.Hints[I].begin(); - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.insert(*H, std::make_pair(K, 1))); -#else - auto Inserted = Map.insert(*H, std::make_pair(K, 1)); - if (Mode() == ::Mode::Hit) { - if (Inserted != *H) - State.SkipWithError("Inserted a duplicate element"); - } else { - if (++Inserted != *H) - State.SkipWithError("Failed to insert a new element"); - } -#endif - ++H; - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - template < ::Hint hint> - typename std::enable_if::type run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (size_t I = 0; I < Data.Maps.size(); ++I) { - auto& Map = Data.Maps[I]; - auto Third = *(Data.Hints[I].begin() + 2); - for (auto K : Data.Keys) { - auto Itor = hint == ::Hint::Begin ? Map.begin() : hint == ::Hint::Third ? Third : Map.end(); -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.insert(Itor, std::make_pair(K, 1))); -#else - size_t Size = Map.size(); - Map.insert(Itor, std::make_pair(K, 1)); - if (Mode() == ::Mode::Hit) { - if (Size != Map.size()) - State.SkipWithError("Inserted a duplicate element"); - } else { - if (Size + 1 != Map.size()) - State.SkipWithError("Failed to insert a new element"); - } -#endif - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - void run(benchmark::State& State) const { - static constexpr auto h = Hint(); - run(State); - } - - std::string name() const { return "BM_InsertHint" + baseName() + Mode::name() + Hint::name(); } -}; - -template -struct InsertAssign : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (auto& Map : Data.Maps) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.insert_or_assign(K, 1)); -#else - bool Inserted = Map.insert_or_assign(K, 1).second; - if (Mode() == ::Mode::Hit) { - if (Inserted) - State.SkipWithError("Inserted a duplicate element"); - } else { - if (!Inserted) - State.SkipWithError("Failed to insert e new element"); - } -#endif - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - std::string name() const { return "BM_InsertAssign" + baseName() + Mode::name() + Order::name(); } -}; - -template -struct InsertAssignHint : Base { - using Base::Base; - - template < ::Hint hint> - typename std::enable_if::type run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (size_t I = 0; I < Data.Maps.size(); ++I) { - auto& Map = Data.Maps[I]; - auto H = Data.Hints[I].begin(); - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.insert_or_assign(*H, K, 1)); -#else - auto Inserted = Map.insert_or_assign(*H, K, 1); - if (Mode() == ::Mode::Hit) { - if (Inserted != *H) - State.SkipWithError("Inserted a duplicate element"); - } else { - if (++Inserted != *H) - State.SkipWithError("Failed to insert a new element"); - } -#endif - ++H; - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - template < ::Hint hint> - typename std::enable_if::type run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (size_t I = 0; I < Data.Maps.size(); ++I) { - auto& Map = Data.Maps[I]; - auto Third = *(Data.Hints[I].begin() + 2); - for (auto K : Data.Keys) { - auto Itor = hint == ::Hint::Begin ? Map.begin() : hint == ::Hint::Third ? Third : Map.end(); -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.insert_or_assign(Itor, K, 1)); -#else - size_t Size = Map.size(); - Map.insert_or_assign(Itor, K, 1); - if (Mode() == ::Mode::Hit) { - if (Size != Map.size()) - State.SkipWithError("Inserted a duplicate element"); - } else { - if (Size + 1 != Map.size()) - State.SkipWithError("Failed to insert a new element"); - } -#endif - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - void run(benchmark::State& State) const { - static constexpr auto h = Hint(); - run(State); - } - - std::string name() const { return "BM_InsertAssignHint" + baseName() + Mode::name() + Hint::name(); } -}; - -template -struct Emplace : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (auto& Map : Data.Maps) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.emplace(K, 1)); -#else - bool Inserted = Map.emplace(K, 1).second; - if (Mode() == ::Mode::Hit) { - if (Inserted) - State.SkipWithError("Emplaced a duplicate element"); - } else { - if (!Inserted) - State.SkipWithError("Failed to emplace a new element"); - } -#endif - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - std::string name() const { return "BM_Emplace" + baseName() + Mode::name() + Order::name(); } -}; - -template -struct EmplaceHint : Base { - using Base::Base; - - template < ::Hint hint> - typename std::enable_if::type run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (size_t I = 0; I < Data.Maps.size(); ++I) { - auto& Map = Data.Maps[I]; - auto H = Data.Hints[I].begin(); - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.emplace_hint(*H, K, 1)); -#else - auto Inserted = Map.emplace_hint(*H, K, 1); - if (Mode() == ::Mode::Hit) { - if (Inserted != *H) - State.SkipWithError("Emplaced a duplicate element"); - } else { - if (++Inserted != *H) - State.SkipWithError("Failed to emplace a new element"); - } -#endif - ++H; - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - template < ::Hint hint> - typename std::enable_if::type run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (size_t I = 0; I < Data.Maps.size(); ++I) { - auto& Map = Data.Maps[I]; - auto Third = *(Data.Hints[I].begin() + 2); - for (auto K : Data.Keys) { - auto Itor = hint == ::Hint::Begin ? Map.begin() : hint == ::Hint::Third ? Third : Map.end(); -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.emplace_hint(Itor, K, 1)); -#else - size_t Size = Map.size(); - Map.emplace_hint(Itor, K, 1); - if (Mode() == ::Mode::Hit) { - if (Size != Map.size()) - State.SkipWithError("Emplaced a duplicate element"); - } else { - if (Size + 1 != Map.size()) - State.SkipWithError("Failed to emplace a new element"); - } -#endif - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - void run(benchmark::State& State) const { - static constexpr auto h = Hint(); - run(State); - } - - std::string name() const { return "BM_EmplaceHint" + baseName() + Mode::name() + Hint::name(); } -}; - -template -struct TryEmplace : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (auto& Map : Data.Maps) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.try_emplace(K, 1)); -#else - bool Inserted = Map.try_emplace(K, 1).second; - if (Mode() == ::Mode::Hit) { - if (Inserted) - State.SkipWithError("Emplaced a duplicate element"); - } else { - if (!Inserted) - State.SkipWithError("Failed to emplace a new element"); - } -#endif - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - std::string name() const { return "BM_TryEmplace" + baseName() + Mode::name() + Order::name(); } -}; - -template -struct TryEmplaceHint : Base { - using Base::Base; - - template < ::Hint hint> - typename std::enable_if::type run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (size_t I = 0; I < Data.Maps.size(); ++I) { - auto& Map = Data.Maps[I]; - auto H = Data.Hints[I].begin(); - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.try_emplace(*H, K, 1)); -#else - auto Inserted = Map.try_emplace(*H, K, 1); - if (Mode() == ::Mode::Hit) { - if (Inserted != *H) - State.SkipWithError("Emplaced a duplicate element"); - } else { - if (++Inserted != *H) - State.SkipWithError("Failed to emplace a new element"); - } -#endif - ++H; - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - template < ::Hint hint> - typename std::enable_if::type run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (size_t I = 0; I < Data.Maps.size(); ++I) { - auto& Map = Data.Maps[I]; - auto Third = *(Data.Hints[I].begin() + 2); - for (auto K : Data.Keys) { - auto Itor = hint == ::Hint::Begin ? Map.begin() : hint == ::Hint::Third ? Third : Map.end(); -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.try_emplace(Itor, K, 1)); -#else - size_t Size = Map.size(); - Map.try_emplace(Itor, K, 1); - if (Mode() == ::Mode::Hit) { - if (Size != Map.size()) - State.SkipWithError("Emplaced a duplicate element"); - } else { - if (Size + 1 != Map.size()) - State.SkipWithError("Failed to emplace a new element"); - } -#endif - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - void run(benchmark::State& State) const { - static constexpr auto h = Hint(); - run(State); - } - - std::string name() const { return "BM_TryEmplaceHint" + baseName() + Mode::name() + Hint::name(); } -}; - -template -struct Erase : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (auto& Map : Data.Maps) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.erase(K)); -#else - size_t I = Map.erase(K); - if (Mode() == ::Mode::Hit) { - if (I == 0) - State.SkipWithError("Did not find the existing element"); - } else { - if (I == 1) - State.SkipWithError("Did find the non-existing element"); - } -#endif - } - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - std::string name() const { return "BM_Erase" + baseName() + Mode::name() + Order::name(); } -}; - -template -struct EraseIterator : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = - makeTestingSets(MapSize, Mode::Hit, Order::value == ::Order::Random ? Shuffle::Hints : Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (size_t I = 0; I < Data.Maps.size(); ++I) { - auto& Map = Data.Maps[I]; - for (auto H : Data.Hints[I]) { - benchmark::DoNotOptimize(Map.erase(H)); - } -#ifdef VALIDATE - if (!Map.empty()) - State.SkipWithError("Did not erase the entire map"); -#endif - } - - State.PauseTiming(); - Data = - makeTestingSets(MapSize, Mode::Hit, Order::value == ::Order::Random ? Shuffle::Hints : Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - std::string name() const { return "BM_EraseIterator" + baseName() + Order::name(); } -}; - -struct EraseRange : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000); - while (State.KeepRunningBatch(MapSize * Data.Maps.size())) { - for (auto& Map : Data.Maps) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.erase(Map.begin(), Map.end())); -#else - Map.erase(Map.begin(), Map.end()); - if (!Map.empty()) - State.SkipWithError("Did not erase the entire map"); -#endif - } - - State.PauseTiming(); - Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000); - State.ResumeTiming(); - } - } - - std::string name() const { return "BM_EraseRange" + baseName(); } -}; - -//*******************************************************************| -// Lookup | -//*******************************************************************| - -template -struct Count : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1); - auto& Map = Data.Maps.front(); - while (State.KeepRunningBatch(MapSize)) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.count(K)); -#else - size_t I = Map.count(K); - if (Mode() == ::Mode::Hit) { - if (I == 0) - State.SkipWithError("Did not find the existing element"); - } else { - if (I == 1) - State.SkipWithError("Did find the non-existing element"); - } -#endif - } - } - } - - std::string name() const { return "BM_Count" + baseName() + Mode::name() + Order::name(); } -}; - -template -struct Find : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1); - auto& Map = Data.Maps.front(); - while (State.KeepRunningBatch(MapSize)) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.find(K)); -#else - auto Itor = Map.find(K); - if (Mode() == ::Mode::Hit) { - if (Itor == Map.end()) - State.SkipWithError("Did not find the existing element"); - } else { - if (Itor != Map.end()) - State.SkipWithError("Did find the non-existing element"); - } -#endif - } - } - } - - std::string name() const { return "BM_Find" + baseName() + Mode::name() + Order::name(); } -}; - -template -struct EqualRange : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1); - auto& Map = Data.Maps.front(); - while (State.KeepRunningBatch(MapSize)) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.equal_range(K)); -#else - auto Range = Map.equal_range(K); - if (Mode() == ::Mode::Hit) { - // Adjust validation for the last element. - auto Key = K; - if (Range.second == Map.end() && K == 2 * MapSize) { - --Range.second; - Key -= 2; - } - if (Range.first == Map.end() || Range.first->first != K || Range.second == Map.end() || - Range.second->first - 2 != Key) - State.SkipWithError("Did not find the existing element"); - } else { - if (Range.first == Map.end() || Range.first->first - 1 != K || Range.second == Map.end() || - Range.second->first - 1 != K) - State.SkipWithError("Did find the non-existing element"); - } -#endif - } - } - } - - std::string name() const { return "BM_EqualRange" + baseName() + Mode::name() + Order::name(); } -}; - -template -struct LowerBound : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1); - auto& Map = Data.Maps.front(); - while (State.KeepRunningBatch(MapSize)) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.lower_bound(K)); -#else - auto Itor = Map.lower_bound(K); - if (Mode() == ::Mode::Hit) { - if (Itor == Map.end() || Itor->first != K) - State.SkipWithError("Did not find the existing element"); - } else { - if (Itor == Map.end() || Itor->first - 1 != K) - State.SkipWithError("Did find the non-existing element"); - } -#endif - } - } - } - - std::string name() const { return "BM_LowerBound" + baseName() + Mode::name() + Order::name(); } -}; - -template -struct UpperBound : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(MapSize, Mode(), Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1); - auto& Map = Data.Maps.front(); - while (State.KeepRunningBatch(MapSize)) { - for (auto K : Data.Keys) { -#ifndef VALIDATE - benchmark::DoNotOptimize(Map.upper_bound(K)); -#else - std::map::iterator Itor = Map.upper_bound(K); - if (Mode() == ::Mode::Hit) { - // Adjust validation for the last element. - auto Key = K; - if (Itor == Map.end() && K == 2 * MapSize) { - --Itor; - Key -= 2; - } - if (Itor == Map.end() || Itor->first - 2 != Key) - State.SkipWithError("Did not find the existing element"); - } else { - if (Itor == Map.end() || Itor->first - 1 != K) - State.SkipWithError("Did find the non-existing element"); - } -#endif - } - } - } - - std::string name() const { return "BM_UpperBound" + baseName() + Mode::name() + Order::name(); } -}; - -} // namespace - -int main(int argc, char** argv) { - benchmark::Initialize(&argc, argv); - if (benchmark::ReportUnrecognizedArguments(argc, argv)) - return 1; - -#ifdef VALIDATE - const std::vector MapSize{10}; -#else - const std::vector MapSize{10, 100, 1000, 10000, 100000, 1000000}; -#endif - - // Member functions - makeCartesianProductBenchmark(); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - - // Capacity - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - - // Modifiers - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - - // Lookup - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - makeCartesianProductBenchmark(MapSize); - - benchmark::RunSpecifiedBenchmarks(); -} diff --git a/libcxx/test/benchmarks/containers/ordered_set.bench.cpp b/libcxx/test/benchmarks/containers/ordered_set.bench.cpp deleted file mode 100644 index cb68902c6dcc8..0000000000000 --- a/libcxx/test/benchmarks/containers/ordered_set.bench.cpp +++ /dev/null @@ -1,232 +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 - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../CartesianBenchmarks.h" -#include "benchmark/benchmark.h" -#include "test_macros.h" - -namespace { - -enum class HitType { Hit, Miss }; - -struct AllHitTypes : EnumValuesAsTuple { - static constexpr const char* Names[] = {"Hit", "Miss"}; -}; - -enum class AccessPattern { Ordered, Random }; - -struct AllAccessPattern : EnumValuesAsTuple { - static constexpr const char* Names[] = {"Ordered", "Random"}; -}; - -void sortKeysBy(std::vector& Keys, AccessPattern AP) { - if (AP == AccessPattern::Random) { - std::random_device R; - std::mt19937 M(R()); - std::shuffle(std::begin(Keys), std::end(Keys), M); - } -} - -struct TestSets { - std::vector > Sets; - std::vector Keys; -}; - -TestSets makeTestingSets(size_t TableSize, size_t NumTables, HitType Hit, AccessPattern Access) { - TestSets R; - R.Sets.resize(1); - - for (uint64_t I = 0; I < TableSize; ++I) { - R.Sets[0].insert(2 * I); - R.Keys.push_back(Hit == HitType::Hit ? 2 * I : 2 * I + 1); - } - R.Sets.resize(NumTables, R.Sets[0]); - sortKeysBy(R.Keys, Access); - - return R; -} - -struct Base { - size_t TableSize; - size_t NumTables; - Base(size_t T, size_t N) : TableSize(T), NumTables(N) {} - - bool skip() const { - size_t Total = TableSize * NumTables; - return Total < 100 || Total > 1000000; - } - - std::string baseName() const { - return "_TableSize" + std::to_string(TableSize) + "_NumTables" + std::to_string(NumTables); - } -}; - -template -struct Create : Base { - using Base::Base; - - void run(benchmark::State& State) const { - std::vector Keys(TableSize); - std::iota(Keys.begin(), Keys.end(), uint64_t{0}); - sortKeysBy(Keys, Access()); - - while (State.KeepRunningBatch(TableSize * NumTables)) { - std::vector> Sets(NumTables); - for (auto K : Keys) { - for (auto& Set : Sets) { - benchmark::DoNotOptimize(Set.insert(K)); - } - } - } - } - - std::string name() const { return "BM_Create" + Access::name() + baseName(); } -}; - -template -struct Find : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(TableSize, NumTables, Hit(), Access()); - - while (State.KeepRunningBatch(TableSize * NumTables)) { - for (auto K : Data.Keys) { - for (auto& Set : Data.Sets) { - benchmark::DoNotOptimize(Set.find(K)); - } - } - } - } - - std::string name() const { return "BM_Find" + Hit::name() + Access::name() + baseName(); } -}; - -template -struct FindNeEnd : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(TableSize, NumTables, Hit(), Access()); - - while (State.KeepRunningBatch(TableSize * NumTables)) { - for (auto K : Data.Keys) { - for (auto& Set : Data.Sets) { - benchmark::DoNotOptimize(Set.find(K) != Set.end()); - } - } - } - } - - std::string name() const { return "BM_FindNeEnd" + Hit::name() + Access::name() + baseName(); } -}; - -template -struct InsertHit : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(TableSize, NumTables, HitType::Hit, Access()); - - while (State.KeepRunningBatch(TableSize * NumTables)) { - for (auto K : Data.Keys) { - for (auto& Set : Data.Sets) { - benchmark::DoNotOptimize(Set.insert(K)); - } - } - } - } - - std::string name() const { return "BM_InsertHit" + Access::name() + baseName(); } -}; - -template -struct InsertMissAndErase : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss, Access()); - - while (State.KeepRunningBatch(TableSize * NumTables)) { - for (auto K : Data.Keys) { - for (auto& Set : Data.Sets) { - benchmark::DoNotOptimize(Set.erase(Set.insert(K).first)); - } - } - } - } - - std::string name() const { return "BM_InsertMissAndErase" + Access::name() + baseName(); } -}; - -struct IterateRangeFor : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss, AccessPattern::Ordered); - - while (State.KeepRunningBatch(TableSize * NumTables)) { - for (auto& Set : Data.Sets) { - for (auto& V : Set) { - benchmark::DoNotOptimize(const_cast::reference>(V)); - } - } - } - } - - std::string name() const { return "BM_IterateRangeFor" + baseName(); } -}; - -struct IterateBeginEnd : Base { - using Base::Base; - - void run(benchmark::State& State) const { - auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss, AccessPattern::Ordered); - - while (State.KeepRunningBatch(TableSize * NumTables)) { - for (auto& Set : Data.Sets) { - for (auto it = Set.begin(); it != Set.end(); ++it) { - benchmark::DoNotOptimize(const_cast::reference>(*it)); - } - } - } - } - - std::string name() const { return "BM_IterateBeginEnd" + baseName(); } -}; - -} // namespace - -int main(int argc, char** argv) { - benchmark::Initialize(&argc, argv); - if (benchmark::ReportUnrecognizedArguments(argc, argv)) - return 1; - - const std::vector TableSize{1, 10, 100, 1000, 10000, 100000, 1000000}; - const std::vector NumTables{1, 10, 100, 1000, 10000, 100000, 1000000}; - - makeCartesianProductBenchmark(TableSize, NumTables); - makeCartesianProductBenchmark(TableSize, NumTables); - makeCartesianProductBenchmark(TableSize, NumTables); - makeCartesianProductBenchmark(TableSize, NumTables); - makeCartesianProductBenchmark(TableSize, NumTables); - makeCartesianProductBenchmark(TableSize, NumTables); - makeCartesianProductBenchmark(TableSize, NumTables); - benchmark::RunSpecifiedBenchmarks(); -} diff --git a/libcxx/test/benchmarks/containers/unordered_set.bench.cpp b/libcxx/test/benchmarks/containers/unordered_set.bench.cpp deleted file mode 100644 index ad8d0feaa0436..0000000000000 --- a/libcxx/test/benchmarks/containers/unordered_set.bench.cpp +++ /dev/null @@ -1,245 +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 - -#include -#include -#include -#include -#include -#include - -#include "benchmark/benchmark.h" - -#include "container_benchmarks.h" -#include "../GenerateInput.h" -#include "test_macros.h" - -using namespace ContainerBenchmarks; - -constexpr std::size_t TestNumInputs = 1024; - -// The purpose of this hash function is to NOT be implemented as the identity function, -// which is how std::hash is implemented for smaller integral types. -struct NonIdentityScalarHash : std::hash {}; - -// The sole purpose of this comparator is to be used in BM_Rehash, where -// we need something slow enough to be easily noticable in benchmark results. -// The default implementation of operator== for strings seems to be a little -// too fast for that specific benchmark to reliably show a noticeable -// improvement, but unoptimized bytewise comparison fits just right. -// Early return is there just for convenience, since we only compare strings -// of equal length in BM_Rehash. -struct SlowStringEq { - SlowStringEq() = default; - inline TEST_ALWAYS_INLINE bool operator()(const std::string& lhs, const std::string& rhs) const { - if (lhs.size() != rhs.size()) - return false; - - bool eq = true; - for (size_t i = 0; i < lhs.size(); ++i) { - eq &= lhs[i] == rhs[i]; - } - return eq; - } -}; - -//----------------------------------------------------------------------------// -// BM_InsertValue -// ---------------------------------------------------------------------------// - -// Sorted Ascending // -BENCHMARK_CAPTURE( - BM_InsertValue, unordered_set_uint32, std::unordered_set{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE( - BM_InsertValue, unordered_set_uint32_sorted, std::unordered_set{}, getSortedIntegerInputs) - ->Arg(TestNumInputs); - -// Top Bytes // -BENCHMARK_CAPTURE(BM_InsertValue, - unordered_set_top_bits_uint32, - std::unordered_set{}, - getSortedTopBitsIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_InsertValueRehash, - unordered_set_top_bits_uint32, - std::unordered_set{}, - getSortedTopBitsIntegerInputs) - ->Arg(TestNumInputs); - -// String // -BENCHMARK_CAPTURE(BM_InsertValue, unordered_set_string, std::unordered_set{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_InsertValueRehash, unordered_set_string, std::unordered_set{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -// Prefixed String // -BENCHMARK_CAPTURE( - BM_InsertValue, unordered_set_prefixed_string, std::unordered_set{}, getPrefixedRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_InsertValueRehash, - unordered_set_prefixed_string, - std::unordered_set{}, - getPrefixedRandomStringInputs) - ->Arg(TestNumInputs); - -//----------------------------------------------------------------------------// -// BM_Find -// ---------------------------------------------------------------------------// - -// Random // -BENCHMARK_CAPTURE( - BM_Find, unordered_set_random_uint64, std::unordered_set{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_FindRehash, - unordered_set_random_uint64, - std::unordered_set{}, - getRandomIntegerInputs) - ->Arg(TestNumInputs); - -// Sorted // -BENCHMARK_CAPTURE( - BM_Find, unordered_set_sorted_uint64, std::unordered_set{}, getSortedIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_FindRehash, - unordered_set_sorted_uint64, - std::unordered_set{}, - getSortedIntegerInputs) - ->Arg(TestNumInputs); - -// Sorted // -#ifndef TEST_HAS_NO_INT128 -BENCHMARK_CAPTURE(BM_Find, - unordered_set_sorted_uint128, - std::unordered_set<__uint128_t>{}, - getSortedTopBitsIntegerInputs<__uint128_t>) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_FindRehash, - unordered_set_sorted_uint128, - std::unordered_set<__uint128_t>{}, - getSortedTopBitsIntegerInputs<__uint128_t>) - ->Arg(TestNumInputs); -#endif - -// Sorted // -BENCHMARK_CAPTURE( - BM_Find, unordered_set_sorted_uint32, std::unordered_set{}, getSortedIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_FindRehash, - unordered_set_sorted_uint32, - std::unordered_set{}, - getSortedIntegerInputs) - ->Arg(TestNumInputs); - -// Sorted Ascending // -BENCHMARK_CAPTURE( - BM_Find, unordered_set_sorted_large_uint64, std::unordered_set{}, getSortedLargeIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_FindRehash, - unordered_set_sorted_large_uint64, - std::unordered_set{}, - getSortedLargeIntegerInputs) - ->Arg(TestNumInputs); - -// Top Bits // -BENCHMARK_CAPTURE( - BM_Find, unordered_set_top_bits_uint64, std::unordered_set{}, getSortedTopBitsIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_FindRehash, - unordered_set_top_bits_uint64, - std::unordered_set{}, - getSortedTopBitsIntegerInputs) - ->Arg(TestNumInputs); - -// String // -BENCHMARK_CAPTURE(BM_Find, unordered_set_string, std::unordered_set{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_FindRehash, unordered_set_string, std::unordered_set{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -// Prefixed String // -BENCHMARK_CAPTURE( - BM_Find, unordered_set_prefixed_string, std::unordered_set{}, getPrefixedRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE( - BM_FindRehash, unordered_set_prefixed_string, std::unordered_set{}, getPrefixedRandomStringInputs) - ->Arg(TestNumInputs); - -//----------------------------------------------------------------------------// -// BM_Rehash -// ---------------------------------------------------------------------------// - -BENCHMARK_CAPTURE(BM_Rehash, - unordered_set_string_arg, - std::unordered_set, SlowStringEq>{}, - getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_Rehash, unordered_set_int_arg, std::unordered_set{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -//----------------------------------------------------------------------------// -// BM_Compare -// ---------------------------------------------------------------------------// - -BENCHMARK_CAPTURE( - BM_Compare_same_container, unordered_set_string, std::unordered_set{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_Compare_same_container, unordered_set_int, std::unordered_set{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE( - BM_Compare_different_containers, unordered_set_string, std::unordered_set{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE( - BM_Compare_different_containers, unordered_set_int, std::unordered_set{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -/////////////////////////////////////////////////////////////////////////////// -BENCHMARK_CAPTURE(BM_InsertDuplicate, unordered_set_int, std::unordered_set{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); -BENCHMARK_CAPTURE(BM_InsertDuplicate, unordered_set_string, std::unordered_set{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_EmplaceDuplicate, unordered_set_int, std::unordered_set{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); -BENCHMARK_CAPTURE(BM_EmplaceDuplicate, unordered_set_string, std::unordered_set{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE( - BM_InsertDuplicate, unordered_set_int_insert_arg, std::unordered_set{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); -BENCHMARK_CAPTURE( - BM_InsertDuplicate, unordered_set_string_insert_arg, std::unordered_set{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE( - BM_EmplaceDuplicate, unordered_set_int_insert_arg, std::unordered_set{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE( - BM_EmplaceDuplicate, unordered_set_string_arg, std::unordered_set{}, getRandomCStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_MAIN();