From 8c75f8ad843d19857ae6d5333186374d977a0f6c Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 29 Dec 2018 18:31:01 +0800 Subject: [PATCH] pool_alloc (TBD) --- README.md | 2 +- src/channel.inc | 2 +- src/ipc.cpp | 33 ++++++++-- src/memory/alloc.hpp | 128 ++++++++++++++++++++++++------------- src/memory/resource.hpp | 58 +++++++++-------- src/memory/wrapper.hpp | 55 ++++++++++++++-- src/platform/shm_linux.cpp | 2 +- src/platform/shm_win.cpp | 2 +- 8 files changed, 201 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index c798800..18e1705 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ A high-performance inter-process communication using shared memory on Linux/Wind ## Performance - | | Environment | + | Environment | Value | | ------ | ------ | | Device | Lenovo ThinkPad T450 | | CPU | Intel(R) Core(TM) i5-4300U @ 2.5 GHz | diff --git a/src/channel.inc b/src/channel.inc index 8f58e92..439e2e0 100644 --- a/src/channel.inc +++ b/src/channel.inc @@ -4,8 +4,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/src/ipc.cpp b/src/ipc.cpp index 399cb19..64188b2 100644 --- a/src/ipc.cpp +++ b/src/ipc.cpp @@ -46,6 +46,29 @@ constexpr queue_t* queue_of(handle_t h) { return static_cast(h); } +using cache_t = mem::vector; + +template +cache_t make_cache(byte_t const (& data)[N]) { + return { + static_cast(data), + static_cast(data) + N + }; +} + +template +using remove_cv_ref_t = std::remove_cv_t>; + +template +constexpr auto to_buff(Cache&& cac) -> Requires, buff_t>::value, buff_t> { + return cac; +} + +template +auto to_buff(Cache&& cac) -> Requires, buff_t>::value, buff_t> { + return make_buff(cac.data(), cac.size()); +} + inline auto& recv_cache() { /* thread_local may have some bugs. @@ -56,12 +79,12 @@ inline auto& recv_cache() { https://developercommunity.visualstudio.com/content/problem/124121/thread-local-variables-fail-to-be-initialized-when.html https://software.intel.com/en-us/forums/intel-c-compiler/topic/684827 */ - static tls::pointer> rc; + static tls::pointer> rc; return *rc.create(); } inline auto& queues_cache() { - static tls::pointer> qc; + static tls::pointer> qc; return *qc.create(); } @@ -168,7 +191,7 @@ buff_t multi_recv(F&& upd) { return make_buff(msg.data_, remain); } // cache the first message fragment - else rc.emplace(msg.id_, make_buff(msg.data_)); + else rc.emplace(msg.id_, make_cache(msg.data_)); } // has cached before this message else { @@ -177,9 +200,9 @@ buff_t multi_recv(F&& upd) { if (msg.remain_ <= 0) { cache.insert(cache.end(), msg.data_, msg.data_ + remain); // finish this message, erase it from cache - auto buf = std::move(cache); + auto cac = std::move(cache); rc.erase(cache_it); - return buf; + return to_buff(std::move(cac)); } // there are remain datas after this message cache.insert(cache.end(), msg.data_, msg.data_ + data_length); diff --git a/src/memory/alloc.hpp b/src/memory/alloc.hpp index fc6a845..9b125ce 100644 --- a/src/memory/alloc.hpp +++ b/src/memory/alloc.hpp @@ -2,19 +2,22 @@ #include #include +#include #include #include "def.h" namespace ipc { -namespace memory { +namespace mem { -struct static_alloc { +class static_alloc { +public: static constexpr std::size_t remain() { return (std::numeric_limits::max)(); } static constexpr void clear() {} + static constexpr void swap(static_alloc&) {} static void* alloc(std::size_t size) { return size ? std::malloc(size) : nullptr; @@ -33,19 +36,40 @@ struct static_alloc { /// Scope allocation -- The destructor will release all allocated blocks. //////////////////////////////////////////////////////////////// +namespace detail { + +class scope_alloc_base { +protected: + struct block_t { + block_t* next_; + }; + block_t* list_ = nullptr; + +public: + std::size_t remain() const { + std::size_t c = 0; + auto curr = list_; + while (curr != nullptr) { + ++c; + curr = curr->next_; + } + return c; + } + + void free(void* /*p*/) {} + void free(void* /*p*/, std::size_t) {} +}; + +} // namespace detail + template -class scope_alloc { +class scope_alloc : public detail::scope_alloc_base { public: using alloc_policy = AllocP; private: alloc_policy alloc_; - struct block_t { - block_t* next_; - }; - block_t* list_ = nullptr; - public: scope_alloc() = default; @@ -60,16 +84,6 @@ public: std::swap(this->list_ , rhs.list_); } - std::size_t remain() const { - std::size_t c = 0; - auto curr = list_; - while (curr != nullptr) { - ++c; - curr = curr->next_; - } - return c; - } - void clear() { while (list_ != nullptr) { auto curr = list_; @@ -85,16 +99,59 @@ public: curr->next_ = list_; return ((list_ = curr) + 1); } - - void free(void* /*p*/) {} }; //////////////////////////////////////////////////////////////// /// Fixed-size blocks allocation //////////////////////////////////////////////////////////////// +namespace detail { + +class fixed_pool_base { +protected: + std::size_t init_expand_; + std::size_t iter_; + void* cursor_; + + void init(std::size_t init_expand) { + iter_ = init_expand_ = init_expand; + cursor_ = nullptr; + } + + static void** node_p(void* node) { + return reinterpret_cast(node); + } + + static auto& next(void* node) { + return *node_p(node); + } + +public: + std::size_t remain() const { + std::size_t c = 0; + void* curr = cursor_; + while (curr != nullptr) { + ++c; + curr = next(curr); + } + return c; + } + + void free(void* p) { + if (p == nullptr) return; + next(p) = cursor_; + cursor_ = p; + } + + void free(void* p, std::size_t) { + free(p); + } +}; + +} // namespace detail + template > -class fixed_pool { +class fixed_pool : public detail::fixed_pool_base { public: using alloc_policy = AllocP; @@ -104,22 +161,15 @@ public: private: alloc_policy alloc_; - std::size_t init_expand_, iter_; - void* cursor_; void expand() { - void** p = reinterpret_cast(cursor_ = alloc_.alloc(block_size * iter_)); + auto p = node_p(cursor_ = alloc_.alloc(block_size * iter_)); for (std::size_t i = 0; i < iter_ - 1; ++i) - p = reinterpret_cast((*p) = reinterpret_cast(p) + block_size); + p = node_p((*p) = reinterpret_cast(p) + block_size); (*p) = nullptr; iter_ *= 2; } - void init(std::size_t init_expand) { - iter_ = init_expand_ = init_expand; - cursor_ = nullptr; - } - public: explicit fixed_pool(std::size_t init_expand = 1) { init(init_expand); @@ -139,13 +189,7 @@ public: } std::size_t remain() const { - std::size_t c = 0; - void* curr = cursor_; - while (curr != nullptr) { - ++c; - curr = *reinterpret_cast(curr); // curr = next - } - return c * block_size; + return detail::fixed_pool_base::remain() * block_size; } void clear() { @@ -156,16 +200,14 @@ public: void* alloc() { if (cursor_ == nullptr) expand(); void* p = cursor_; - cursor_ = *reinterpret_cast(p); + cursor_ = next(p); return p; } - void free(void* p) { - if (p == nullptr) return; - *reinterpret_cast(p) = cursor_; - cursor_ = p; + void* alloc(std::size_t) { + return alloc(); } }; -} // namespace memory +} // namespace mem } // namespace ipc diff --git a/src/memory/resource.hpp b/src/memory/resource.hpp index 43b29bb..fa87f93 100644 --- a/src/memory/resource.hpp +++ b/src/memory/resource.hpp @@ -1,27 +1,31 @@ #pragma once #include -#include #include #include #include #include - -#include "tls_pointer.h" +#include #include "memory/alloc.hpp" #include "memory/wrapper.hpp" +#include "tls_pointer.h" + namespace ipc { -namespace memory { +namespace mem { namespace detail { -template -void switch_constexpr(std::size_t i, std::index_sequence, F&& f) { - [[maybe_unused]] std::initializer_list expand { - (Comp{}(i, I) && (f(std::integral_constant{}), 0))... - }; +template +constexpr decltype(auto) switch_constexpr(std::size_t /*i*/, std::index_sequence<>, F&& /*f*/, D&& def) { + return def(); +} + +template +constexpr decltype(auto) switch_constexpr(std::size_t i, std::index_sequence, F&& f, D&& def) { + return (i == N) ? f(std::integral_constant{}) : + switch_constexpr(i, std::index_sequence{}, f, def); } } // namespace detail @@ -35,18 +39,21 @@ private: } template - static void choose(std::size_t size, F&& f) { + static decltype(auto) choose(std::size_t size, F&& f) { enum : std::size_t { base_size = sizeof(void*) }; - detail::switch_constexpr>(size, std::index_sequence< + size = ((size - 1) & (~(base_size - 1))) + base_size; + return detail::switch_constexpr(size, std::index_sequence< base_size , base_size * 2 , - base_size * 4 , base_size * 6 , - base_size * 8 , base_size * 12, - base_size * 16, base_size * 20, - base_size * 24, base_size * 28, - base_size * 32, base_size * 40, - base_size * 48, base_size * 56, - base_size * 64 - >{}, [&f](auto index) { f(fixed()); }); + 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 + >{}, [&f](auto index) { + return f(fixed()); + }, [&f] { return f(static_alloc{}); }); } public: @@ -63,23 +70,24 @@ public: static constexpr void clear() {} static void* alloc(std::size_t size) { - void* p; - choose(size, [&p](auto& fp) { p = fp.alloc(); }); - return p; + return choose(size, [size](auto&& fp) { return fp.alloc(size); }); } static void free(void* p, std::size_t size) { - choose(size, [p](auto& fp) { fp.free(p); }); + choose(size, [p](auto&& fp) { fp.free(p); }); } }; template using allocator = allocator_wrapper; -template +template using unordered_map = std::unordered_map< Key, T//, std::hash, std::equal_to, allocator> >; -} // namespace memory +template +using vector = std::vector*/>; + +} // namespace mem } // namespace ipc diff --git a/src/memory/wrapper.hpp b/src/memory/wrapper.hpp index f8a07c5..69fb531 100644 --- a/src/memory/wrapper.hpp +++ b/src/memory/wrapper.hpp @@ -1,14 +1,61 @@ #pragma once -#include #include #include +#include +#include +#include +#include + +#include "rw_lock.h" +#include "tls_pointer.h" namespace ipc { -namespace memory { +namespace mem { //////////////////////////////////////////////////////////////// -/// The allocator wrapper class +/// Thread-safe allocation wrapper +//////////////////////////////////////////////////////////////// + +template +class synchronized_pool { +public: + using alloc_policy = AllocP; + +private: + rw_lock lc_; + std::vector allocs_; + + struct alloc_t { + synchronized_pool* t_; + alloc_policy* alc_; + + alloc_t(synchronized_pool* t) + : t_ { t } + {} + + ~alloc_t() { + + } + }; + +public: + static constexpr std::size_t remain() { + return (std::numeric_limits::max)(); + } + + static void* alloc() { + static tls::pointer alc; + return nullptr; + } + + static void* alloc(std::size_t) { + return alloc(); + } +}; + +//////////////////////////////////////////////////////////////// +/// The allocator wrapper class for STL //////////////////////////////////////////////////////////////// template @@ -106,5 +153,5 @@ constexpr bool operator!=(const allocator_wrapper&, const allocator_w return false; } -} // namespace memory +} // namespace mem } // namespace ipc diff --git a/src/platform/shm_linux.cpp b/src/platform/shm_linux.cpp index 13d47e5..e5d94ac 100644 --- a/src/platform/shm_linux.cpp +++ b/src/platform/shm_linux.cpp @@ -25,7 +25,7 @@ constexpr void* mem_of(void* mem) { } inline auto& m2h() { - static ipc::tls::pointer> cache; + static ipc::tls::pointer> cache; return *cache.create(); } diff --git a/src/platform/shm_win.cpp b/src/platform/shm_win.cpp index 130102f..2b4f612 100644 --- a/src/platform/shm_win.cpp +++ b/src/platform/shm_win.cpp @@ -28,7 +28,7 @@ constexpr auto to_tchar(std::string && str) -> IsSame { } inline auto& m2h() { - static ipc::tls::pointer> cache; + static ipc::tls::pointer> cache; return *cache.create(); }