From 4c927cd2f22dcf212a10420eb03acf9b6e09b357 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 20 Mar 2023 16:00:54 -0700 Subject: [PATCH] Implement myriad insert() overloads, get first threaded test working --- .../boost/unordered/concurrent_flat_map.hpp | 12 ++ test/cfoa/insert_tests.cpp | 167 ++++++++++++++---- 2 files changed, 147 insertions(+), 32 deletions(-) diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index 8a981db9..0be57eef 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -126,6 +126,18 @@ namespace boost { /// bool insert(value_type const& obj) { return table_.insert(obj); } + bool insert(value_type&& obj) { return table_.insert(obj); } + + bool insert(init_type const& obj) { return table_.insert(obj); } + bool insert(init_type&& obj) { return table_.insert(std::move(obj)); } + + template + void insert(InputIterator begin, InputIterator end) + { + for (auto pos = begin; pos != end; ++pos) { + table_.insert(*pos); + } + } template std::size_t visit_all(F f) { diff --git a/test/cfoa/insert_tests.cpp b/test/cfoa/insert_tests.cpp index 1d3a6ac8..eb63403b 100644 --- a/test/cfoa/insert_tests.cpp +++ b/test/cfoa/insert_tests.cpp @@ -8,12 +8,17 @@ #include #include +#include #include #include +#include #include +#include #include +constexpr std::size_t const num_threads = 16; + struct raii { static std::atomic_int default_constructor; @@ -55,19 +60,19 @@ struct raii return *this; } - static void reset_counts() + friend bool operator==(raii const& lhs, raii const& rhs) { - default_constructor = 0; - copy_constructor = 0; - move_constructor = 0; - destructor = 0; - copy_assignment = 0; - move_assignment = 0; + return lhs.x_ == rhs.x_; + } + + friend bool operator!=(raii const& lhs, raii const& rhs) + { + return !(lhs == rhs); } friend std::ostream& operator<<(std::ostream& os, raii const& rhs) { - os << "{ x_: " << rhs.x_ << "}"; + os << "{ x_: " << rhs.x_ << " }"; return os; } @@ -78,14 +83,14 @@ struct raii return os; } - friend bool operator==(raii const& lhs, raii const& rhs) + static void reset_counts() { - return lhs.x_ == rhs.x_; - } - - friend bool operator!=(raii const& lhs, raii const& rhs) - { - return !(lhs == rhs); + default_constructor = 0; + copy_constructor = 0; + move_constructor = 0; + destructor = 0; + copy_assignment = 0; + move_assignment = 0; } }; @@ -102,16 +107,15 @@ std::size_t hash_value(raii const& r) noexcept return hasher(r.x_); } -std::vector > make_random_values( - std::size_t count, test::random_generator rg) +template +auto make_random_values(std::size_t count, F f) -> std::vector { - std::vector > v; + using vector_type = std::vector; + + vector_type v; v.reserve(count); for (std::size_t i = 0; i < count; ++i) { - int* p = nullptr; - int a = generate(p, rg); - int b = generate(p, rg); - v.emplace_back(raii{a}, raii{b}); + v.emplace_back(f()); } return v; } @@ -119,14 +123,104 @@ std::vector > make_random_values( namespace { test::seed_t initialize_seed(78937); + struct value_type_generator_type + { + std::pair operator()(test::random_generator rg) + { + int* p = nullptr; + int a = generate(p, rg); + int b = generate(p, rg); + return std::make_pair(raii{a}, raii{b}); + } + } value_type_generator; + + struct init_type_generator_type + { + std::pair operator()(test::random_generator rg) + { + int* p = nullptr; + int a = generate(p, rg); + int b = generate(p, rg); + return std::make_pair(raii{a}, raii{b}); + } + } init_type_generator; + + template + std::vector > split( + std::vector& vec, std::size_t const nt /* num threads*/) + { + std::vector > subslices; + subslices.reserve(nt); + + boost::span s(vec); + + auto a = vec.size() / nt; + auto b = a; + if (vec.size() % nt != 0) { + ++b; + } + + auto num_a = nt; + auto num_b = std::size_t{0}; + + if (nt * b > vec.size()) { + num_a = nt * b - vec.size(); + num_b = nt - num_a; + } + + auto sub_b = s.subspan(0, num_b * b); + auto sub_a = s.subspan(num_b * b); + + for (std::size_t i = 0; i < num_b; ++i) { + subslices.push_back(sub_b.subspan(i * b, b)); + } + + for (std::size_t i = 0; i < num_a; ++i) { + auto const is_last = i == (num_a - 1); + subslices.push_back( + sub_a.subspan(i * a, is_last ? boost::dynamic_extent : a)); + } + + return subslices; + } + struct lvalue_inserter_type { - template - void operator()(std::vector const& values, X& x) + template void operator()(std::vector& values, X& x) { - for (auto const& r : values) { - bool b = x.insert(r); - (void)b; + std::mutex m; + std::vector threads; + std::condition_variable cv; + + auto ready = false; + + auto subslices = split(values, num_threads); + + BOOST_ASSERT(subslices.size() == num_threads); + + for (std::size_t i = 0; i < num_threads; ++i) { + threads.emplace_back([&x, &m, &ready, &subslices, &cv, i] { + std::unique_lock lk(m); + cv.wait(lk, [&] { return ready; }); + lk.unlock(); + + auto s = subslices[i]; + + for (auto const& r : s) { + bool b = x.insert(r); + (void)b; + } + }); + } + + { + std::unique_lock lk(m); + ready = true; + } + cv.notify_all(); + + for (auto& t : threads) { + t.join(); } } } lvalue_inserter; @@ -142,10 +236,18 @@ namespace { } } rvalue_inserter; - template - void insert(X*, F inserter, test::random_generator generator) + struct iterator_range_inserter_type { - auto values = make_random_values(1024, generator); + template void operator()(std::vector& values, X& x) + { + x.insert(values.begin(), values.end()); + } + } iterator_range_inserter; + + template + void insert(X*, G gen, F inserter, test::random_generator rg) + { + auto values = make_random_values(1024 * 1024, [&] { return gen(rg); }); BOOST_TEST_GT(values.size(), 0u); auto reference_map = @@ -190,8 +292,9 @@ using test::limited_range; // clang-format off UNORDERED_TEST( insert, ((map)) - ((lvalue_inserter)(rvalue_inserter)) - ((default_generator)(generate_collisions)(limited_range))) + ((value_type_generator)(init_type_generator)) + ((lvalue_inserter)(rvalue_inserter)(iterator_range_inserter)) + ((default_generator)(limited_range))) // clang-format on RUN_TESTS()