diff options
Diffstat (limited to 'src/lib/netlist/plib/pmempool.h')
-rw-r--r-- | src/lib/netlist/plib/pmempool.h | 283 |
1 files changed, 149 insertions, 134 deletions
diff --git a/src/lib/netlist/plib/pmempool.h b/src/lib/netlist/plib/pmempool.h index 769d2f653b5..29712601237 100644 --- a/src/lib/netlist/plib/pmempool.h +++ b/src/lib/netlist/plib/pmempool.h @@ -1,21 +1,21 @@ -// license:GPL-2.0+ +// license:BSD-3-Clause // copyright-holders:Couriersud -/* - * pmempool.h - * - */ #ifndef PMEMPOOL_H_ #define PMEMPOOL_H_ +/// +/// \file pmempool.h +/// + #include "palloc.h" -#include "pstream.h" -#include "pstring.h" +#include "pconfig.h" +#include "pstream.h" // perrlogger +//#include "pstring.h" #include "ptypes.h" -#include "putil.h" +//#include "putil.h" #include <algorithm> -//#include <cstddef> #include <memory> #include <unordered_map> #include <utility> @@ -27,30 +27,39 @@ namespace plib { // Memory pool //============================================================ - class mempool + template <typename BASEARENA, std::size_t MINALIGN = PALIGN_MIN_SIZE> + class mempool_arena : public arena_base<mempool_arena<BASEARENA, MINALIGN>, MINALIGN, false, false> { + public: + + using size_type = typename BASEARENA::size_type; + using base_type = arena_base<mempool_arena<BASEARENA, MINALIGN>, MINALIGN, false, false>; + + template <class T> + using base_allocator_type = typename BASEARENA::template allocator_type<T>; + using block_align = std::integral_constant<size_t, 1024>; + + mempool_arena(size_t min_alloc = (1<<21)); + + PCOPYASSIGNMOVE(mempool_arena, delete) + + ~mempool_arena(); + + void *allocate(size_t align, size_t size); + + void deallocate(void *ptr, std::size_t alignment, size_t size) noexcept; + + bool operator ==(const mempool_arena &rhs) const noexcept { return this == &rhs; } + private: struct block { - block(mempool *mp, std::size_t min_bytes) - : m_num_alloc(0) - , m_cur(0) - , m_data(nullptr) - , m_mempool(mp) - { - min_bytes = std::max(mp->m_min_alloc, min_bytes); - m_free = min_bytes; - std::size_t alloc_bytes = (min_bytes + mp->m_min_align); // - 1); // & ~(mp->m_min_align - 1); - //m_data_allocated = ::operator new(alloc_bytes); - m_data_allocated = new char[alloc_bytes]; - void *r = m_data_allocated; - std::align(mp->m_min_align, min_bytes, r, alloc_bytes); - m_data = reinterpret_cast<char *>(r); - } + block(mempool_arena &mp, size_type min_bytes); ~block() { //::operator delete(m_data_allocated); - delete [] m_data_allocated; + //delete [] m_data_allocated; + m_mempool.base_arena().deallocate(m_data_allocated, mempool_arena::block_align(), m_bytes_allocated); } block(const block &) = delete; @@ -58,151 +67,157 @@ namespace plib { block &operator =(const block &) = delete; block &operator =(block &&) = delete; - std::size_t m_num_alloc; - std::size_t m_free; - std::size_t m_cur; - char *m_data; - char *m_data_allocated; - mempool *m_mempool; + size_type m_num_alloc; + size_type m_free; + size_type m_cur; + size_type m_bytes_allocated; + std::uint8_t *m_data; + std::uint8_t *m_data_allocated; + mempool_arena &m_mempool; }; struct info { - info(block *b, std::size_t p) : m_block(b), m_pos(p) { } + info(block *b, size_type p, size_type orig_size) : m_block(b), m_pos(p), m_orig_size(orig_size) { } + info(const info &) = default; + info &operator=(const info &) = default; + info(info &&) noexcept = default; + info &operator=(info &&) noexcept = default; ~info() = default; - COPYASSIGNMOVE(info, default) block * m_block; - std::size_t m_pos; + size_type m_pos; + size_type m_orig_size; }; - - block * new_block(std::size_t min_bytes) + block * new_block(size_type min_bytes) { - auto *b = plib::pnew<block>(this, min_bytes); + auto *b = detail::alloc<block, 0>(base_arena(), *this, min_bytes); m_blocks.push_back(b); return b; } - - static std::unordered_map<void *, info> &sinfo() + size_t m_min_alloc; + static BASEARENA &base_arena() { - static std::unordered_map<void *, info> spinfo; - return spinfo; + static BASEARENA s_arena; + return s_arena; } - size_t m_min_alloc; - size_t m_min_align; + using info_type = std::pair<void * const, info>; - std::vector<block *> m_blocks; + using info_allocator_type = typename BASEARENA::template allocator_type<info_type>; + std::unordered_map<void *, info, std::hash<void *>, std::equal_to<>, + info_allocator_type> m_info; - public: - static constexpr const bool is_stateless = false; - template <class T, std::size_t ALIGN = alignof(T)> - using allocator_type = arena_allocator<mempool, T, ALIGN>; + plib::arena_vector<BASEARENA, block *> m_blocks; - mempool(size_t min_alloc = (1<<21), size_t min_align = 16) - : m_min_alloc(min_alloc), m_min_align(min_align) - { - } + }; - COPYASSIGNMOVE(mempool, delete) + template <typename BASEARENA, std::size_t MINALIGN> + mempool_arena<BASEARENA, MINALIGN>::mempool_arena(size_t min_alloc) + : m_min_alloc(min_alloc) + //, m_blocks(base_allocator_type<block *>(base_arena())) + , m_blocks(base_arena()) + { + } - ~mempool() + template <typename BASEARENA, std::size_t MINALIGN> + mempool_arena<BASEARENA, MINALIGN>::~mempool_arena() + { + for (auto & b : m_blocks) { - - for (auto & b : m_blocks) + if (b->m_num_alloc != 0) { - if (b->m_num_alloc != 0) - { - plib::perrlogger("Found {} info blocks\n", sinfo().size()); - plib::perrlogger("Found block with {} dangling allocations\n", b->m_num_alloc); - } - plib::pdelete(b); - //::operator delete(b->m_data); + plib::perrlogger("Found {} info blocks\n", m_info.size()); + plib::perrlogger("Found block with {} dangling allocations\n", b->m_num_alloc); } + detail::free<0>(base_arena(), b); } + if (!m_info.empty()) + plib::perrlogger("Still found {} info blocks after mempool deleted\n", m_info.size()); + } - void *allocate(size_t align, size_t size) - { - block *b = nullptr; + template <typename BASEARENA, std::size_t MINALIGN> + void * mempool_arena<BASEARENA, MINALIGN>::allocate(size_t align, size_t size) + { + block *b = nullptr; - if (align < m_min_align) - align = m_min_align; + if (align < MINALIGN) + align = MINALIGN; - size_t rs = size + align; - for (auto &bs : m_blocks) - { - if (bs->m_free > rs) - { - b = bs; - break; - } - } - if (b == nullptr) - { - b = new_block(rs); - } - b->m_free -= rs; - b->m_num_alloc++; - void *ret = reinterpret_cast<void *>(b->m_data + b->m_cur); - auto capacity(rs); - ret = std::align(align, size, ret, capacity); - sinfo().insert({ ret, info(b, b->m_cur)}); - rs -= (capacity - size); - b->m_cur += rs; - - return ret; - } + size_t rs = size + align; - static void deallocate(void *ptr) + for (auto &bs : m_blocks) { - - auto it = sinfo().find(ptr); - if (it == sinfo().end()) - plib::terminate("mempool::free - pointer not found\n"); - block *b = it->second.m_block; - if (b->m_num_alloc == 0) - plib::terminate("mempool::free - double free was called\n"); - else + if (bs->m_free > rs) { - b->m_num_alloc--; - //printf("Freeing in block %p %lu\n", b, b->m_num_alloc); - if (b->m_num_alloc == 0) - { - mempool *mp = b->m_mempool; - auto itb = std::find(mp->m_blocks.begin(), mp->m_blocks.end(), b); - if (itb == mp->m_blocks.end()) - plib::terminate("mempool::free - block not found\n"); - - mp->m_blocks.erase(itb); - plib::pdelete(b); - } - sinfo().erase(it); + b = bs; + break; } } - - template <typename T> - using owned_pool_ptr = plib::owned_ptr<T, arena_deleter<mempool, T>>; - - template<typename T, typename... Args> - owned_pool_ptr<T> make_poolptr(Args&&... args) + if (b == nullptr) { - auto *mem = this->allocate(alignof(T), sizeof(T)); - try - { - auto *mema = new (mem) T(std::forward<Args>(args)...); - return owned_pool_ptr<T>(mema, true, arena_deleter<mempool, T>(this)); - } - catch (...) - { - this->deallocate(mem); - throw; - } + b = new_block(rs); } + b->m_free -= rs; + b->m_num_alloc++; + void *ret = reinterpret_cast<void *>(b->m_data + b->m_cur); // NOLINT(cppcoreguidelines-pro-type-reinterpret + auto capacity(rs); + ret = std::align(align, size, ret, capacity); + m_info.insert({ ret, info(b, b->m_cur, size)}); + rs -= (capacity - size); + b->m_cur += rs; + this->inc_alloc_stat(size); + + return ret; + } + + template <typename BASEARENA, std::size_t MINALIGN> + void mempool_arena<BASEARENA, MINALIGN>::deallocate(void *ptr, [[maybe_unused]] std::size_t alignment, size_t size) noexcept + { + auto it = m_info.find(ptr); + if (it == m_info.end()) + plib::terminate("mempool::free - pointer not found"); + block *b = it->second.m_block; + if (b->m_num_alloc == 0) + plib::terminate("mempool::free - double free was called"); + if (it->second.m_orig_size != size) + plib::perrlogger("Size mismatch original {} vs {}\n", it->second.m_orig_size, size); + + mempool_arena &mp = b->m_mempool; + b->m_num_alloc--; + mp.dec_alloc_stat(size); + if (b->m_num_alloc == 0) + { + auto itb = std::find(mp.m_blocks.begin(), mp.m_blocks.end(), b); + if (itb == mp.m_blocks.end()) + plib::terminate("mempool::free - block not found"); - }; + mp.m_blocks.erase(itb); + detail::free<0>(mp.base_arena(), b); + } + m_info.erase(it); + } + + template <typename BASEARENA, std::size_t MINALIGN> + mempool_arena<BASEARENA, MINALIGN>::block::block(mempool_arena &mp, size_type min_bytes) + : m_num_alloc(0) + , m_cur(0) + , m_data(nullptr) + , m_mempool(mp) + { + min_bytes = std::max(mp.m_min_alloc, min_bytes); + m_free = min_bytes; + m_bytes_allocated = (min_bytes + mempool_arena::block_align()); // - 1); // & ~(mp.m_min_align - 1); + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + //m_data_allocated = new std::uint8_t[alloc_bytes]; + m_data_allocated = static_cast<std::uint8_t *>(mp.base_arena().allocate(mempool_arena::block_align(), m_bytes_allocated)); + void *r = m_data_allocated; + std::align(mempool_arena::block_align(), min_bytes, r, m_bytes_allocated); + m_data = reinterpret_cast<std::uint8_t *>(r); // NOLINT(cppcoreguidelines-pro-type-reinterpret + } } // namespace plib -#endif /* PMEMPOOL_H_ */ +#endif // PMEMPOOL_H_ |