18 #define left_child(i) (((i) << 1U) + 1U)
19 #define right_child(i) (((i) << 1U) + 2U)
20 #define parent(i) ((((i) + 1) >> 1U) - 1U)
21 #define is_power_of_2(i) (!((i) & ((i) - 1)))
22 #define next_exp_of_2(i) (sizeof(i) * CHAR_BIT - intrinsics_clz(i))
24 void model_allocator_lp_init(
void)
27 uint_fast8_t node_size = B_TOTAL_EXP;
29 for (uint_fast32_t i = 0;
30 i <
sizeof(
self->longest) /
sizeof(*self->longest); ++i) {
31 self->longest[i] = node_size;
32 node_size -= is_power_of_2(i + 2);
36 array_init(self->logs);
37 #ifdef ROOTSIM_INCREMENTAL
38 memset(self->dirty, 0,
sizeof(self->dirty));
43 void model_allocator_lp_fini(
void)
49 array_fini(current_lp->
mm_state.logs);
52 void *malloc_mt(
size_t req_size)
59 uint_fast8_t req_blks = max(next_exp_of_2(req_size - 1), B_BLOCK_EXP);
61 if (
unlikely(self->longest[0] < req_blks)) {
68 uint_fast8_t node_size = B_TOTAL_EXP;
70 while (node_size > req_blks) {
74 i +=
self->longest[i] < req_blks;
80 self->used_mem += 1 << node_size;
81 #ifdef ROOTSIM_INCREMENTAL
84 uint_fast32_t offset = ((i + 1) << node_size) - (1 << B_TOTAL_EXP);
88 self->longest[i] = max(
89 self->longest[left_child(i)],
90 self->longest[right_child(i)]
92 #ifdef ROOTSIM_INCREMENTAL
97 return ((
char *)self->base_mem) + offset;
100 void *calloc_mt(
size_t nmemb,
size_t size)
102 size_t tot = nmemb * size;
103 void *ret = malloc_mt(tot);
111 void free_mt(
void *ptr)
117 uint_fast8_t node_size = B_BLOCK_EXP;
119 (((uintptr_t)ptr - (uintptr_t)
self->base_mem) >> B_BLOCK_EXP) +
120 (1 << (B_TOTAL_EXP - B_BLOCK_EXP)) - 1;
122 for (;
self->longest[i]; i = parent(i)) {
126 self->longest[i] = node_size;
127 self->used_mem -= 1 << node_size;
128 #ifdef ROOTSIM_INCREMENTAL
134 uint_fast8_t left_longest =
self->longest[left_child(i)];
135 uint_fast8_t right_longest =
self->longest[right_child(i)];
137 if (left_longest == node_size && right_longest == node_size) {
138 self->longest[i] = node_size + 1;
140 self->longest[i] = max(left_longest, right_longest);
142 #ifdef ROOTSIM_INCREMENTAL
149 void *realloc_mt(
void *ptr,
size_t req_size)
156 return malloc_mt(req_size);
163 #define buddy_tree_visit(longest, on_visit) \
165 bool __vis = false; \
166 uint_fast8_t __l = B_TOTAL_EXP; \
167 uint_fast32_t __i = 0; \
169 uint_fast8_t __lon = longest[__i]; \
171 uint_fast32_t __len = 1U << __l; \
172 uint_fast32_t __o = \
173 ((__i + 1) << __l) - (1 << B_TOTAL_EXP);\
174 on_visit(__o, __len); \
175 } else if(__lon != __l) { \
176 __i = left_child(__i) + __vis; \
182 __vis = !(__i & 1U); \
187 if (__l > B_TOTAL_EXP) break; \
192 #ifdef ROOTSIM_INCREMENTAL
194 void __write_mem(
void *ptr,
size_t siz)
197 uintptr_t diff = (uintptr_t)ptr - (uintptr_t)
self->
base_mem;
198 if (diff >= (1 << B_TOTAL_EXP))
201 uint_fast32_t i = (diff >> B_BLOCK_EXP) +
202 (1 << (B_TOTAL_EXP - 2 * B_BLOCK_EXP + 1));
204 siz += diff & ((1 << B_BLOCK_EXP) - 1);
207 self->dirty_mem += siz;
219 bset * (1 << B_BLOCK_EXP));
221 unsigned char *ptr = ret->
longest;
222 const unsigned char *src =
self->longest;
224 #define copy_block_to_ckp(i) \
226 memcpy(ptr, src + (i << B_BLOCK_EXP), 1 << B_BLOCK_EXP); \
227 ptr += 1 << B_BLOCK_EXP; \
231 #undef copy_block_to_ckp
234 memcpy(ret->
dirty, self->dirty,
sizeof(self->dirty));
239 static void checkpoint_incremental_restore(
struct mm_state *
self,
245 const struct mm_checkpoint *cur_ckp = array_get_at(self->logs, i).c;
247 while (cur_ckp != ckp) {
249 sizeof(self->dirty));
250 cur_ckp = array_get_at(self->logs, --i).c;
253 #define copy_dirty_block(i) \
255 if (bitmap_check(self->dirty, i)) { \
256 memcpy(self->longest + (i << B_BLOCK_EXP), ptr, \
258 bitmap_reset(self->dirty, i); \
261 ptr += 1 << B_BLOCK_EXP; \
266 const unsigned char *ptr = cur_ckp->
longest;
269 cur_ckp = array_get_at(self->logs, --i).c;
272 #undef copy_dirty_block
277 #define copy_block_from_ckp(i) \
279 memcpy(self->longest + (i << B_BLOCK_EXP), cur_ckp->longest + \
280 (i << B_BLOCK_EXP), 1 << B_BLOCK_EXP); \
283 const unsigned tree_bit_size =
286 #undef copy_block_from_ckp
288 #define buddy_block_dirty_from_ckp(offset, len) \
290 uint_fast32_t b_off = (offset >> B_BLOCK_EXP) + \
291 (1 << (B_TOTAL_EXP - 2 * B_BLOCK_EXP + 1)); \
292 uint_fast32_t b_len = len >> B_BLOCK_EXP; \
294 if (bitmap_check(self->dirty, b_off)) { \
295 memcpy(self->longest + (b_off << B_BLOCK_EXP), \
296 ptr, (1 << B_BLOCK_EXP)); \
298 ptr += 1 << B_BLOCK_EXP; \
303 const unsigned char *ptr = cur_ckp->
base_mem;
304 buddy_tree_visit(self->longest, buddy_block_dirty_from_ckp);
305 #undef buddy_block_dirty_from_ckp
315 #ifdef ROOTSIM_INCREMENTAL
317 memcpy(ret->
dirty, self->dirty,
sizeof(self->dirty));
323 #define buddy_block_copy_to_ckp(offset, len) \
325 memcpy(ptr, self->base_mem + offset, len); \
330 buddy_tree_visit(self->longest, buddy_block_copy_to_ckp);
332 #undef buddy_block_copy_to_ckp
336 static void checkpoint_full_restore(
struct mm_state *
self,
340 memcpy(self->longest, ckp->
longest,
sizeof(self->longest));
342 #define buddy_block_copy_from_ckp(offset, len) \
344 memcpy(self->base_mem + offset, ptr, len); \
348 const unsigned char *ptr = ckp->
base_mem;
349 buddy_tree_visit(self->longest, buddy_block_copy_from_ckp);
351 #undef buddy_block_copy_from_ckp
356 if (ref_i % B_LOG_FREQUENCY)
362 #ifdef ROOTSIM_INCREMENTAL
363 if (self->dirty_mem < self->used_mem * B_LOG_INCREMENTAL_THRESHOLD) {
364 ckp = checkpoint_incremental_take(
self);
367 ckp = checkpoint_full_take(
self);
368 #ifdef ROOTSIM_INCREMENTAL
370 memset(self->dirty, 0,
sizeof(self->dirty));
373 struct mm_log mm_log = {
377 array_push(self->logs, mm_log);
380 void model_allocator_checkpoint_next_force_full(
void)
382 #ifdef ROOTSIM_INCREMENTAL
384 self->
dirty_mem =
self->used_mem * B_LOG_INCREMENTAL_THRESHOLD;
393 while (array_get_at(self->logs, i).ref_i > ref_i) {
397 const struct mm_checkpoint *ckp = array_get_at(self->logs, i).c;
398 #ifdef ROOTSIM_INCREMENTAL
400 checkpoint_incremental_restore(
self, ckp);
403 checkpoint_full_restore(
self, ckp);
404 #ifdef ROOTSIM_INCREMENTAL
406 memset(self->dirty, 0,
sizeof(self->dirty));
411 mm_free(array_get_at(self->logs, j).c);
415 return array_get_at(self->logs, i).ref_i;
423 while (ref_i > tgt_ref_i) {
425 ref_i = array_get_at(self->logs, log_i).ref_i;
428 #ifdef ROOTSIM_INCREMENTAL
429 while (array_get_at(self->logs, log_i).c->is_incremental) {
431 ref_i = array_get_at(self->logs, log_i).ref_i;
438 array_get_at(self->logs, j).ref_i -= ref_i;
441 mm_free(array_get_at(self->logs, j).c);
444 array_truncate_first(self->logs, log_i);