aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_goodfit_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_goodfit_alloc.c')
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.c662
1 files changed, 662 insertions, 0 deletions
diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c
new file mode 100644
index 0000000000..ea2ba4d55c
--- /dev/null
+++ b/erts/emulator/beam/erl_goodfit_alloc.c
@@ -0,0 +1,662 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+
+/*
+ * Description: A "good fit" allocator. Segregated free-lists with a
+ * maximum search depth are used in order to find a good
+ * fit fast. Each free-list contains blocks of sizes in a
+ * specific range. First the free-list
+ * covering the desired size is searched if it is not empty.
+ * This search is stopped when the maximum search depth has
+ * been reached. If no free block was found in the free-list
+ * covering the desired size, the next non-empty free-list
+ * covering larger sizes is searched. The maximum search
+ * depth is by default 3. The insert and delete operations
+ * are O(1) and the search operation is O(n) where n is the
+ * maximum search depth, i.e. by default the all operations
+ * are O(1).
+ *
+ * This module is a callback-module for erl_alloc_util.c
+ *
+ * Author: Rickard Green
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "global.h"
+#define GET_ERL_GF_ALLOC_IMPL
+#include "erl_goodfit_alloc.h"
+
+#define MIN_MBC_SZ (16*1024)
+#define MIN_MBC_FIRST_FREE_SZ (4*1024)
+
+#define MAX_SUB_MASK_IX \
+ ((((Uint)1) << (NO_OF_BKT_IX_BITS - SUB_MASK_IX_SHIFT)) - 1)
+#define MAX_SUB_BKT_IX ((((Uint)1) << SUB_MASK_IX_SHIFT) - 1)
+#define MAX_BKT_IX (NO_OF_BKTS - 1)
+
+#define MIN_BLK_SZ UNIT_CEILING(sizeof(GFFreeBlock_t) + sizeof(Uint))
+
+#define IX2SBIX(IX) ((IX) & (~(~((Uint)0) << SUB_MASK_IX_SHIFT)))
+#define IX2SMIX(IX) ((IX) >> SUB_MASK_IX_SHIFT)
+#define MAKE_BKT_IX(SMIX, SBIX) \
+ ((((Uint)(SMIX)) << SUB_MASK_IX_SHIFT) | ((Uint)(SBIX)))
+
+#define SET_BKT_MASK_IX(BM, IX) \
+do { \
+ int sub_mask_ix__ = IX2SMIX((IX)); \
+ (BM).main |= (((Uint) 1) << sub_mask_ix__); \
+ (BM).sub[sub_mask_ix__] |= (((Uint)1) << IX2SBIX((IX))); \
+} while (0)
+
+#define UNSET_BKT_MASK_IX(BM, IX) \
+do { \
+ int sub_mask_ix__ = IX2SMIX((IX)); \
+ (BM).sub[sub_mask_ix__] &= ~(((Uint)1) << IX2SBIX((IX))); \
+ if (!(BM).sub[sub_mask_ix__]) \
+ (BM).main &= ~(((Uint)1) << sub_mask_ix__); \
+} while (0)
+
+/* Buckets ... */
+
+#define BKT_INTRVL_A (1*sizeof(Unit_t))
+#define BKT_INTRVL_B (16*sizeof(Unit_t))
+#define BKT_INTRVL_C (96*sizeof(Unit_t))
+
+#define BKT_MIN_SIZE_A MIN_BLK_SZ
+#define BKT_MIN_SIZE_B (BKT_MAX_SIZE_A + 1)
+#define BKT_MIN_SIZE_C (BKT_MAX_SIZE_B + 1)
+#define BKT_MIN_SIZE_D (BKT_MAX_SIZE_C + 1)
+
+#define BKT_MAX_SIZE_A ((NO_OF_BKTS/4)*BKT_INTRVL_A+BKT_MIN_SIZE_A-1)
+#define BKT_MAX_SIZE_B ((NO_OF_BKTS/4)*BKT_INTRVL_B+BKT_MIN_SIZE_B-1)
+#define BKT_MAX_SIZE_C ((NO_OF_BKTS/4)*BKT_INTRVL_C+BKT_MIN_SIZE_C-1)
+
+
+#define BKT_MAX_IX_A ((NO_OF_BKTS*1)/4 - 1)
+#define BKT_MAX_IX_B ((NO_OF_BKTS*2)/4 - 1)
+#define BKT_MAX_IX_C ((NO_OF_BKTS*3)/4 - 1)
+#define BKT_MAX_IX_D ((NO_OF_BKTS*4)/4 - 1)
+
+#define BKT_MIN_IX_A (0)
+#define BKT_MIN_IX_B (BKT_MAX_IX_A + 1)
+#define BKT_MIN_IX_C (BKT_MAX_IX_B + 1)
+#define BKT_MIN_IX_D (BKT_MAX_IX_C + 1)
+
+
+#define BKT_IX_(BAP, SZ) \
+ ((SZ) <= BKT_MAX_SIZE_A \
+ ? (((SZ) - BKT_MIN_SIZE_A)/BKT_INTRVL_A + BKT_MIN_IX_A) \
+ : ((SZ) <= BKT_MAX_SIZE_B \
+ ? (((SZ) - BKT_MIN_SIZE_B)/BKT_INTRVL_B + BKT_MIN_IX_B) \
+ : ((SZ) <= BKT_MAX_SIZE_C \
+ ? (((SZ) - BKT_MIN_SIZE_C)/BKT_INTRVL_C + BKT_MIN_IX_C) \
+ : ((SZ) <= (BAP)->bkt_max_size_d \
+ ? (((SZ) - BKT_MIN_SIZE_D)/(BAP)->bkt_intrvl_d + BKT_MIN_IX_D)\
+ : (NO_OF_BKTS - 1)))))
+
+#define BKT_MIN_SZ_(BAP, IX) \
+ ((IX) <= BKT_MAX_IX_A \
+ ? (((IX) - BKT_MIN_IX_A)*BKT_INTRVL_A + BKT_MIN_SIZE_A) \
+ : ((IX) <= BKT_MAX_IX_B \
+ ? (((IX) - BKT_MIN_IX_B)*BKT_INTRVL_B + BKT_MIN_SIZE_B) \
+ : ((IX) <= BKT_MAX_IX_C \
+ ? (((IX) - BKT_MIN_IX_C)*BKT_INTRVL_C + BKT_MIN_SIZE_C) \
+ : (((IX) - BKT_MIN_IX_D)*(BAP)->bkt_intrvl_d + BKT_MIN_SIZE_D))))
+
+#ifdef DEBUG
+
+static int
+BKT_IX(GFAllctr_t *gfallctr, Uint size)
+{
+ int ix;
+ ASSERT(size >= MIN_BLK_SZ);
+
+ ix = BKT_IX_(gfallctr, size);
+
+ ASSERT(0 <= ix && ix <= BKT_MAX_IX_D);
+
+ return ix;
+}
+
+static Uint
+BKT_MIN_SZ(GFAllctr_t *gfallctr, int ix)
+{
+ Uint size;
+ ASSERT(0 <= ix && ix <= BKT_MAX_IX_D);
+
+ size = BKT_MIN_SZ_(gfallctr, ix);
+
+#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
+ ASSERT(ix == BKT_IX(gfallctr, size));
+ ASSERT(size == MIN_BLK_SZ || ix - 1 == BKT_IX(gfallctr, size - 1));
+#endif
+
+ return size;
+}
+
+#else
+
+#define BKT_IX BKT_IX_
+#define BKT_MIN_SZ BKT_MIN_SZ_
+
+#endif
+
+
+/* Prototypes of callback functions */
+static Block_t * get_free_block (Allctr_t *, Uint,
+ Block_t *, Uint);
+static void link_free_block (Allctr_t *, Block_t *);
+static void unlink_free_block (Allctr_t *, Block_t *);
+static void update_last_aux_mbc (Allctr_t *, Carrier_t *);
+static Eterm info_options (Allctr_t *, char *, int *,
+ void *, Uint **, Uint *);
+static void init_atoms (void);
+
+#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
+static void check_block (Allctr_t *, Block_t *, int);
+static void check_mbc (Allctr_t *, Carrier_t *);
+#endif
+
+static int atoms_initialized = 0;
+
+void
+erts_gfalc_init(void)
+{
+ atoms_initialized = 0;
+}
+
+
+Allctr_t *
+erts_gfalc_start(GFAllctr_t *gfallctr,
+ GFAllctrInit_t *gfinit,
+ AllctrInit_t *init)
+{
+ GFAllctr_t nulled_state = {{0}};
+ /* {{0}} is used instead of {0}, in order to avoid (an incorrect) gcc
+ warning. gcc warns if {0} is used as initializer of a struct when
+ the first member is a struct (not if, for example, the third member
+ is a struct). */
+ Allctr_t *allctr = (Allctr_t *) gfallctr;
+
+ sys_memcpy((void *) gfallctr, (void *) &nulled_state, sizeof(GFAllctr_t));
+
+ allctr->mbc_header_size = sizeof(Carrier_t);
+ allctr->min_mbc_size = MIN_MBC_SZ;
+ allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ;
+ allctr->min_block_size = sizeof(GFFreeBlock_t);
+
+
+ allctr->vsn_str = ERTS_ALC_GF_ALLOC_VSN_STR;
+
+ /* Callback functions */
+
+ allctr->get_free_block = get_free_block;
+ allctr->link_free_block = link_free_block;
+ allctr->unlink_free_block = unlink_free_block;
+ allctr->info_options = info_options;
+
+ allctr->get_next_mbc_size = NULL;
+ allctr->creating_mbc = update_last_aux_mbc;
+ allctr->destroying_mbc = update_last_aux_mbc;
+
+ allctr->init_atoms = init_atoms;
+
+#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
+ allctr->check_block = check_block;
+ allctr->check_mbc = check_mbc;
+#endif
+
+ allctr->atoms_initialized = 0;
+
+ if (init->sbct > BKT_MIN_SIZE_D-1)
+ gfallctr->bkt_intrvl_d =
+ UNIT_CEILING(((3*(init->sbct - BKT_MIN_SIZE_D - 1)
+ /(NO_OF_BKTS/4 - 1)) + 1)
+ / 2);
+ if (gfallctr->bkt_intrvl_d < BKT_INTRVL_C)
+ gfallctr->bkt_intrvl_d = BKT_INTRVL_C;
+ gfallctr->bkt_max_size_d = ((NO_OF_BKTS/4)*gfallctr->bkt_intrvl_d
+ + BKT_MIN_SIZE_D
+ - 1);
+
+ gfallctr->max_blk_search = (Uint) MAX(1, gfinit->mbsd);
+
+ if (!erts_alcu_start(allctr, init))
+ return NULL;
+
+ if (allctr->min_block_size != MIN_BLK_SZ)
+ return NULL;
+
+ return allctr;
+}
+
+static int
+find_bucket(BucketMask_t *bmask, int min_index)
+{
+ int min, mid, max;
+ int sub_mask_ix, sub_bkt_ix;
+ int ix = -1;
+
+#undef GET_MIN_BIT
+#define GET_MIN_BIT(MinBit, BitMask, Min, Max) \
+ min = (Min); \
+ max = (Max); \
+ while(max != min) { \
+ mid = ((max - min) >> 1) + min; \
+ if((BitMask) \
+ & (~(~((Uint) 0) << (mid + 1))) \
+ & (~((Uint) 0) << min)) \
+ max = mid; \
+ else \
+ min = mid + 1; \
+ } \
+ (MinBit) = min
+
+
+ ASSERT(bmask->main < (((Uint) 1) << (MAX_SUB_MASK_IX+1)));
+
+ sub_mask_ix = IX2SMIX(min_index);
+
+ if ((bmask->main & (~((Uint) 0) << sub_mask_ix)) == 0)
+ return -1;
+
+ /* There exists a non empty bucket; find it... */
+
+ if (bmask->main & (((Uint) 1) << sub_mask_ix)) {
+ sub_bkt_ix = IX2SBIX(min_index);
+ if ((bmask->sub[sub_mask_ix] & (~((Uint) 0) << sub_bkt_ix)) == 0) {
+ sub_mask_ix++;
+ sub_bkt_ix = 0;
+ if ((bmask->main & (~((Uint) 0)<< sub_mask_ix)) == 0)
+ return -1;
+ }
+ else
+ goto find_sub_bkt_ix;
+ }
+ else {
+ sub_mask_ix++;
+ sub_bkt_ix = 0;
+ }
+
+ ASSERT(sub_mask_ix <= MAX_SUB_MASK_IX);
+ /* Has to be a bit > sub_mask_ix */
+ ASSERT(bmask->main & (~((Uint) 0) << (sub_mask_ix)));
+ GET_MIN_BIT(sub_mask_ix, bmask->main, sub_mask_ix, MAX_SUB_MASK_IX);
+
+ find_sub_bkt_ix:
+ ASSERT(sub_mask_ix <= MAX_SUB_MASK_IX);
+ ASSERT(sub_bkt_ix <= MAX_SUB_BKT_IX);
+
+ if ((bmask->sub[sub_mask_ix] & (((Uint) 1) << sub_bkt_ix)) == 0) {
+ ASSERT(sub_mask_ix + 1 <= MAX_SUB_BKT_IX);
+ /* Has to be a bit > sub_bkt_ix */
+ ASSERT(bmask->sub[sub_mask_ix] & (~((Uint) 0) << sub_bkt_ix));
+
+ GET_MIN_BIT(sub_bkt_ix,
+ bmask->sub[sub_mask_ix],
+ sub_bkt_ix+1,
+ MAX_SUB_BKT_IX);
+
+ ASSERT(sub_bkt_ix <= MAX_SUB_BKT_IX);
+ }
+
+ ix = MAKE_BKT_IX(sub_mask_ix, sub_bkt_ix);
+
+ ASSERT(0 <= ix && ix < NO_OF_BKTS);
+
+ return ix;
+
+#undef GET_MIN_BIT
+
+}
+
+static Block_t *
+search_bucket(Allctr_t *allctr, int ix, Uint size)
+{
+ int i;
+ Uint min_sz;
+ Uint blk_sz;
+ Uint cand_sz = 0;
+ Uint max_blk_search;
+ GFFreeBlock_t *blk;
+ GFFreeBlock_t *cand = NULL;
+ int blk_on_lambc;
+ int cand_on_lambc = 0;
+ GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
+
+ ASSERT(0 <= ix && ix <= NO_OF_BKTS - 1);
+
+ if (!gfallctr->buckets[ix])
+ return NULL;
+
+ min_sz = BKT_MIN_SZ(gfallctr, ix);
+ if (min_sz < size)
+ min_sz = size;
+
+ max_blk_search = gfallctr->max_blk_search;
+ for (blk = gfallctr->buckets[ix], i = 0;
+ blk && i < max_blk_search;
+ blk = blk->next, i++) {
+
+ blk_sz = BLK_SZ(blk);
+ blk_on_lambc = (((char *) blk) < gfallctr->last_aux_mbc_end
+ && gfallctr->last_aux_mbc_start <= ((char *) blk));
+
+ if (blk_sz == min_sz && !blk_on_lambc)
+ return (Block_t *) blk;
+
+ if (blk_sz >= min_sz
+ && (!cand
+ || (!blk_on_lambc && (cand_on_lambc || blk_sz < cand_sz))
+ || (blk_on_lambc && cand_on_lambc && blk_sz < cand_sz))) {
+ cand_sz = blk_sz;
+ cand = blk;
+ cand_on_lambc = blk_on_lambc;
+ }
+
+ }
+ return (Block_t *) cand;
+}
+
+static Block_t *
+get_free_block(Allctr_t *allctr, Uint size,
+ Block_t *cand_blk, Uint cand_size)
+{
+ GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
+ int unsafe_bi, min_bi;
+ Block_t *blk;
+
+ ASSERT(!cand_blk || cand_size >= size);
+
+ unsafe_bi = BKT_IX(gfallctr, size);
+
+ min_bi = find_bucket(&gfallctr->bucket_mask, unsafe_bi);
+ if (min_bi < 0)
+ return NULL;
+
+ if (min_bi == unsafe_bi) {
+ blk = search_bucket(allctr, min_bi, size);
+ if (blk) {
+ if (cand_blk && cand_size <= BLK_SZ(blk))
+ return NULL; /* cand_blk was better */
+ unlink_free_block(allctr, blk);
+ return blk;
+ }
+ if (min_bi < NO_OF_BKTS - 1) {
+ min_bi = find_bucket(&gfallctr->bucket_mask, min_bi + 1);
+ if (min_bi < 0)
+ return NULL;
+ }
+ else
+ return NULL;
+ }
+ else {
+ ASSERT(min_bi > unsafe_bi);
+ }
+
+ /* We are guaranteed to find a block that fits in this bucket */
+ blk = search_bucket(allctr, min_bi, size);
+ ASSERT(blk);
+ if (cand_blk && cand_size <= BLK_SZ(blk))
+ return NULL; /* cand_blk was better */
+ unlink_free_block(allctr, blk);
+ return blk;
+}
+
+
+
+static void
+link_free_block(Allctr_t *allctr, Block_t *block)
+{
+ GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
+ GFFreeBlock_t *blk = (GFFreeBlock_t *) block;
+ Uint sz = BLK_SZ(blk);
+ int i = BKT_IX(gfallctr, sz);
+
+ ASSERT(sz >= MIN_BLK_SZ);
+
+ SET_BKT_MASK_IX(gfallctr->bucket_mask, i);
+
+ blk->prev = NULL;
+ blk->next = gfallctr->buckets[i];
+ if (blk->next) {
+ ASSERT(!blk->next->prev);
+ blk->next->prev = blk;
+ }
+ gfallctr->buckets[i] = blk;
+}
+
+static void
+unlink_free_block(Allctr_t *allctr, Block_t *block)
+{
+ GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
+ GFFreeBlock_t *blk = (GFFreeBlock_t *) block;
+ Uint sz = BLK_SZ(blk);
+ int i = BKT_IX(gfallctr, sz);
+
+ if (!blk->prev) {
+ ASSERT(gfallctr->buckets[i] == blk);
+ gfallctr->buckets[i] = blk->next;
+ }
+ else
+ blk->prev->next = blk->next;
+ if (blk->next)
+ blk->next->prev = blk->prev;
+
+ if (!gfallctr->buckets[i])
+ UNSET_BKT_MASK_IX(gfallctr->bucket_mask, i);
+}
+
+static void
+update_last_aux_mbc(Allctr_t *allctr, Carrier_t *mbc)
+{
+ GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
+
+ if (gfallctr->last_aux_mbc_start != (char *) allctr->mbc_list.last) {
+
+ if (allctr->mbc_list.last
+ && allctr->main_carrier != allctr->mbc_list.last) {
+ gfallctr->last_aux_mbc_start = (char *) allctr->mbc_list.last;
+ gfallctr->last_aux_mbc_end = (((char *) allctr->mbc_list.last)
+ + CARRIER_SZ(allctr->mbc_list.last));
+ }
+ else {
+ gfallctr->last_aux_mbc_start = NULL;
+ gfallctr->last_aux_mbc_end = NULL;
+ }
+
+ }
+}
+
+static struct {
+ Eterm mbsd;
+ Eterm as;
+ Eterm gf;
+#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 void
+init_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(mbsd);
+ AM_INIT(as);
+ AM_INIT(gf);
+
+#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_tuple
+
+static ERTS_INLINE void
+add_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 Eterm
+info_options(Allctr_t *allctr,
+ char *prefix,
+ int *print_to_p,
+ void *print_to_arg,
+ Uint **hpp,
+ Uint *szp)
+{
+ GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
+ Eterm res = THE_NON_VALUE;
+
+ if (print_to_p) {
+ erts_print(*print_to_p,
+ print_to_arg,
+ "%smbsd: %lu\n"
+ "%sas: gf\n",
+ prefix, gfallctr->max_blk_search,
+ prefix);
+ }
+
+ 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, am.gf);
+ add_2tup(hpp, szp, &res,
+ am.mbsd,
+ bld_uint(hpp, szp, gfallctr->max_blk_search));
+ }
+
+ return res;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * NOTE: erts_gfalc_test() is only supposed to be used for testing. *
+ * *
+ * Keep alloc_SUITE_data/allocator_test.h updated if changes are made *
+ * to erts_gfalc_test() *
+\* */
+
+unsigned long
+erts_gfalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+{
+ switch (op) {
+ case 0x100: return (unsigned long) BKT_IX((GFAllctr_t *) a1, (Uint) a2);
+ case 0x101: return (unsigned long) BKT_MIN_SZ((GFAllctr_t *) a1, (int) a2);
+ case 0x102: return (unsigned long) NO_OF_BKTS;
+ case 0x103: return (unsigned long)
+ find_bucket(&((GFAllctr_t *) a1)->bucket_mask, (int) a2);
+ default: ASSERT(0); return ~((unsigned long) 0);
+ }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * Debug functions *
+\* */
+
+#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
+void
+check_block(Allctr_t *allctr, Block_t * blk, int free_block)
+{
+ GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
+ int i;
+ int bi;
+ int found;
+ GFFreeBlock_t *fblk;
+
+ if(free_block) {
+ Uint blk_sz = BLK_SZ(blk);
+ bi = BKT_IX(gfallctr, blk_sz);
+
+ ASSERT(gfallctr->bucket_mask.main & (((Uint) 1) << IX2SMIX(bi)));
+ ASSERT(gfallctr->bucket_mask.sub[IX2SMIX(bi)]
+ & (((Uint) 1) << IX2SBIX(bi)));
+
+ found = 0;
+ for (fblk = gfallctr->buckets[bi]; fblk; fblk = fblk->next)
+ if (blk == (Block_t *) fblk)
+ found++;
+ ASSERT(found == 1);
+ }
+ else
+ bi = -1;
+
+ found = 0;
+ for (i = 0; i < NO_OF_BKTS; i++) {
+ if (i == bi)
+ continue; /* Already checked */
+ for (fblk = gfallctr->buckets[i]; fblk; fblk = fblk->next)
+ if (blk == (Block_t *) fblk)
+ found++;
+ }
+
+ ASSERT(found == 0);
+
+}
+
+void
+check_mbc(Allctr_t *allctr, Carrier_t *mbc)
+{
+ GFAllctr_t *gfallctr = (GFAllctr_t *) allctr;
+ int bi;
+
+ for(bi = 0; bi < NO_OF_BKTS; bi++) {
+ if ((gfallctr->bucket_mask.main & (((Uint) 1) << IX2SMIX(bi)))
+ && (gfallctr->bucket_mask.sub[IX2SMIX(bi)]
+ & (((Uint) 1) << IX2SBIX(bi)))) {
+ ASSERT(gfallctr->buckets[bi] != NULL);
+ }
+ else {
+ ASSERT(gfallctr->buckets[bi] == NULL);
+ }
+ }
+}
+
+#endif