From 224ea725477504ddb91a00abc7c52519906e3e16 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 6 Jan 2019 22:30:55 +0800 Subject: [PATCH] use elem_array --- include/circ_elem_array.h | 386 +++++++++++++++++++++---------------- include/circ_elems_array.h | 265 ------------------------- include/circ_queue.h | 18 +- src/memory/resource.hpp | 38 ++-- test/test_circ.cpp | 146 ++++++-------- 5 files changed, 311 insertions(+), 542 deletions(-) delete mode 100644 include/circ_elems_array.h diff --git a/include/circ_elem_array.h b/include/circ_elem_array.h index f57329b..ef78bf1 100644 --- a/include/circ_elem_array.h +++ b/include/circ_elem_array.h @@ -1,27 +1,216 @@ #pragma once #include -#include -#include #include +#include #include "def.h" namespace ipc { namespace circ { -template -struct alignas(std::max_align_t) elem_array_head { - using u1_t = uint_t; - using u2_t = uint_t; +namespace detail { - std::atomic cc_ { 0 }; // connection counter, using for broadcast - std::atomic wt_ { 0 }; // write index +using u1_t = uint_t<8>; +using u2_t = uint_t<16>; - constexpr static u1_t index_of(u2_t c) noexcept { - return static_cast(c); +constexpr u1_t index_of(u2_t c) noexcept { + return static_cast(c); +} + +struct elem_head { + std::atomic rc_ { 0 }; // read counter +}; + +template +struct elem_t { + elem_head head_; + byte_t data_[DataSize] {}; +}; + +template <> +struct elem_t<0> { + elem_head head_; +}; + +template +elem_t* elem_of(void* ptr) noexcept { + return reinterpret_cast*>(static_cast(ptr) - sizeof(elem_head)); +} + +} // namespace detail + +enum class relat { // multiplicity of the relationship + single, + multi +}; + +enum class trans { // transmission + unicast, + broadcast +}; + +//////////////////////////////////////////////////////////////// +/// producer-consumer policies +//////////////////////////////////////////////////////////////// + +template +struct prod_cons; + +template <> +struct prod_cons { + std::atomic rd_ { 0 }; // read index + std::atomic wt_ { 0 }; // write index + + template + constexpr static std::size_t elem_param = DataSize - sizeof(detail::elem_head); + + constexpr detail::u2_t cursor() const noexcept { + return 0; } + template + bool push(E* /*elems*/, F&& f, detail::elem_t* elem_start) { + auto cur_wt = detail::index_of(wt_.load(std::memory_order_acquire)); + if (cur_wt == detail::index_of(rd_.load(std::memory_order_relaxed) - 1)) { + return false; // full + } + std::forward(f)(elem_start + cur_wt); + wt_.fetch_add(1, std::memory_order_release); + return true; + } + + template + bool pop(E* /*elems*/, detail::u2_t& /*cur*/, F&& f, detail::elem_t* elem_start) noexcept { + auto cur_rd = detail::index_of(rd_.load(std::memory_order_acquire)); + if (cur_rd == detail::index_of(wt_.load(std::memory_order_relaxed))) { + return false; // empty + } + std::forward(f)(elem_start + cur_rd); + rd_.fetch_add(1, std::memory_order_release); + return true; + } +}; + +template <> +struct prod_cons + : prod_cons { + + template + bool pop(E* /*elems*/, detail::u2_t& /*cur*/, F&& f, detail::elem_t* elem_start) noexcept { + byte_t buff[sizeof(detail::elem_t)]; + while (1) { + auto cur_rd = rd_.load(std::memory_order_acquire); + if (detail::index_of(cur_rd) == + detail::index_of(wt_.load(std::memory_order_relaxed))) { + return false; // empty + } + std::memcpy(buff, elem_start + detail::index_of(cur_rd), sizeof(buff)); + if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) { + std::forward(f)(buff); + return true; + } + std::this_thread::yield(); + } + } +}; + +template <> +struct prod_cons + : prod_cons { + + std::atomic ct_ { 0 }; // commit index + + template + bool push(E* /*elems*/, F&& f, detail::elem_t* elem_start) { + detail::u2_t cur_ct, nxt_ct; + while (1) { + cur_ct = ct_.load(std::memory_order_acquire); + if (detail::index_of(nxt_ct = cur_ct + 1) == + detail::index_of(rd_.load(std::memory_order_relaxed))) { + return false; // full + } + if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_relaxed)) { + break; + } + std::this_thread::yield(); + } + std::forward(f)(elem_start + detail::index_of(cur_ct)); + while (1) { + auto exp_wt = cur_ct; + if (wt_.compare_exchange_weak(exp_wt, nxt_ct, std::memory_order_release)) { + break; + } + std::this_thread::yield(); + } + return true; + } +}; + +template <> +struct prod_cons { + std::atomic wt_ { 0 }; // write index + + template + constexpr static std::size_t elem_param = DataSize; + + /* + std::atomic may not have value_type. + See: https://stackoverflow.com/questions/53648614/what-happened-to-stdatomicxvalue-type + */ + using rc_t = decltype(detail::elem_head::rc_.load()); + + detail::u2_t cursor() const noexcept { + return wt_.load(std::memory_order_acquire); + } + + template + bool push(E* elems, F&& f, detail::elem_t* elem_start) { + auto conn_cnt = elems->conn_count(); // acquire + if (conn_cnt == 0) return false; + auto el = elem_start + detail::index_of(wt_.load(std::memory_order_relaxed)); + // check all consumers have finished reading this element + while (1) { + rc_t expected = 0; + if (el->head_.rc_.compare_exchange_weak( + expected, static_cast(conn_cnt), std::memory_order_relaxed)) { + break; + } + std::this_thread::yield(); + conn_cnt = elems->conn_count(); // acquire + if (conn_cnt == 0) return false; + } + std::forward(f)(el->data_); + wt_.fetch_add(1, std::memory_order_release); + return true; + } + + template + bool pop(E* /*elems*/, detail::u2_t& cur, F&& f, detail::elem_t* elem_start) noexcept { + if (cur == cursor()) return false; // acquire + auto el = elem_start + detail::index_of(cur++); + std::forward(f)(el->data_); + while (1) { + rc_t cur_rc = el->head_.rc_.load(std::memory_order_acquire); + if (cur_rc == 0) { + return true; + } + if (el->head_.rc_.compare_exchange_weak( + cur_rc, cur_rc - 1, std::memory_order_release)) { + return true; + } + std::this_thread::yield(); + } + } +}; + +//////////////////////////////////////////////////////////////// +/// element-array implementation +//////////////////////////////////////////////////////////////// + +struct elem_head { + std::atomic cc_ { 0 }; // connection counter + std::size_t connect() noexcept { return cc_.fetch_add(1, std::memory_order_release); } @@ -30,185 +219,52 @@ struct alignas(std::max_align_t) elem_array_head { return cc_.fetch_sub(1, std::memory_order_release); } - std::size_t conn_count() const noexcept { - return cc_.load(std::memory_order_acquire); - } - - u2_t cursor() const noexcept { - return wt_.load(std::memory_order_acquire); - } - - auto acquire(std::memory_order order = std::memory_order_acquire) noexcept { - return index_of(wt_.load(order)); - } - - void commit() noexcept { - wt_.fetch_add(1, std::memory_order_release); + std::size_t conn_count(std::memory_order order = std::memory_order_acquire) const noexcept { + return cc_.load(order); } }; -template -constexpr std::size_t elem_array_head_size = - (sizeof(elem_array_head) % alignof(std::max_align_t)) ? - ((sizeof(elem_array_head) / alignof(std::max_align_t)) + 1) * alignof(std::max_align_t) : - sizeof(elem_array_head); - -struct elem_head { - std::atomic> rc_ { 0 }; // read counter -}; - -template -class elem_array : protected elem_array_head { +template +class elem_array : private Policy { public: - using base_t = elem_array_head; - using head_t = elem_head; - - using typename base_t::u1_t; - using typename base_t::u2_t; + using policy_t = Policy; + using base_t = Policy; + using head_t = elem_head; + using elem_t = detail::elem_t>; enum : std::size_t { - head_size = elem_array_head_size, + head_size = sizeof(policy_t) + sizeof(head_t), data_size = DataSize, - elem_max = (std::numeric_limits::max)() + 1, // default is 255 + 1 - elem_size = sizeof(head_t) + DataSize, + elem_max = (std::numeric_limits>::max)() + 1, // default is 255 + 1 + elem_size = sizeof(elem_t), block_size = elem_size * elem_max }; -protected: - struct elem_t { - head_t head_; - byte_t data_[data_size] {}; - }; +private: + head_t head_; elem_t block_[elem_max]; - elem_t* elem_start() noexcept { - return block_; - } - - static elem_t* elem(void* ptr) noexcept { return reinterpret_cast(static_cast(ptr) - sizeof(head_t)); } - elem_t* elem(u1_t i ) noexcept { return elem_start() + i; } - - template - void* acquire(std::memory_order order, Acq&& acq, P&&... params) noexcept { - uint_t<32> conn_cnt = this->cc_.load(order); - if (conn_cnt == 0) return nullptr; - elem_t* el = elem(std::forward(acq)(std::memory_order_relaxed, - std::forward

(params)...)); - // check all consumers have finished reading - while(1) { - uint_t<32> expected = 0; - if (el->head_.rc_.compare_exchange_weak( - expected, conn_cnt, std::memory_order_relaxed)) { - break; - } - std::this_thread::yield(); - conn_cnt = this->cc_.load(std::memory_order_acquire); - } - return el->data_; - } - public: elem_array() = default; - elem_array(const elem_array&) = delete; elem_array& operator=(const elem_array&) = delete; - elem_array(elem_array&&) = delete; - elem_array& operator=(elem_array&&) = delete; - using base_t::connect; - using base_t::disconnect; - using base_t::conn_count; + std::size_t connect () noexcept { return head_.connect (); } + std::size_t disconnect() noexcept { return head_.disconnect(); } + std::size_t conn_count() const noexcept { return head_.conn_count(); } + using base_t::cursor; - void* acquire(std::memory_order order = std::memory_order_acquire) noexcept { - return this->acquire(order, [this](auto o) { - return base_t::acquire(o); - }); - } - - void commit(void* /*ptr*/) noexcept { - base_t::commit(); + template + bool push(F&& f) noexcept { + return base_t::push(this, std::forward(f), block_); } template - bool fetch(F&& f) noexcept { - auto p = this->acquire(); - if (p == nullptr) return false; - std::forward(f)(p); - this->commit(p); - return true; - } - - void* take(u2_t cursor) noexcept { - return elem(base_t::index_of(cursor))->data_; - } - - void put(void* ptr) noexcept { - auto el = elem(ptr); - uint_t<32> cur_rc; - do { - cur_rc = el->head_.rc_.load(std::memory_order_relaxed); - if (cur_rc == 0) return; - } while (!el->head_.rc_.compare_exchange_weak( - cur_rc, cur_rc - 1, std::memory_order_release)); + bool pop(detail::u2_t& cur, F&& f) noexcept { + return base_t::pop(this, cur, std::forward(f), block_); } }; -/* -template -class multi_write_array : protected elem_array { -public: - using base_t = elem_array; - using head_t = typename base_t::head_t; - using typename base_t::u1_t; - using typename base_t::u2_t; - - using base_t::head_size; - using base_t::data_size; - using base_t::elem_max; - using base_t::elem_size; - using base_t::block_size; - -protected: - std::atomic rd_ { 0 }; // ready index - -public: - using base_t::connect; - using base_t::disconnect; - using base_t::conn_count; - - u2_t cursor() const noexcept { - return rd_.load(std::memory_order_acquire); - } - - template - bool fetch(F&& f) noexcept { - u2_t cur_rd; - auto p = base_t::acquire(std::memory_order_acquire, [this, &cur_rd](auto o) { - while (1) { - u2_t cur_wt = wt_.load(o), nxt_wt = cur_wt + 1; - if (base_t::index_of(nxt_wt) == - base_t::index_of(cur_rd = rd_.load(std::memory_order_relaxed))) { - // is full - } - else if (wt_.compare_exchange_weak(cur_wt, nxt_wt, std::memory_order_relaxed)) { - return base_t::index_of(nxt_wt); - } - std::this_thread::yield(); - std::atomic_thread_fence(std::memory_order_acquire); - } - }); - if (p == nullptr) return false; - std::forward(f)(p); - while (1) { - if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) { - break; - } - std::this_thread::yield(); - } - return true; - } -}; -*/ } // namespace circ } // namespace ipc diff --git a/include/circ_elems_array.h b/include/circ_elems_array.h deleted file mode 100644 index 9884c05..0000000 --- a/include/circ_elems_array.h +++ /dev/null @@ -1,265 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "def.h" - -namespace ipc { -namespace circ { - -namespace detail { - -using u1_t = uint_t<8>; -using u2_t = uint_t<16>; - -constexpr u1_t index_of(u2_t c) noexcept { - return static_cast(c); -} - -struct elem_head { - std::atomic rc_ { 0 }; // read counter -}; - -template -struct elem_t { - elem_head head_; - byte_t data_[DataSize] {}; -}; - -template <> -struct elem_t<0> { - elem_head head_; -}; - -template -elem_t* elem_of(void* ptr) noexcept { - return reinterpret_cast*>(static_cast(ptr) - sizeof(elem_head)); -} - -} // namespace detail - -enum class relat { // multiplicity of the relationship - single, - multi -}; - -enum class trans { // transmission - unicast, - broadcast -}; - -//////////////////////////////////////////////////////////////// -/// producer-consumer policies -//////////////////////////////////////////////////////////////// - -template -struct prod_cons; - -template <> -struct prod_cons { - std::atomic rd_ { 0 }; // read index - std::atomic wt_ { 0 }; // write index - - template - constexpr static std::size_t elem_param = DataSize - sizeof(detail::elem_head); - - constexpr detail::u2_t cursor() const noexcept { - return 0; - } - - template - bool push(E* /*elems*/, F&& f, detail::elem_t* elem_start) { - auto cur_wt = detail::index_of(wt_.load(std::memory_order_acquire)); - if (cur_wt == detail::index_of(rd_.load(std::memory_order_relaxed) - 1)) { - return false; // full - } - std::forward(f)(elem_start + cur_wt); - wt_.fetch_add(1, std::memory_order_release); - return true; - } - - template - bool pop(E* /*elems*/, detail::u2_t& /*cur*/, F&& f, detail::elem_t* elem_start) noexcept { - auto cur_rd = detail::index_of(rd_.load(std::memory_order_acquire)); - if (cur_rd == detail::index_of(wt_.load(std::memory_order_relaxed))) { - return false; // empty - } - std::forward(f)(elem_start + cur_rd); - rd_.fetch_add(1, std::memory_order_release); - return true; - } -}; - -template <> -struct prod_cons - : prod_cons { - - template - bool pop(E* /*elems*/, detail::u2_t& /*cur*/, F&& f, detail::elem_t* elem_start) noexcept { - byte_t buff[sizeof(detail::elem_t)]; - while (1) { - auto cur_rd = rd_.load(std::memory_order_acquire); - if (detail::index_of(cur_rd) == - detail::index_of(wt_.load(std::memory_order_relaxed))) { - return false; // empty - } - std::memcpy(buff, elem_start + detail::index_of(cur_rd), sizeof(buff)); - if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) { - std::forward(f)(buff); - return true; - } - std::this_thread::yield(); - } - } -}; - -template <> -struct prod_cons - : prod_cons { - - std::atomic ct_ { 0 }; // commit index - - template - bool push(E* /*elems*/, F&& f, detail::elem_t* elem_start) { - detail::u2_t cur_ct, nxt_ct; - while (1) { - cur_ct = ct_.load(std::memory_order_acquire); - if (detail::index_of(nxt_ct = cur_ct + 1) == - detail::index_of(rd_.load(std::memory_order_relaxed))) { - return false; // full - } - if (ct_.compare_exchange_weak(cur_ct, nxt_ct, std::memory_order_relaxed)) { - break; - } - std::this_thread::yield(); - } - std::forward(f)(elem_start + detail::index_of(cur_ct)); - while (1) { - auto exp_wt = cur_ct; - if (wt_.compare_exchange_weak(exp_wt, nxt_ct, std::memory_order_release)) { - break; - } - std::this_thread::yield(); - } - return true; - } -}; - -template <> -struct prod_cons { - std::atomic wt_ { 0 }; // write index - - template - constexpr static std::size_t elem_param = DataSize; - - /* - std::atomic may not have value_type. - See: https://stackoverflow.com/questions/53648614/what-happened-to-stdatomicxvalue-type - */ - using rc_t = decltype(detail::elem_head::rc_.load()); - - detail::u2_t cursor() const noexcept { - return wt_.load(std::memory_order_acquire); - } - - template - bool push(E* elems, F&& f, detail::elem_t* elem_start) { - auto conn_cnt = elems->conn_count(); // acquire - if (conn_cnt == 0) return false; - auto el = elem_start + detail::index_of(wt_.load(std::memory_order_relaxed)); - // check all consumers have finished reading this element - rc_t expected = 0; - if (!el->head_.rc_.compare_exchange_weak( - expected, static_cast(conn_cnt), std::memory_order_relaxed)) { - return false; - } - std::forward(f)(el->data_); - wt_.fetch_add(1, std::memory_order_release); - return true; - } - - template - bool pop(E* /*elems*/, detail::u2_t& cur, F&& f, detail::elem_t* elem_start) noexcept { - if (cur == cursor()) return false; // acquire - auto el = elem_start + detail::index_of(cur++); - std::forward(f)(el->data_); - do { - rc_t cur_rc = el->head_.rc_.load(std::memory_order_acquire); - if (cur_rc == 0) { - return true; - } - if (el->head_.rc_.compare_exchange_weak( - cur_rc, cur_rc - 1, std::memory_order_release)) { - return true; - } - std::this_thread::yield(); - } while (1); - } -}; - -//////////////////////////////////////////////////////////////// -/// element-array implementation -//////////////////////////////////////////////////////////////// - -struct elems_head { - std::atomic cc_ { 0 }; // connection counter - - std::size_t connect() noexcept { - return cc_.fetch_add(1, std::memory_order_release); - } - - std::size_t disconnect() noexcept { - return cc_.fetch_sub(1, std::memory_order_release); - } - - std::size_t conn_count(std::memory_order order = std::memory_order_acquire) const noexcept { - return cc_.load(order); - } -}; - -template -class elems_array : private Policy { -public: - using policy_t = Policy; - using base_t = Policy; - using head_t = elems_head; - using elem_t = detail::elem_t>; - - enum : std::size_t { - head_size = sizeof(head_t), - data_size = DataSize, - elem_max = (std::numeric_limits>::max)() + 1, // default is 255 + 1 - elem_size = sizeof(elem_t), - block_size = elem_size * elem_max - }; - -private: - head_t head_; - elem_t block_[elem_max]; - -public: - elems_array() = default; - elems_array(const elems_array&) = delete; - elems_array& operator=(const elems_array&) = delete; - - std::size_t connect () noexcept { return head_.connect (); } - std::size_t disconnect() noexcept { return head_.disconnect(); } - std::size_t conn_count() const noexcept { return head_.conn_count(); } - - using base_t::cursor; - - template - bool push(F&& f) noexcept { - return base_t::push(this, std::forward(f), block_); - } - - template - bool pop(detail::u2_t& cur, F&& f) noexcept { - return base_t::pop(this, cur, std::forward(f), block_); - } -}; - -} // namespace circ -} // namespace ipc diff --git a/include/circ_queue.h b/include/circ_queue.h index 345e612..5fb0e8a 100644 --- a/include/circ_queue.h +++ b/include/circ_queue.h @@ -15,14 +15,15 @@ namespace ipc { namespace circ { -template class ElemArray = elem_array> +template > class queue { public: - using array_t = ElemArray; + using array_t = elem_array; + using policy_t = typename array_t::policy_t; private: array_t* elems_ = nullptr; - typename array_t::u2_t cursor_ = 0; + decltype(std::declval().cursor()) cursor_ = 0; std::atomic_bool connected_ { false }; public: @@ -89,7 +90,7 @@ public: template auto push(P&&... params) noexcept { if (elems_ == nullptr) return false; - return elems_->fetch([&](void* p) { + return elems_->push([&](void* p) { ::new (p) T(std::forward

(params)...); }); } @@ -121,9 +122,12 @@ public: if (que->elems_ == nullptr) { return {}; } - auto item_ptr = static_cast(que->elems_->take(que->cursor_++)); - T item = std::move(*item_ptr); - que->elems_->put(item_ptr); + T item; + if (!que->elems_->pop(que->cursor_, [&item](void* p) { + ::new (&item) T(std::move(*static_cast(p))); + })) { + return {}; + } return item; } diff --git a/src/memory/resource.hpp b/src/memory/resource.hpp index 8a46af5..c41f9fd 100644 --- a/src/memory/resource.hpp +++ b/src/memory/resource.hpp @@ -41,27 +41,29 @@ enum : std::size_t { base_size = sizeof(void*) }; -template -constexpr std::size_t roundup(std::size_t n) { - return ((n - 1) & (~(Radix - 1))) + Radix; +constexpr std::size_t classify(std::size_t size) { + constexpr static std::size_t mapping[] = { + /* 1 */ + 0 , 1 , 2 , 3 , + /* 2 */ + 5 , 5 , 7 , 7 , + 9 , 9 , 11, 11, + 13, 13, 15, 15, + /* 4 */ + 19, 19, 19, 19, + 23, 23, 23, 23, + 27, 27, 27, 27, + 31, 31, 31, 31 + }; + size = (size - 1) / base_size; + return (size < std::size(mapping)) ? mapping[size] : 32; } -using fixed_sequence_t = std::index_sequence< - base_size , base_size * 2 , - base_size * 3 , base_size * 4 , - base_size * 5 , base_size * 6 , - base_size * 7 , base_size * 8 , - base_size * 9 , base_size * 10, - base_size * 11, base_size * 12, - base_size * 13, base_size * 14, - base_size * 15, base_size * 16 ->; - template decltype(auto) choose(std::size_t size, F&& f) { - return detail::static_switch(roundup(size), fixed_sequence_t { + return detail::static_switch(classify(size), std::make_index_sequence<32> { }, [&f](auto index) { - return f(fixed()); + return f(fixed<(decltype(index)::value + 1) * base_size>()); }, [&f] { return f(static_alloc{}); }); @@ -70,8 +72,8 @@ decltype(auto) choose(std::size_t size, F&& f) { class pool_alloc { public: static void clear() { - static_for(fixed_sequence_t {}, [](auto index) { - fixed().clear(); + static_for(std::make_index_sequence<32> {}, [](auto index) { + fixed<(decltype(index)::value + 1) * base_size>().clear(); }); } diff --git a/test/test_circ.cpp b/test/test_circ.cpp index 1d0d946..93b78f5 100644 --- a/test/test_circ.cpp +++ b/test/test_circ.cpp @@ -6,7 +6,6 @@ #include #include -#include "circ_elems_array.h" #include "circ_elem_array.h" #include "circ_queue.h" #include "memory/resource.hpp" @@ -19,7 +18,10 @@ struct msg_t { int dat_; }; -using cq_t = ipc::circ::elem_array; +using cq_t = ipc::circ::elem_array>; cq_t* cq__; bool operator==(msg_t const & m1, msg_t const & m2) { @@ -28,8 +30,8 @@ bool operator==(msg_t const & m1, msg_t const & m2) { } // internal-linkage -template <> -struct test_verify { +template +struct test_verify> { std::vector>> list_; test_verify(int M) @@ -99,14 +101,14 @@ struct quit_mode> { template struct quit_mode> { struct type { - type(bool) {} + constexpr type(bool) {} constexpr operator bool() const { return false; } }; }; template -struct test_cq> { - using ca_t = ipc::circ::elems_array; +struct test_cq> { + using ca_t = ipc::circ::elem_array; using cn_t = decltype(std::declval().cursor()); typename quit_mode

::type quit_ = false; @@ -132,7 +134,7 @@ struct test_cq> { template void recv(cn_t cur, F&& proc) { - while(1) { + while (1) { msg_t msg; while (ca_->pop(cur, [&msg](void* p) { msg = *static_cast(p); @@ -161,59 +163,6 @@ struct test_cq> { } }; -template -struct test_cq> { - using ca_t = ipc::circ::elem_array; - using cn_t = typename ca_t::u2_t; - - ca_t* ca_; - - test_cq(ca_t* ca) : ca_(ca) { - ::new (ca) ca_t; - } - - cn_t connect() { - auto cur = ca_->cursor(); - ca_->connect(); - return cur; - } - - void disconnect(cn_t) { - ca_->disconnect(); - } - - void wait_start(int M) { - while (ca_->conn_count() != static_cast(M)) { - std::this_thread::yield(); - } - } - - template - void recv(cn_t cur, F&& proc) { - while(1) { - while (cur != ca_->cursor()) { - msg_t* pmsg = static_cast(ca_->take(cur)), - msg = *pmsg; - ca_->put(pmsg); - if (msg.pid_ < 0) return; - ++cur; - proc(msg); - } - std::this_thread::yield(); - } - } - - ca_t* connect_send() { - return ca_; - } - - void send(ca_t* ca, msg_t const & msg) { - msg_t* pmsg = static_cast(ca->acquire()); - (*pmsg) = msg; - ca->commit(pmsg); - } -}; - template struct test_cq> { using cn_t = ipc::circ::queue; @@ -283,7 +232,7 @@ private slots: #include "test_circ.moc" -constexpr int LoopCount = 10000000; +constexpr int LoopCount = 1000000; //constexpr int LoopCount = 1000/*0000*/; void Unit::initTestCase() { @@ -302,15 +251,8 @@ void Unit::test_inst() { std::cout << "cq_t::block_size = " << cq_t::block_size << std::endl; QCOMPARE(static_cast(cq_t::data_size), sizeof(msg_t)); - QCOMPARE(sizeof(cq_t), static_cast(cq_t::block_size + cq_t::head_size)); - std::cout << "sizeof(ipc::circ::elem_array<4096>) = " << sizeof(*cq__) << std::endl; - - auto a = cq__->take(1); - auto b = cq__->take(2); - QCOMPARE(static_cast(static_cast(b) - - static_cast(a)), - static_cast(cq_t::elem_size)); + std::cout << "sizeof(ipc::circ::elem_array) = " << sizeof(*cq__) << std::endl; } template @@ -319,9 +261,7 @@ void test_prod_cons() { } void Unit::test_prod_cons_1v1() { - test_prod_cons<1, 1>(); - - ipc::circ::elems_array< + ipc::circ::elem_array< sizeof(msg_t), ipc::circ::prod_cons el_arr_ss; benchmark_prod_cons<1, 1, LoopCount, cq_t>(&el_arr_ss); benchmark_prod_cons<1, 1, LoopCount, void>(&el_arr_ss); + + ipc::circ::elem_array< + sizeof(msg_t), + ipc::circ::prod_cons + > el_arr_smn; + benchmark_prod_cons<1, 1, LoopCount, decltype(el_arr_smn)::policy_t>(&el_arr_smn); + benchmark_prod_cons<1, 1, LoopCount, void>(&el_arr_smn); + + ipc::circ::elem_array< + sizeof(msg_t), + ipc::circ::prod_cons + > el_arr_mmn; + benchmark_prod_cons<1, 1, LoopCount, decltype(el_arr_mmn)::policy_t>(&el_arr_mmn); + benchmark_prod_cons<1, 1, LoopCount, void>(&el_arr_mmn); + + test_prod_cons<1, 1>(); } void Unit::test_prod_cons_1v3() { - test_prod_cons<1, 3>(); - - ipc::circ::elems_array< + ipc::circ::elem_array< sizeof(msg_t), ipc::circ::prod_cons(&el_arr_smn); benchmark_prod_cons<1, 3, LoopCount, void>(&el_arr_smn); - ipc::circ::elems_array< + ipc::circ::elem_array< sizeof(msg_t), ipc::circ::prod_cons el_arr_mmn; benchmark_prod_cons<1, 3, LoopCount, decltype(el_arr_mmn)::policy_t>(&el_arr_mmn); benchmark_prod_cons<1, 3, LoopCount, void>(&el_arr_mmn); - benchmark_prod_cons<3, 3, LoopCount, decltype(el_arr_mmn)::policy_t>(&el_arr_mmn); - benchmark_prod_cons<3, 3, LoopCount, void>(&el_arr_mmn); - ipc::circ::elems_array< - sizeof(msg_t), - ipc::circ::prod_cons - > el_arr_smm; - benchmark_prod_cons<1, 3, LoopCount, cq_t>(&el_arr_smm); - benchmark_prod_cons<1, 3, LoopCount, void>(&el_arr_smm); + test_prod_cons<1, 3>(); } void Unit::test_prod_cons_performance() { + ipc::circ::elem_array< + sizeof(msg_t), + ipc::circ::prod_cons + > el_arr_smn; + ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_smn](auto index) { + benchmark_prod_cons<1, decltype(index)::value + 1, LoopCount, void>(&el_arr_smn); + }); + + ipc::circ::elem_array< + sizeof(msg_t), + ipc::circ::prod_cons + > el_arr_mmn; + ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmn](auto index) { + benchmark_prod_cons<1, decltype(index)::value + 1, LoopCount, void>(&el_arr_mmn); + }); + ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmn](auto index) { + benchmark_prod_cons(&el_arr_mmn); + }); + ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [](auto index) { test_prod_cons<1, decltype(index)::value + 1, false>(); });