From 573ebca3d2e4de325d9a18e3ffcabea908c99de1 Mon Sep 17 00:00:00 2001 From: Arenoros Date: Tue, 29 Aug 2023 13:33:31 +0300 Subject: [PATCH] Optimization of msgpack::zone size on the stack and deferred memory allocation --- include/msgpack/v1/detail/cpp11_zone.hpp | 207 ++++++++++------------- 1 file changed, 92 insertions(+), 115 deletions(-) diff --git a/include/msgpack/v1/detail/cpp11_zone.hpp b/include/msgpack/v1/detail/cpp11_zone.hpp index 2586f275..544d306a 100644 --- a/include/msgpack/v1/detail/cpp11_zone.hpp +++ b/include/msgpack/v1/detail/cpp11_zone.hpp @@ -25,70 +25,51 @@ namespace msgpack { /// @cond MSGPACK_API_VERSION_NAMESPACE(v1) { /// @endcond - + class zone { private: struct finalizer { - finalizer(void (*func)(void*), void* data):m_func(func), m_data(data) {} + finalizer(void (*func)(void*), void* data, finalizer* next): m_func(func), m_data(data), m_next(next) {} void operator()() { m_func(m_data); } void (*m_func)(void*); void* m_data; + finalizer* m_next{}; }; struct finalizer_array { - finalizer_array():m_tail(MSGPACK_NULLPTR), m_end(MSGPACK_NULLPTR), m_array(MSGPACK_NULLPTR) {} - void call() { - finalizer* fin = m_tail; - for(; fin != m_array; --fin) (*(fin-1))(); + finalizer_array(): m_head(MSGPACK_NULLPTR) {} + + void call(bool clear = false) { + finalizer* fin = m_head; + finalizer* tmp = nullptr; + while(fin) { + (*(fin-1))(); + if (clear) { + tmp = fin; + } + fin = fin->m_next; + if (clear) { + delete tmp; + } + } } ~finalizer_array() { - call(); - ::free(m_array); + call(true); } void clear() { - call(); - m_tail = m_array; + call(true); } void push(void (*func)(void* data), void* data) { - finalizer* fin = m_tail; - - if(fin == m_end) { - push_expand(func, data); - return; - } - - fin->m_func = func; - fin->m_data = data; - - ++m_tail; + m_head = new finalizer(func, data, m_head); } - void push_expand(void (*func)(void*), void* data) { - const size_t nused = static_cast(m_end - m_array); - size_t nnext; - if(nused == 0) { - nnext = (sizeof(finalizer) < 72/2) ? - 72 / sizeof(finalizer) : 8; - } else { - nnext = nused * 2; - } - finalizer* tmp = - static_cast(::realloc(m_array, sizeof(finalizer) * nnext)); - if(!tmp) { - throw std::bad_alloc(); - } - m_array = tmp; - m_end = tmp + nnext; - m_tail = tmp + nused; - new (m_tail) finalizer(func, data); - - ++m_tail; + void pop() { + auto n = m_head->m_next; + delete m_head; + m_head = n; } - finalizer_array(finalizer_array&& other) noexcept - :m_tail(other.m_tail), m_end(other.m_end), m_array(other.m_array) - { - other.m_tail = MSGPACK_NULLPTR; - other.m_end = MSGPACK_NULLPTR; - other.m_array = MSGPACK_NULLPTR; + + finalizer_array(finalizer_array&& other) noexcept: m_head(other.m_head) { + other.m_head = MSGPACK_NULLPTR; } finalizer_array& operator=(finalizer_array&& other) noexcept { @@ -96,10 +77,7 @@ private: new (this) finalizer_array(std::move(other)); return *this; } - - finalizer* m_tail; - finalizer* m_end; - finalizer* m_array; + finalizer* m_head; private: finalizer_array(const finalizer_array&); @@ -109,20 +87,8 @@ private: chunk* m_next; }; struct chunk_list { - chunk_list(size_t chunk_size) - { - chunk* c = static_cast(::malloc(sizeof(chunk) + chunk_size)); - if(!c) { - throw std::bad_alloc(); - } - - m_head = c; - m_free = chunk_size; - m_ptr = reinterpret_cast(c) + sizeof(chunk); - c->m_next = MSGPACK_NULLPTR; - } - ~chunk_list() - { + chunk_list(size_t chunk_size, char* ptr): m_free(chunk_size), m_ptr(ptr), m_head(MSGPACK_NULLPTR) {} + ~chunk_list() { chunk* c = m_head; while(c) { chunk* n = c->m_next; @@ -130,48 +96,35 @@ private: c = n; } } - void clear(size_t chunk_size) + void clear(size_t chunk_size, char* ptr) { chunk* c = m_head; - while(true) { + while(c) { chunk* n = c->m_next; - if(n) { - ::free(c); - c = n; - } else { - m_head = c; - break; - } + ::free(c); + c = n; } m_head->m_next = MSGPACK_NULLPTR; m_free = chunk_size; - m_ptr = reinterpret_cast(m_head) + sizeof(chunk); - } - chunk_list(chunk_list&& other) noexcept - :m_free(other.m_free), m_ptr(other.m_ptr), m_head(other.m_head) - { - other.m_head = MSGPACK_NULLPTR; - } - chunk_list& operator=(chunk_list&& other) noexcept - { - this->~chunk_list(); - new (this) chunk_list(std::move(other)); - return *this; + m_ptr = ptr; } size_t m_free; char* m_ptr; chunk* m_head; private: + chunk_list(chunk_list&& other) noexcept = delete; + chunk_list& operator=(chunk_list&& other) noexcept = delete; chunk_list(const chunk_list&); chunk_list& operator=(const chunk_list&); }; size_t m_chunk_size; - chunk_list m_chunk_list; + chunk_list* m_chunk_list{}; finalizer_array m_finalizer_array; public: zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE); + ~zone(); public: void* allocate_align(size_t size, size_t align = MSGPACK_ZONE_ALIGN); @@ -223,53 +176,75 @@ private: static char* get_aligned(char* ptr, size_t align); + chunk_list& get_chank_lst(); + char* allocate_expand(size_t size); }; -inline zone::zone(size_t chunk_size):m_chunk_size(chunk_size), m_chunk_list(m_chunk_size) +inline zone::zone(size_t chunk_size):m_chunk_size(chunk_size), m_chunk_list(MSGPACK_NULLPTR) { } +inline zone::~zone() +{ + if(m_chunk_list) { + m_chunk_list->~chunk_list(); + ::free(m_chunk_list); + m_chunk_list = MSGPACK_NULLPTR; + } +} + inline char* zone::get_aligned(char* ptr, size_t align) { MSGPACK_ASSERT(align != 0 && (align & (align - 1)) == 0); // align must be 2^n (n >= 0) return - reinterpret_cast( - reinterpret_cast(ptr + (align - 1)) & ~static_cast(align - 1) - ); + reinterpret_cast( + reinterpret_cast(ptr + (align - 1)) & ~static_cast(align - 1) + ); +} + +inline zone::chunk_list& zone::get_chank_lst() +{ + if (!m_chunk_list) { + auto ptr = ::malloc(sizeof(chunk_list) + m_chunk_size); + if (!ptr) + throw std::bad_alloc(); + m_chunk_list = new (ptr) chunk_list(m_chunk_size, reinterpret_cast(ptr) + sizeof(chunk_list)); + } + return *m_chunk_list; } inline void* zone::allocate_align(size_t size, size_t align) { - char* aligned = get_aligned(m_chunk_list.m_ptr, align); - size_t adjusted_size = size + static_cast(aligned - m_chunk_list.m_ptr); - if (m_chunk_list.m_free < adjusted_size) { + chunk_list& chank_lst = get_chank_lst(); + char* aligned = get_aligned(chank_lst.m_ptr, align); + size_t adjusted_size = size + static_cast(aligned - chank_lst.m_ptr); + if (chank_lst.m_free < adjusted_size) { size_t enough_size = size + align - 1; char* ptr = allocate_expand(enough_size); aligned = get_aligned(ptr, align); - adjusted_size = size + static_cast(aligned - m_chunk_list.m_ptr); + adjusted_size = size + static_cast(aligned - chank_lst.m_ptr); } - m_chunk_list.m_free -= adjusted_size; - m_chunk_list.m_ptr += adjusted_size; + chank_lst.m_free -= adjusted_size; + chank_lst.m_ptr += adjusted_size; return aligned; } -inline void* zone::allocate_no_align(size_t size) -{ - char* ptr = m_chunk_list.m_ptr; - if(m_chunk_list.m_free < size) { +inline void* zone::allocate_no_align(size_t size) { + chunk_list& chank_lst = get_chank_lst(); + char* ptr = chank_lst.m_ptr; + if(chank_lst.m_free < size) { ptr = allocate_expand(size); } - m_chunk_list.m_free -= size; - m_chunk_list.m_ptr += size; + chank_lst.m_free -= size; + chank_lst.m_ptr += size; return ptr; } inline char* zone::allocate_expand(size_t size) { - chunk_list* const cl = &m_chunk_list; - + chunk_list& cl = get_chank_lst(); size_t sz = m_chunk_size; while(sz < size) { @@ -286,10 +261,10 @@ inline char* zone::allocate_expand(size_t size) char* ptr = reinterpret_cast(c) + sizeof(chunk); - c->m_next = cl->m_head; - cl->m_head = c; - cl->m_free = sz; - cl->m_ptr = ptr; + c->m_next = cl.m_head; + cl.m_head = c; + cl.m_free = sz; + cl.m_ptr = ptr; return ptr; } @@ -308,7 +283,9 @@ inline void zone::push_finalizer(msgpack::unique_ptr obj) inline void zone::clear() { m_finalizer_array.clear(); - m_chunk_list.clear(m_chunk_size); + if (m_chunk_list) { + m_chunk_list->clear(m_chunk_size, reinterpret_cast(m_chunk_list) + sizeof(chunk_list)); + } } inline void zone::swap(zone& o) @@ -328,10 +305,10 @@ void zone::object_destruct(void* obj) static_cast(obj)->~T(); } -inline void zone::undo_allocate(size_t size) -{ - m_chunk_list.m_ptr -= size; - m_chunk_list.m_free += size; +inline void zone::undo_allocate(size_t size) { + chunk_list& cl = get_chank_lst(); + cl.m_ptr -= size; + cl.m_free += size; } @@ -348,7 +325,7 @@ T* zone::allocate(Args... args) try { return new (x) T(args...); } catch (...) { - --m_finalizer_array.m_tail; + m_finalizer_array.pop(); undo_allocate(sizeof(T)); throw; }