📄 erl_bestfit_alloc.c
字号:
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * "Address order best fit" specific callbacks. *\* */static voidaobf_link_free_block(Allctr_t *allctr, Block_t *block){ BFAllctr_t *bfallctr = (BFAllctr_t *) allctr; RBTree_t *blk = (RBTree_t *) block; Uint blk_sz = BLK_SZ(blk); blk->flags = 0; blk->left = NULL; blk->right = NULL; if (!bfallctr->root) { blk->parent = NULL; SET_BLACK(blk); bfallctr->root = blk; } else { RBTree_t *x = bfallctr->root; while (1) { Uint size; size = BLK_SZ(x); if (blk_sz < size || (blk_sz == size && blk < x)) { if (!x->left) { blk->parent = x; x->left = blk; break; } x = x->left; } else { if (!x->right) { blk->parent = x; x->right = blk; break; } x = x->right; } } /* Insert block into size tree */ RBT_ASSERT(blk->parent); SET_RED(blk); if (IS_RED(blk->parent)) tree_insert_fixup(bfallctr, blk); }#ifdef HARD_DEBUG check_tree(bfallctr, 0);#endif}#if 0 /* tree_delete() is directly used instead */static voidaobf_unlink_free_block(Allctr_t *allctr, Block_t *block){ tree_delete(allctr, block);}#endifstatic Block_t *aobf_get_free_block(Allctr_t *allctr, Uint size){ BFAllctr_t *bfallctr = (BFAllctr_t *) allctr; RBTree_t *x = bfallctr->root; RBTree_t *blk = NULL; Uint blk_sz; while (x) { blk_sz = BLK_SZ(x); if (blk_sz < size) { x = x->right; } else { blk = x; x = x->left; } } if (!blk) return NULL;#ifdef HARD_DEBUG ASSERT(blk == check_tree(bfallctr, size));#endif aobf_unlink_free_block(allctr, (Block_t *) blk); return (Block_t *) blk;}/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * "Best fit" specific callbacks. *\* */static voidbf_link_free_block(Allctr_t *allctr, Block_t *block){ BFAllctr_t *bfallctr = (BFAllctr_t *) allctr; RBTree_t *blk = (RBTree_t *) block; Uint blk_sz = BLK_SZ(blk); SET_TREE_NODE(blk); blk->flags = 0; blk->left = NULL; blk->right = NULL; if (!bfallctr->root) { blk->parent = NULL; SET_BLACK(blk); bfallctr->root = blk; } else { RBTree_t *x = bfallctr->root; while (1) { Uint size; size = BLK_SZ(x); if (blk_sz == size) { SET_LIST_ELEM(blk); LIST_NEXT(blk) = LIST_NEXT(x); LIST_PREV(blk) = x; if (LIST_NEXT(x)) LIST_PREV(LIST_NEXT(x)) = blk; LIST_NEXT(x) = blk; return; /* Finnished */ } else if (blk_sz < size) { if (!x->left) { blk->parent = x; x->left = blk; break; } x = x->left; } else { if (!x->right) { blk->parent = x; x->right = blk; break; } x = x->right; } } RBT_ASSERT(blk->parent); SET_RED(blk); if (IS_RED(blk->parent)) tree_insert_fixup(bfallctr, blk); } SET_TREE_NODE(blk); LIST_NEXT(blk) = NULL;#ifdef HARD_DEBUG check_tree(bfallctr, 0);#endif}static ERTS_INLINE voidbf_unlink_free_block(Allctr_t *allctr, Block_t *block){ BFAllctr_t *bfallctr = (BFAllctr_t *) allctr; RBTree_t *x = (RBTree_t *) block; if (IS_LIST_ELEM(x)) { /* Remove from list */ ASSERT(LIST_PREV(x)); LIST_NEXT(LIST_PREV(x)) = LIST_NEXT(x); if (LIST_NEXT(x)) LIST_PREV(LIST_NEXT(x)) = LIST_PREV(x); } else if (LIST_NEXT(x)) { /* Replace tree node by next element in list... */ ASSERT(BLK_SZ(LIST_NEXT(x)) == BLK_SZ(x)); ASSERT(IS_TREE_NODE(x)); ASSERT(IS_LIST_ELEM(LIST_NEXT(x)));#ifdef HARD_DEBUG check_tree(bfallctr, 0);#endif replace(&bfallctr->root, x, LIST_NEXT(x));#ifdef HARD_DEBUG check_tree(bfallctr, 0);#endif } else { /* Remove from tree */ tree_delete(allctr, block); } DESTROY_LIST_ELEM(x);}static Block_t *bf_get_free_block(Allctr_t *allctr, Uint size){ BFAllctr_t *bfallctr = (BFAllctr_t *) allctr; RBTree_t *x = bfallctr->root; RBTree_t *blk = NULL; Uint blk_sz; while (x) { blk_sz = BLK_SZ(x); if (blk_sz < size) { x = x->right; } else { blk = x; if (blk_sz == size) break; x = x->left; } } if (!blk) return NULL; ASSERT(IS_TREE_NODE(blk));#ifdef HARD_DEBUG { RBTree_t *ct_blk = check_tree(bfallctr, size); ASSERT(BLK_SZ(ct_blk) == BLK_SZ(blk)); }#endif /* Use next block if it exist in order to avoid replacing the tree node */ blk = LIST_NEXT(blk) ? LIST_NEXT(blk) : blk; bf_unlink_free_block(allctr, (Block_t *) blk); return (Block_t *) blk;}/* * info_options() */static struct { Eterm as; Eterm aobf; Eterm bf;#ifdef DEBUG Eterm end_of_atoms;#endif} am;static void ERTS_INLINE atom_init(Eterm *atom, char *name){ *atom = am_atom_put(name, strlen(name));}#define AM_INIT(AM) atom_init(&am.AM, #AM)static voidinit_atoms(void){#ifdef DEBUG Eterm *atom;#endif if (atoms_initialized) return;#ifdef DEBUG for (atom = (Eterm *) &am; atom <= &am.end_of_atoms; atom++) { *atom = THE_NON_VALUE; }#endif AM_INIT(as); AM_INIT(aobf); AM_INIT(bf);#ifdef DEBUG for (atom = (Eterm *) &am; atom < &am.end_of_atoms; atom++) { ASSERT(*atom != THE_NON_VALUE); }#endif atoms_initialized = 1;}#define bld_uint erts_bld_uint#define bld_cons erts_bld_cons#define bld_tuple erts_bld_tuplestatic ERTS_INLINE voidadd_2tup(Uint **hpp, Uint *szp, Eterm *lp, Eterm el1, Eterm el2){ *lp = bld_cons(hpp, szp, bld_tuple(hpp, szp, 2, el1, el2), *lp);}static Eterminfo_options(Allctr_t *allctr, char *prefix, int *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp){ BFAllctr_t *bfallctr = (BFAllctr_t *) allctr; Eterm res = THE_NON_VALUE; if (print_to_p) { erts_print(*print_to_p, print_to_arg, "%sas: %s\n", prefix, bfallctr->address_order ? "aobf" : "bf"); } if (hpp || szp) { if (!atoms_initialized) erl_exit(1, "%s:%d: Internal error: Atoms not initialized", __FILE__, __LINE__);; res = NIL; add_2tup(hpp, szp, &res, am.as, bfallctr->address_order ? am.aobf : am.bf); } return res;}/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * NOTE: erts_bfalc_test() is only supposed to be used for testing. * * * * Keep alloc_SUITE_data/allocator_test.h updated if changes are made * * to erts_bfalc_test() *\* */unsigned longerts_bfalc_test(unsigned long op, unsigned long a1, unsigned long a2){ switch (op) { case 0x200: return (unsigned long) ((BFAllctr_t *) a1)->address_order; case 0x201: return (unsigned long) ((BFAllctr_t *) a1)->root; case 0x202: return (unsigned long) ((RBTree_t *) a1)->parent; case 0x203: return (unsigned long) ((RBTree_t *) a1)->left; case 0x204: return (unsigned long) ((RBTree_t *) a1)->right; case 0x205: return (unsigned long) ((RBTreeList_t *) a1)->next; case 0x206: return (unsigned long) IS_BLACK((RBTree_t *) a1); case 0x207: return (unsigned long) IS_TREE_NODE((RBTree_t *) a1); default: ASSERT(0); return ~((unsigned long) 0); }}/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Debug functions *\* */#ifdef HARD_DEBUG#define IS_LEFT_VISITED(FB) ((FB)->flags & LEFT_VISITED_FLG)#define IS_RIGHT_VISITED(FB) ((FB)->flags & RIGHT_VISITED_FLG)#define SET_LEFT_VISITED(FB) ((FB)->flags |= LEFT_VISITED_FLG)#define SET_RIGHT_VISITED(FB) ((FB)->flags |= RIGHT_VISITED_FLG)#define UNSET_LEFT_VISITED(FB) ((FB)->flags &= ~LEFT_VISITED_FLG)#define UNSET_RIGHT_VISITED(FB) ((FB)->flags &= ~RIGHT_VISITED_FLG)#if 0# define PRINT_TREE#else# undef PRINT_TREE#endif#ifdef PRINT_TREEstatic void print_tree(BFAllctr_t *);#endif/* * Checks that the order between parent and children are correct, * and that the Red-Black Tree properies are satisfied. if size > 0, * check_tree() returns a node that satisfies "best fit" resp. * "address order best fit". * * The Red-Black Tree properies are: * 1. Every node is either red or black. * 2. Every leaf (NIL) is black. * 3. If a node is red, then both its children are black. * 4. Every simple path from a node to a descendant leaf * contains the same number of black nodes. */static RBTree_t *check_tree(BFAllctr_t *bfallctr, Uint size){ RBTree_t *res = NULL; Sint blacks; Sint curr_blacks; RBTree_t *x;#ifdef PRINT_TREE print_tree(bfallctr);#endif if (!bfallctr->root) return res; x = bfallctr->root; ASSERT(IS_BLACK(x)); ASSERT(!x->parent); curr_blacks = 1; blacks = -1; while (x) { if (!IS_LEFT_VISITED(x)) { SET_LEFT_VISITED(x); if (x->left) { x = x->left; if (IS_BLACK(x)) curr_blacks++; continue; } else { if (blacks < 0) blacks = curr_blacks; ASSERT(blacks == curr_blacks); } } if (!IS_RIGHT_VISITED(x)) { SET_RIGHT_VISITED(x); if (x->right) { x = x->right; if (IS_BLACK(x)) curr_blacks++; continue; } else { if (blacks < 0) blacks = curr_blacks; ASSERT(blacks == curr_blacks); } } if (IS_RED(x)) { ASSERT(IS_BLACK(x->right)); ASSERT(IS_BLACK(x->left)); } ASSERT(x->parent || x == bfallctr->root); if (x->left) { ASSERT(x->left->parent == x); if (bfallctr->address_order) { ASSERT(BLK_SZ(x->left) < BLK_SZ(x) || (BLK_SZ(x->left) == BLK_SZ(x) && x->left < x)); } else { ASSERT(IS_TREE_NODE(x->left)); ASSERT(BLK_SZ(x->left) < BLK_SZ(x)); } } if (x->right) { ASSERT(x->right->parent == x); if (bfallctr->address_order) { ASSERT(BLK_SZ(x->right) > BLK_SZ(x) || (BLK_SZ(x->right) == BLK_SZ(x) && x->right > x)); } else { ASSERT(IS_TREE_NODE(x->right)); ASSERT(BLK_SZ(x->right) > BLK_SZ(x)); } } if (size && BLK_SZ(x) >= size) { if (bfallctr->address_order) { if (!res || BLK_SZ(x) < BLK_SZ(res) || (BLK_SZ(x) == BLK_SZ(res) && x < res)) res = x; } else { if (!res || BLK_SZ(x) < BLK_SZ(res)) res = x; } } UNSET_LEFT_VISITED(x); UNSET_RIGHT_VISITED(x); if (IS_BLACK(x)) curr_blacks--; x = x->parent; } ASSERT(curr_blacks == 0); UNSET_LEFT_VISITED(bfallctr->root); UNSET_RIGHT_VISITED(bfallctr->root); return res;}#ifdef PRINT_TREE#define INDENT_STEP 2#include <stdio.h>static voidprint_tree_aux(RBTree_t *x, int indent){ int i; if (!x) { for (i = 0; i < indent; i++) { putc(' ', stderr); } fprintf(stderr, "BLACK: nil\r\n"); } else { print_tree_aux(x->right, indent + INDENT_STEP); for (i = 0; i < indent; i++) { putc(' ', stderr); } fprintf(stderr, "%s: sz=%lu addr=0x%lx\r\n", IS_BLACK(x) ? "BLACK" : "RED", BLK_SZ(x), (Uint) x); print_tree_aux(x->left, indent + INDENT_STEP); }}static voidprint_tree(BFAllctr_t *bfallctr){ char *type = bfallctr->address_order ? "Size-Adress" : "Size"; fprintf(stderr, " --- %s tree begin ---\r\n", type); print_tree_aux(bfallctr->root, 0); fprintf(stderr, " --- %s tree end ---\r\n", type);}#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -