diff --git a/include/def.h b/include/def.h index d02f112..0360ecf 100644 --- a/include/def.h +++ b/include/def.h @@ -2,7 +2,7 @@ #include #include -#include +#include // std::numeric_limits #include #include diff --git a/src/memory/alloc.h b/src/memory/alloc.h index a7113f3..f640b11 100755 --- a/src/memory/alloc.h +++ b/src/memory/alloc.h @@ -2,9 +2,9 @@ #include #include -#include -#include #include +#include // std::numeric_limits +#include #include // assert #include "def.h" @@ -41,7 +41,7 @@ public: namespace detail { constexpr std::size_t aligned(std::size_t size, size_t alignment) noexcept { - return ((size - 1) & ~(alignment - 1)) + alignment; + return ( (size - 1) & ~(alignment - 1) ) + alignment; } IPC_CONCEPT_(has_take, take(std::move(std::declval()))); @@ -49,8 +49,8 @@ IPC_CONCEPT_(has_take, take(std::move(std::declval()))); class scope_alloc_base { protected: struct block_t { - block_t * next_; std::size_t size_; + block_t * next_; } * head_ = nullptr, * tail_ = nullptr; enum : std::size_t { @@ -127,9 +127,10 @@ public: } void* alloc(std::size_t size) { - auto curr = static_cast(alloc_.alloc(size += aligned_block_size)); + std::size_t real_size = aligned_block_size + size; + auto curr = static_cast(alloc_.alloc(real_size)); + curr->size_ = real_size; curr->next_ = head_; - curr->size_ = size; head_ = curr; if (tail_ == nullptr) { tail_ = curr; @@ -272,11 +273,13 @@ public: } // namespace detail -template +template ::max)()> struct fixed_expand_policy { enum : std::size_t { - base_size = BaseSize + base_size = BaseSize, + limit_size = LimitSize }; constexpr static std::size_t prev(std::size_t e) noexcept { @@ -289,7 +292,7 @@ struct fixed_expand_policy { static std::size_t next(std::size_t block_size, std::size_t & e) { auto n = ipc::detail::max(block_size, base_size) * e; - e = next(e); + e = ipc::detail::min(limit_size, next(e)); return n; } }; @@ -302,7 +305,7 @@ public: using base_t = detail::fixed_alloc; enum : std::size_t { - block_size = (ipc::detail::max)(BlockSize, sizeof(void*)) + block_size = ipc::detail::max(BlockSize, sizeof(void*)) }; public: @@ -334,35 +337,32 @@ namespace detail { class variable_alloc_base { protected: - struct head_t { - std::size_t free_; - } * head_ = nullptr; - - enum : std::size_t { - aligned_head_size = aligned(sizeof(head_t), alignof(std::max_align_t)) - }; - - static byte_t * buffer(head_t* p) { - return reinterpret_cast(p) + aligned_head_size + p->free_; - } + byte_t * head_ = nullptr, * tail_ = nullptr; public: - bool operator<(variable_alloc_base const & right) const { - return remain() < right.remain(); - } - - void swap(variable_alloc_base& rhs) { + void swap(variable_alloc_base & rhs) { std::swap(head_, rhs.head_); + std::swap(tail_, rhs.tail_); } std::size_t remain() const noexcept { - return (head_ == nullptr) ? 0 : head_->free_; + return static_cast(tail_ - head_); } bool empty() const noexcept { return remain() == 0; } + void take(variable_alloc_base && rhs) { + if (remain() < rhs.remain()) { + // replace this by rhs + head_ = rhs.head_; + tail_ = rhs.tail_; + } + // discard rhs + rhs.head_ = rhs.tail_ = nullptr; + } + void free(void* /*p*/) {} void free(void* /*p*/, std::size_t) {} }; @@ -373,35 +373,15 @@ template - struct fixed_alloc_t : public fixed_alloc {}; - - template - using allocator = allocator_wrapper>; - - std::map, - allocator> - > reserves_; - alloc_policy alloc_; - void take_base(variable_alloc && rhs) { - if (rhs.remain() > remain()) { - if (!empty()) { - reserves_.emplace(head_->free_, head_); - } - head_ = rhs.head_; - } - else if (!rhs.empty()) { - reserves_.emplace(rhs.head_->free_, rhs.head_); - } - rhs.head_ = nullptr; - } - public: variable_alloc() = default; @@ -415,38 +395,28 @@ public: template auto take(variable_alloc && rhs) -> ipc::require::value> { - take_base(std::move(rhs)); + base_t::take(std::move(rhs)); alloc_.take(std::move(rhs.alloc_)); } - template - auto take(variable_alloc && rhs) -> ipc::require::value> { - take_base(std::move(rhs)); - } - void* alloc(std::size_t size) { - if (size >= ChunkSize) { - return alloc_.alloc(size); - } + /* + * byte alignment is always alignof(std::max_align_t). + */ + size = detail::aligned(size, alignof(std::max_align_t)); + void* ptr; + // size would never be 0 here if (remain() < size) { - auto it = reserves_.begin(); - if ((it == reserves_.end()) || (it->first < size)) { - head_ = static_cast(alloc_.alloc(ChunkSize + aligned_head_size)); - head_->free_ = ChunkSize - size; - } - else { - auto temp = it->second; - temp->free_ -= size; - reserves_.erase(it); - if (remain() < temp->free_) { - head_ = temp; - } - else return base_t::buffer(temp); - } + std::size_t chunk_size = ipc::detail::max(aligned_chunk_size, size); + ptr = alloc_.alloc(chunk_size); + tail_ = static_cast(ptr) + chunk_size; + head_ = tail_ - (chunk_size - size); } - // size shouldn't be 0 here, otherwise behavior is undefined - else head_->free_ -= size; - return base_t::buffer(head_); + else { + ptr = head_; + head_ += size; + } + return ptr; } }; diff --git a/src/memory/resource.h b/src/memory/resource.h index a410034..3efc285 100755 --- a/src/memory/resource.h +++ b/src/memory/resource.h @@ -17,9 +17,12 @@ namespace ipc { namespace mem { -using async_pool_alloc = - static_wrapper >>>>; +using async_pool_alloc = static_wrapper, + fixed_expand_policy + >, + default_recycler >>>; template using allocator = allocator_wrapper; diff --git a/src/memory/wrapper.h b/src/memory/wrapper.h index f0a20d0..353fcc4 100755 --- a/src/memory/wrapper.h +++ b/src/memory/wrapper.h @@ -25,8 +25,17 @@ namespace mem { /// Thread-safe allocation wrapper //////////////////////////////////////////////////////////////// +namespace detail { + +IPC_CONCEPT_(is_comparable, operator<(std::declval())); + +} // namespace detail + +template ::value> +class limited_recycler; + template -class limited_recycler { +class limited_recycler { public: using alloc_policy = AllocP; @@ -35,10 +44,10 @@ protected: struct fixed_alloc_t : public fixed_alloc {}; template - using allocator = allocator_wrapper>; + using allocator = ipc::mem::allocator_wrapper>; - std::set, - allocator + std::multiset, + allocator > master_allocs_; ipc::spin_lock master_lock_; @@ -64,16 +73,13 @@ public: void collect(alloc_policy && alc) { IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_); - auto it = master_allocs_.find(alc); - if (it == master_allocs_.end()) { - master_allocs_.emplace(std::move(alc)); + if (master_allocs_.size() >= 32) { + take_first_do([](alloc_policy &) {}); // erase first } - else const_cast(*it).swap(alc); - // if (master_allocs_.size() <= 32) return; - // take_first_do([](alloc_policy &) {}); // erase first + master_allocs_.emplace(std::move(alc)); } - constexpr static auto try_replenish(alloc_policy&, std::size_t) noexcept {} + constexpr auto try_replenish(alloc_policy&, std::size_t) noexcept {} }; template @@ -125,10 +131,10 @@ class empty_recycler { public: using alloc_policy = AllocP; - constexpr static void swap(empty_recycler&) noexcept {} - constexpr static void try_recover(alloc_policy&) noexcept {} - constexpr static auto try_replenish(alloc_policy&, std::size_t) noexcept {} - constexpr static void collect(alloc_policy&&) noexcept {} + constexpr void swap(empty_recycler&) noexcept {} + constexpr void try_recover(alloc_policy&) noexcept {} + constexpr auto try_replenish(alloc_policy&, std::size_t) noexcept {} + constexpr void collect(alloc_policy&&) noexcept {} }; template