LCOV - code coverage report
Current view: top level - core/src/mm/buddy - buddy.c Hit Total Coverage
Test: ROOT-Sim develop Documentation Coverage Lines: 1 28 3.6 %
Date: 2021-03-02 11:24:52

          Line data    Source code
       1           1 : /**
       2             :  * @file mm/buddy/buddy.c
       3             :  *
       4             :  * @brief A Buddy System implementation
       5             :  *
       6             :  * SPDX-FileCopyrightText: 2008-2021 HPDCS Group <rootsim@googlegroups.com>
       7             :  * SPDX-License-Identifier: GPL-3.0-only
       8             :  */
       9             : #include <mm/buddy/buddy.h>
      10             : 
      11             : #include <core/core.h>
      12             : #include <core/intrinsics.h>
      13             : #include <lp/lp.h>
      14             : 
      15             : #include <errno.h>
      16             : #include <stdlib.h>
      17             : 
      18           0 : #define left_child(i) (((i) << 1U) + 1U)
      19           0 : #define right_child(i) (((i) << 1U) + 2U)
      20           0 : #define parent(i) ((((i) + 1) >> 1U) - 1U)
      21           0 : #define is_power_of_2(i) (!((i) & ((i) - 1)))
      22           0 : #define next_exp_of_2(i) (sizeof(i) * CHAR_BIT - intrinsics_clz(i))
      23             : 
      24           0 : void model_allocator_lp_init(void)
      25             : {
      26             :         struct mm_state *self = &current_lp->mm_state;
      27             :         uint_fast8_t node_size = B_TOTAL_EXP;
      28             : 
      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);
      33             :         }
      34             : 
      35             :         self->used_mem = 0;
      36             :         array_init(self->logs);
      37             : #ifdef ROOTSIM_INCREMENTAL
      38             :         memset(self->dirty, 0, sizeof(self->dirty));
      39             :         self->dirty_mem = 0;
      40             : #endif
      41             : }
      42             : 
      43           0 : void model_allocator_lp_fini(void)
      44             : {
      45             :         array_count_t i = array_count(current_lp->mm_state.logs);
      46             :         while (i--) {
      47             :                 mm_free(array_get_at(current_lp->mm_state.logs, i).c);
      48             :         }
      49             :         array_fini(current_lp->mm_state.logs);
      50             : }
      51             : 
      52           0 : void *malloc_mt(size_t req_size)
      53             : {
      54             :         if(unlikely(!req_size))
      55             :                 return NULL;
      56             : 
      57             :         struct mm_state *self = &current_lp->mm_state;
      58             : 
      59             :         uint_fast8_t req_blks = max(next_exp_of_2(req_size - 1), B_BLOCK_EXP);
      60             : 
      61             :         if (unlikely(self->longest[0] < req_blks)) {
      62             :                 errno = ENOMEM;
      63             :                 log_log(LOG_WARN, "LP %p is out of memory!", current_lp);
      64             :                 return NULL;
      65             :         }
      66             : 
      67             :         /* search recursively for the child */
      68             :         uint_fast8_t node_size = B_TOTAL_EXP;
      69             :         uint_fast32_t i = 0;
      70             :         while (node_size > req_blks) {
      71             :                 /* choose the child with smaller longest value which
      72             :                  * is still large at least *size* */
      73             :                 i = left_child(i);
      74             :                 i += self->longest[i] < req_blks;
      75             :                 --node_size;
      76             :         }
      77             : 
      78             :         /* update the *longest* value back */
      79             :         self->longest[i] = 0;
      80             :         self->used_mem += 1 << node_size;
      81             : #ifdef ROOTSIM_INCREMENTAL
      82             :         bitmap_set(self->dirty, i >> B_BLOCK_EXP);
      83             : #endif
      84             :         uint_fast32_t offset = ((i + 1) << node_size) - (1 << B_TOTAL_EXP);
      85             : 
      86             :         while (i) {
      87             :                 i = parent(i);
      88             :                 self->longest[i] = max(
      89             :                         self->longest[left_child(i)],
      90             :                         self->longest[right_child(i)]
      91             :                 );
      92             : #ifdef ROOTSIM_INCREMENTAL
      93             :                 bitmap_set(self->dirty, i >> B_BLOCK_EXP);
      94             : #endif
      95             :         }
      96             : 
      97             :         return ((char *)self->base_mem) + offset;
      98             : }
      99             : 
     100           0 : void *calloc_mt(size_t nmemb, size_t size)
     101             : {
     102             :         size_t tot = nmemb * size;
     103             :         void *ret = malloc_mt(tot);
     104             : 
     105             :         if (likely(ret))
     106             :                 memset(ret, 0, tot);
     107             : 
     108             :         return ret;
     109             : }
     110             : 
     111           0 : void free_mt(void *ptr)
     112             : {
     113             :         if (unlikely(!ptr))
     114             :                 return;
     115             : 
     116             :         struct mm_state *self = &current_lp->mm_state;
     117             :         uint_fast8_t node_size = B_BLOCK_EXP;
     118             :         uint_fast32_t i =
     119             :                 (((uintptr_t)ptr - (uintptr_t)self->base_mem) >> B_BLOCK_EXP) +
     120             :                 (1 << (B_TOTAL_EXP - B_BLOCK_EXP)) - 1;
     121             : 
     122             :         for (; self->longest[i]; i = parent(i)) {
     123             :                 ++node_size;
     124             :         }
     125             : 
     126             :         self->longest[i] = node_size;
     127             :         self->used_mem -= 1 << node_size;
     128             : #ifdef ROOTSIM_INCREMENTAL
     129             :         bitmap_set(self->dirty, i >> B_BLOCK_EXP);
     130             : #endif
     131             :         while (i) {
     132             :                 i = parent(i);
     133             : 
     134             :                 uint_fast8_t left_longest = self->longest[left_child(i)];
     135             :                 uint_fast8_t right_longest = self->longest[right_child(i)];
     136             : 
     137             :                 if (left_longest == node_size && right_longest == node_size) {
     138             :                         self->longest[i] = node_size + 1;
     139             :                 } else {
     140             :                         self->longest[i] = max(left_longest, right_longest);
     141             :                 }
     142             : #ifdef ROOTSIM_INCREMENTAL
     143             :                 bitmap_set(self->dirty, i >> B_BLOCK_EXP);
     144             : #endif
     145             :                 ++node_size;
     146             :         }
     147             : }
     148             : 
     149           0 : void *realloc_mt(void *ptr, size_t req_size)
     150             : {
     151             :         if (!req_size) {
     152             :                 free_mt(ptr);
     153             :                 return NULL;
     154             :         }
     155             :         if (!ptr) {
     156             :                 return malloc_mt(req_size);
     157             :         }
     158             : 
     159             :         abort();
     160             :         return NULL;
     161             : }
     162             : 
     163           0 : #define buddy_tree_visit(longest, on_visit)                             \
     164             : __extension__({                                                         \
     165             :         bool __vis = false;                                             \
     166             :         uint_fast8_t __l = B_TOTAL_EXP;                                 \
     167             :         uint_fast32_t __i = 0;                                          \
     168             :         while (1) {                                                     \
     169             :                 uint_fast8_t __lon = longest[__i];                      \
     170             :                 if (!__lon) {                                           \
     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;                  \
     177             :                         __vis = false;                                  \
     178             :                         __l--;                                          \
     179             :                         continue;                                       \
     180             :                 }                                                       \
     181             :                 do {                                                    \
     182             :                         __vis = !(__i & 1U);                                \
     183             :                         __i = parent(__i);                              \
     184             :                         __l++;                                          \
     185             :                 } while(__vis);                                         \
     186             :                                                                         \
     187             :                 if (__l > B_TOTAL_EXP) break;                                \
     188             :                 __vis = true;                                           \
     189             :         }                                                               \
     190             : })
     191             : 
     192             : #ifdef ROOTSIM_INCREMENTAL
     193             : 
     194           0 : void __write_mem(void *ptr, size_t siz)
     195             : {
     196             :         struct mm_state *self = &current_lp->mm_state;
     197             :         uintptr_t diff = (uintptr_t)ptr - (uintptr_t)self->base_mem;
     198             :         if (diff >= (1 << B_TOTAL_EXP))
     199             :                 return;
     200             : 
     201             :         uint_fast32_t i = (diff >> B_BLOCK_EXP) +
     202             :                 (1 << (B_TOTAL_EXP - 2 * B_BLOCK_EXP + 1));
     203             : 
     204             :         siz += diff & ((1 << B_BLOCK_EXP) - 1);
     205             :         --siz;
     206             :         siz >>= B_BLOCK_EXP;
     207             :         self->dirty_mem += siz;
     208             :         do {
     209             :                 bitmap_set(self->dirty, i + siz);
     210             :         } while(siz--);
     211             : }
     212             : 
     213           0 : static struct mm_checkpoint *checkpoint_incremental_take(struct mm_state *self)
     214             : {
     215             :         uint_fast32_t bset = bitmap_count_set(self->dirty, sizeof(self->dirty));
     216             : 
     217             :         struct mm_checkpoint *ret = mm_alloc(
     218             :                 offsetof(struct mm_checkpoint, longest) +
     219             :                 bset * (1 << B_BLOCK_EXP));
     220             : 
     221             :         unsigned char *ptr = ret->longest;
     222             :         const unsigned char *src = self->longest;
     223             : 
     224           0 : #define copy_block_to_ckp(i)                                            \
     225             : __extension__({                                                         \
     226             :         memcpy(ptr, src + (i << B_BLOCK_EXP), 1 << B_BLOCK_EXP);    \
     227             :         ptr += 1 << B_BLOCK_EXP;                                  \
     228             : })
     229             : 
     230             :         bitmap_foreach_set(self->dirty, sizeof(self->dirty), copy_block_to_ckp);
     231             : #undef copy_block_to_ckp
     232             : 
     233             :         ret->used_mem = self->used_mem;
     234             :         memcpy(ret->dirty, self->dirty, sizeof(self->dirty));
     235             :         ret->is_incremental = true;
     236             :         return ret;
     237             : }
     238             : 
     239           0 : static void checkpoint_incremental_restore(struct mm_state *self,
     240             :         const struct mm_checkpoint *ckp)
     241             : {
     242             :         self->used_mem = ckp->used_mem;
     243             : 
     244             :         array_count_t i = array_count(self->logs) - 1;
     245             :         const struct mm_checkpoint *cur_ckp = array_get_at(self->logs, i).c;
     246             : 
     247             :         while (cur_ckp != ckp) {
     248             :                 bitmap_merge_or(self->dirty, cur_ckp->dirty,
     249             :                         sizeof(self->dirty));
     250             :                 cur_ckp = array_get_at(self->logs, --i).c;
     251             :         }
     252             : 
     253           0 : #define copy_dirty_block(i)                                             \
     254             : __extension__({                                                         \
     255             :         if (bitmap_check(self->dirty, i)) {                          \
     256             :                 memcpy(self->longest + (i << B_BLOCK_EXP), ptr,                \
     257             :                        1 << B_BLOCK_EXP);                         \
     258             :                 bitmap_reset(self->dirty, i);                                \
     259             :                 bset--;                                                 \
     260             :         }                                                               \
     261             :         ptr += 1 << B_BLOCK_EXP;                                  \
     262             : })
     263             : 
     264             :         uint_fast32_t bset = bitmap_count_set(self->dirty, sizeof(self->dirty));
     265             :         do {
     266             :                 const unsigned char *ptr = cur_ckp->longest;
     267             :                 bitmap_foreach_set(cur_ckp->dirty, sizeof(cur_ckp->dirty),
     268             :                         copy_dirty_block);
     269             :                 cur_ckp = array_get_at(self->logs, --i).c;
     270             :         } while (bset && cur_ckp->is_incremental);
     271             : 
     272             : #undef copy_dirty_block
     273             : 
     274             :         if (!bset)
     275             :                 return;
     276             : 
     277           0 : #define copy_block_from_ckp(i)                                          \
     278             : __extension__({                                                         \
     279             :         memcpy(self->longest + (i << B_BLOCK_EXP), cur_ckp->longest +       \
     280             :                 (i << B_BLOCK_EXP), 1 << B_BLOCK_EXP);                      \
     281             : })
     282             : 
     283             :         const unsigned tree_bit_size =
     284             :                 bitmap_required_size(1 << (B_TOTAL_EXP - 2 * B_BLOCK_EXP + 1));
     285             :         bitmap_foreach_set(self->dirty, tree_bit_size, copy_block_from_ckp);
     286             : #undef copy_block_from_ckp
     287             : 
     288           0 : #define buddy_block_dirty_from_ckp(offset, len)                         \
     289             : __extension__({                                                         \
     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;                 \
     293             :         while (b_len--) {                                               \
     294             :                 if (bitmap_check(self->dirty, b_off)) {                      \
     295             :                         memcpy(self->longest + (b_off << B_BLOCK_EXP),         \
     296             :                                ptr, (1 << B_BLOCK_EXP));          \
     297             :                 }                                                       \
     298             :                 ptr += 1 << B_BLOCK_EXP;                          \
     299             :                 b_off++;                                                \
     300             :         }                                                               \
     301             : })
     302             : 
     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
     306             : }
     307             : 
     308             : #endif
     309             : 
     310           0 : static struct mm_checkpoint *checkpoint_full_take(const struct mm_state *self)
     311             : {
     312             :         struct mm_checkpoint *ret = mm_alloc(
     313             :                 offsetof(struct mm_checkpoint, base_mem) + self->used_mem);
     314             : 
     315             : #ifdef ROOTSIM_INCREMENTAL
     316             :         ret->is_incremental = false;
     317             :         memcpy(ret->dirty, self->dirty, sizeof(self->dirty));
     318             : #endif
     319             : 
     320             :         ret->used_mem = self->used_mem;
     321             :         memcpy(ret->longest, self->longest, sizeof(ret->longest));
     322             : 
     323           0 : #define buddy_block_copy_to_ckp(offset, len)                            \
     324             : __extension__({                                                         \
     325             :         memcpy(ptr, self->base_mem + offset, len);                   \
     326             :         ptr += len;                                                     \
     327             : })
     328             : 
     329             :         unsigned char *ptr = ret->base_mem;
     330             :         buddy_tree_visit(self->longest, buddy_block_copy_to_ckp);
     331             : 
     332             : #undef buddy_block_copy_to_ckp
     333             :         return ret;
     334             : }
     335             : 
     336           0 : static void checkpoint_full_restore(struct mm_state *self,
     337             :         const struct mm_checkpoint *ckp)
     338             : {
     339             :         self->used_mem = ckp->used_mem;
     340             :         memcpy(self->longest, ckp->longest, sizeof(self->longest));
     341             : 
     342           0 : #define buddy_block_copy_from_ckp(offset, len)                          \
     343             : __extension__({                                                         \
     344             :         memcpy(self->base_mem + offset, ptr, len);                   \
     345             :         ptr += len;                                                     \
     346             : })
     347             : 
     348             :         const unsigned char *ptr = ckp->base_mem;
     349             :         buddy_tree_visit(self->longest, buddy_block_copy_from_ckp);
     350             : 
     351             : #undef buddy_block_copy_from_ckp
     352             : }
     353             : 
     354           0 : void model_allocator_checkpoint_take(array_count_t ref_i)
     355             : {
     356             :         if (ref_i % B_LOG_FREQUENCY)
     357             :                 return;
     358             : 
     359             :         struct mm_state *self = &current_lp->mm_state;
     360             :         struct mm_checkpoint *ckp;
     361             : 
     362             : #ifdef ROOTSIM_INCREMENTAL
     363             :         if (self->dirty_mem < self->used_mem * B_LOG_INCREMENTAL_THRESHOLD) {
     364             :                 ckp = checkpoint_incremental_take(self);
     365             :         } else {
     366             : #endif
     367             :                 ckp = checkpoint_full_take(self);
     368             : #ifdef ROOTSIM_INCREMENTAL
     369             :         }
     370             :         memset(self->dirty, 0, sizeof(self->dirty));
     371             : #endif
     372             : 
     373             :         struct mm_log mm_log = {
     374             :                 .ref_i = ref_i,
     375             :                 .c = ckp
     376             :         };
     377             :         array_push(self->logs, mm_log);
     378             : }
     379             : 
     380           0 : void model_allocator_checkpoint_next_force_full(void)
     381             : {
     382             : #ifdef ROOTSIM_INCREMENTAL
     383             :         struct mm_state *self = &current_lp->mm_state;
     384             :         self->dirty_mem = self->used_mem * B_LOG_INCREMENTAL_THRESHOLD;
     385             : #endif
     386             : }
     387             : 
     388           0 : array_count_t model_allocator_checkpoint_restore(array_count_t ref_i)
     389             : {
     390             :         struct mm_state *self = &current_lp->mm_state;
     391             : 
     392             :         array_count_t i = array_count(self->logs) - 1;
     393             :         while (array_get_at(self->logs, i).ref_i > ref_i) {
     394             :                 i--;
     395             :         }
     396             : 
     397             :         const struct mm_checkpoint *ckp = array_get_at(self->logs, i).c;
     398             : #ifdef ROOTSIM_INCREMENTAL
     399             :         if (ckp->is_incremental) {
     400             :                 checkpoint_incremental_restore(self, ckp);
     401             :         } else {
     402             : #endif
     403             :                 checkpoint_full_restore(self, ckp);
     404             : #ifdef ROOTSIM_INCREMENTAL
     405             :         }
     406             :         memset(self->dirty, 0, sizeof(self->dirty));
     407             :         self->dirty_mem = 0;
     408             : #endif
     409             : 
     410             :         for (array_count_t j = array_count(self->logs) - 1; j > i; --j) {
     411             :                 mm_free(array_get_at(self->logs, j).c);
     412             :         }
     413             :         array_count(self->logs) = i + 1;
     414             : 
     415             :         return array_get_at(self->logs, i).ref_i;
     416             : }
     417             : 
     418           0 : array_count_t model_allocator_fossil_lp_collect(array_count_t tgt_ref_i)
     419             : {
     420             :         struct mm_state *self = &current_lp->mm_state;
     421             :         array_count_t log_i = array_count(self->logs) - 1;
     422             :         array_count_t ref_i = array_get_at(self->logs, log_i).ref_i;
     423             :         while (ref_i > tgt_ref_i) {
     424             :                 --log_i;
     425             :                 ref_i = array_get_at(self->logs, log_i).ref_i;
     426             :         }
     427             : 
     428             : #ifdef ROOTSIM_INCREMENTAL
     429             :         while (array_get_at(self->logs, log_i).c->is_incremental) {
     430             :                 --log_i;
     431             :                 ref_i = array_get_at(self->logs, log_i).ref_i;
     432             :         }
     433             : #endif
     434             : 
     435             :         array_count_t j = array_count(self->logs);
     436             :         while (j > log_i) {
     437             :                 --j;
     438             :                 array_get_at(self->logs, j).ref_i -= ref_i;
     439             :         }
     440             :         while (j--) {
     441             :                 mm_free(array_get_at(self->logs, j).c);
     442             :         }
     443             : 
     444             :         array_truncate_first(self->logs, log_i);
     445             :         return ref_i;
     446             : }

Generated by: LCOV version 1.14