Skip to content

Commit 573ebca

Browse files
committed
Optimization of msgpack::zone size on the stack and deferred memory allocation
1 parent 37fcaa1 commit 573ebca

File tree

1 file changed

+92
-115
lines changed

1 file changed

+92
-115
lines changed

include/msgpack/v1/detail/cpp11_zone.hpp

Lines changed: 92 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -25,81 +25,59 @@ namespace msgpack {
2525
/// @cond
2626
MSGPACK_API_VERSION_NAMESPACE(v1) {
2727
/// @endcond
28-
28+
2929
class zone {
3030
private:
3131
struct finalizer {
32-
finalizer(void (*func)(void*), void* data):m_func(func), m_data(data) {}
32+
finalizer(void (*func)(void*), void* data, finalizer* next): m_func(func), m_data(data), m_next(next) {}
3333
void operator()() { m_func(m_data); }
3434
void (*m_func)(void*);
3535
void* m_data;
36+
finalizer* m_next{};
3637
};
3738
struct finalizer_array {
38-
finalizer_array():m_tail(MSGPACK_NULLPTR), m_end(MSGPACK_NULLPTR), m_array(MSGPACK_NULLPTR) {}
39-
void call() {
40-
finalizer* fin = m_tail;
41-
for(; fin != m_array; --fin) (*(fin-1))();
39+
finalizer_array(): m_head(MSGPACK_NULLPTR) {}
40+
41+
void call(bool clear = false) {
42+
finalizer* fin = m_head;
43+
finalizer* tmp = nullptr;
44+
while(fin) {
45+
(*(fin-1))();
46+
if (clear) {
47+
tmp = fin;
48+
}
49+
fin = fin->m_next;
50+
if (clear) {
51+
delete tmp;
52+
}
53+
}
4254
}
4355
~finalizer_array() {
44-
call();
45-
::free(m_array);
56+
call(true);
4657
}
4758
void clear() {
48-
call();
49-
m_tail = m_array;
59+
call(true);
5060
}
5161
void push(void (*func)(void* data), void* data)
5262
{
53-
finalizer* fin = m_tail;
54-
55-
if(fin == m_end) {
56-
push_expand(func, data);
57-
return;
58-
}
59-
60-
fin->m_func = func;
61-
fin->m_data = data;
62-
63-
++m_tail;
63+
m_head = new finalizer(func, data, m_head);
6464
}
65-
void push_expand(void (*func)(void*), void* data) {
66-
const size_t nused = static_cast<size_t>(m_end - m_array);
67-
size_t nnext;
68-
if(nused == 0) {
69-
nnext = (sizeof(finalizer) < 72/2) ?
70-
72 / sizeof(finalizer) : 8;
71-
} else {
72-
nnext = nused * 2;
73-
}
74-
finalizer* tmp =
75-
static_cast<finalizer*>(::realloc(m_array, sizeof(finalizer) * nnext));
76-
if(!tmp) {
77-
throw std::bad_alloc();
78-
}
79-
m_array = tmp;
80-
m_end = tmp + nnext;
81-
m_tail = tmp + nused;
82-
new (m_tail) finalizer(func, data);
83-
84-
++m_tail;
65+
void pop() {
66+
auto n = m_head->m_next;
67+
delete m_head;
68+
m_head = n;
8569
}
86-
finalizer_array(finalizer_array&& other) noexcept
87-
:m_tail(other.m_tail), m_end(other.m_end), m_array(other.m_array)
88-
{
89-
other.m_tail = MSGPACK_NULLPTR;
90-
other.m_end = MSGPACK_NULLPTR;
91-
other.m_array = MSGPACK_NULLPTR;
70+
71+
finalizer_array(finalizer_array&& other) noexcept: m_head(other.m_head) {
72+
other.m_head = MSGPACK_NULLPTR;
9273
}
9374
finalizer_array& operator=(finalizer_array&& other) noexcept
9475
{
9576
this->~finalizer_array();
9677
new (this) finalizer_array(std::move(other));
9778
return *this;
9879
}
99-
100-
finalizer* m_tail;
101-
finalizer* m_end;
102-
finalizer* m_array;
80+
finalizer* m_head;
10381

10482
private:
10583
finalizer_array(const finalizer_array&);
@@ -109,69 +87,44 @@ class zone {
10987
chunk* m_next;
11088
};
11189
struct chunk_list {
112-
chunk_list(size_t chunk_size)
113-
{
114-
chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + chunk_size));
115-
if(!c) {
116-
throw std::bad_alloc();
117-
}
118-
119-
m_head = c;
120-
m_free = chunk_size;
121-
m_ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
122-
c->m_next = MSGPACK_NULLPTR;
123-
}
124-
~chunk_list()
125-
{
90+
chunk_list(size_t chunk_size, char* ptr): m_free(chunk_size), m_ptr(ptr), m_head(MSGPACK_NULLPTR) {}
91+
~chunk_list() {
12692
chunk* c = m_head;
12793
while(c) {
12894
chunk* n = c->m_next;
12995
::free(c);
13096
c = n;
13197
}
13298
}
133-
void clear(size_t chunk_size)
99+
void clear(size_t chunk_size, char* ptr)
134100
{
135101
chunk* c = m_head;
136-
while(true) {
102+
while(c) {
137103
chunk* n = c->m_next;
138-
if(n) {
139-
::free(c);
140-
c = n;
141-
} else {
142-
m_head = c;
143-
break;
144-
}
104+
::free(c);
105+
c = n;
145106
}
146107
m_head->m_next = MSGPACK_NULLPTR;
147108
m_free = chunk_size;
148-
m_ptr = reinterpret_cast<char*>(m_head) + sizeof(chunk);
149-
}
150-
chunk_list(chunk_list&& other) noexcept
151-
:m_free(other.m_free), m_ptr(other.m_ptr), m_head(other.m_head)
152-
{
153-
other.m_head = MSGPACK_NULLPTR;
154-
}
155-
chunk_list& operator=(chunk_list&& other) noexcept
156-
{
157-
this->~chunk_list();
158-
new (this) chunk_list(std::move(other));
159-
return *this;
109+
m_ptr = ptr;
160110
}
161111

162112
size_t m_free;
163113
char* m_ptr;
164114
chunk* m_head;
165115
private:
116+
chunk_list(chunk_list&& other) noexcept = delete;
117+
chunk_list& operator=(chunk_list&& other) noexcept = delete;
166118
chunk_list(const chunk_list&);
167119
chunk_list& operator=(const chunk_list&);
168120
};
169121
size_t m_chunk_size;
170-
chunk_list m_chunk_list;
122+
chunk_list* m_chunk_list{};
171123
finalizer_array m_finalizer_array;
172124

173125
public:
174126
zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE);
127+
~zone();
175128

176129
public:
177130
void* allocate_align(size_t size, size_t align = MSGPACK_ZONE_ALIGN);
@@ -223,53 +176,75 @@ class zone {
223176

224177
static char* get_aligned(char* ptr, size_t align);
225178

179+
chunk_list& get_chank_lst();
180+
226181
char* allocate_expand(size_t size);
227182
};
228183

229-
inline zone::zone(size_t chunk_size):m_chunk_size(chunk_size), m_chunk_list(m_chunk_size)
184+
inline zone::zone(size_t chunk_size):m_chunk_size(chunk_size), m_chunk_list(MSGPACK_NULLPTR)
185+
{
186+
}
187+
188+
inline zone::~zone()
230189
{
190+
if(m_chunk_list) {
191+
m_chunk_list->~chunk_list();
192+
::free(m_chunk_list);
193+
m_chunk_list = MSGPACK_NULLPTR;
194+
}
231195
}
232196

233197
inline char* zone::get_aligned(char* ptr, size_t align)
234198
{
235199
MSGPACK_ASSERT(align != 0 && (align & (align - 1)) == 0); // align must be 2^n (n >= 0)
236200
return
237-
reinterpret_cast<char*>(
238-
reinterpret_cast<uintptr_t>(ptr + (align - 1)) & ~static_cast<uintptr_t>(align - 1)
239-
);
201+
reinterpret_cast<char*>(
202+
reinterpret_cast<uintptr_t>(ptr + (align - 1)) & ~static_cast<uintptr_t>(align - 1)
203+
);
204+
}
205+
206+
inline zone::chunk_list& zone::get_chank_lst()
207+
{
208+
if (!m_chunk_list) {
209+
auto ptr = ::malloc(sizeof(chunk_list) + m_chunk_size);
210+
if (!ptr)
211+
throw std::bad_alloc();
212+
m_chunk_list = new (ptr) chunk_list(m_chunk_size, reinterpret_cast<char*>(ptr) + sizeof(chunk_list));
213+
}
214+
return *m_chunk_list;
240215
}
241216

242217
inline void* zone::allocate_align(size_t size, size_t align)
243218
{
244-
char* aligned = get_aligned(m_chunk_list.m_ptr, align);
245-
size_t adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr);
246-
if (m_chunk_list.m_free < adjusted_size) {
219+
chunk_list& chank_lst = get_chank_lst();
220+
char* aligned = get_aligned(chank_lst.m_ptr, align);
221+
size_t adjusted_size = size + static_cast<size_t>(aligned - chank_lst.m_ptr);
222+
if (chank_lst.m_free < adjusted_size) {
247223
size_t enough_size = size + align - 1;
248224
char* ptr = allocate_expand(enough_size);
249225
aligned = get_aligned(ptr, align);
250-
adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr);
226+
adjusted_size = size + static_cast<size_t>(aligned - chank_lst.m_ptr);
251227
}
252-
m_chunk_list.m_free -= adjusted_size;
253-
m_chunk_list.m_ptr += adjusted_size;
228+
chank_lst.m_free -= adjusted_size;
229+
chank_lst.m_ptr += adjusted_size;
254230
return aligned;
255231
}
256232

257-
inline void* zone::allocate_no_align(size_t size)
258-
{
259-
char* ptr = m_chunk_list.m_ptr;
260-
if(m_chunk_list.m_free < size) {
233+
inline void* zone::allocate_no_align(size_t size) {
234+
chunk_list& chank_lst = get_chank_lst();
235+
char* ptr = chank_lst.m_ptr;
236+
if(chank_lst.m_free < size) {
261237
ptr = allocate_expand(size);
262238
}
263-
m_chunk_list.m_free -= size;
264-
m_chunk_list.m_ptr += size;
239+
chank_lst.m_free -= size;
240+
chank_lst.m_ptr += size;
265241

266242
return ptr;
267243
}
268244

269245
inline char* zone::allocate_expand(size_t size)
270246
{
271-
chunk_list* const cl = &m_chunk_list;
272-
247+
chunk_list& cl = get_chank_lst();
273248
size_t sz = m_chunk_size;
274249

275250
while(sz < size) {
@@ -286,10 +261,10 @@ inline char* zone::allocate_expand(size_t size)
286261

287262
char* ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
288263

289-
c->m_next = cl->m_head;
290-
cl->m_head = c;
291-
cl->m_free = sz;
292-
cl->m_ptr = ptr;
264+
c->m_next = cl.m_head;
265+
cl.m_head = c;
266+
cl.m_free = sz;
267+
cl.m_ptr = ptr;
293268

294269
return ptr;
295270
}
@@ -308,7 +283,9 @@ inline void zone::push_finalizer(msgpack::unique_ptr<T> obj)
308283
inline void zone::clear()
309284
{
310285
m_finalizer_array.clear();
311-
m_chunk_list.clear(m_chunk_size);
286+
if (m_chunk_list) {
287+
m_chunk_list->clear(m_chunk_size, reinterpret_cast<char*>(m_chunk_list) + sizeof(chunk_list));
288+
}
312289
}
313290

314291
inline void zone::swap(zone& o)
@@ -328,10 +305,10 @@ void zone::object_destruct(void* obj)
328305
static_cast<T*>(obj)->~T();
329306
}
330307

331-
inline void zone::undo_allocate(size_t size)
332-
{
333-
m_chunk_list.m_ptr -= size;
334-
m_chunk_list.m_free += size;
308+
inline void zone::undo_allocate(size_t size) {
309+
chunk_list& cl = get_chank_lst();
310+
cl.m_ptr -= size;
311+
cl.m_free += size;
335312
}
336313

337314

@@ -348,7 +325,7 @@ T* zone::allocate(Args... args)
348325
try {
349326
return new (x) T(args...);
350327
} catch (...) {
351-
--m_finalizer_array.m_tail;
328+
m_finalizer_array.pop();
352329
undo_allocate(sizeof(T));
353330
throw;
354331
}

0 commit comments

Comments
 (0)