/* -----------------------------------------------------------------------------
*
- * (c) The GHC Team 1998-2006
+ * (c) The GHC Team 1998-2008
*
* The block allocator and free list manager.
*
-------------------------------------------------------------------------- */
STATIC_INLINE void
-initGroup(nat n, bdescr *head)
+initGroup(bdescr *head)
{
bdescr *bd;
- nat i;
+ nat i, n;
- if (n != 0) {
- head->free = head->start;
- head->link = NULL;
- for (i=1, bd = head+1; i < n; i++, bd++) {
+ n = head->blocks;
+ head->free = head->start;
+ head->link = NULL;
+ for (i=1, bd = head+1; i < n; i++, bd++) {
bd->free = 0;
bd->blocks = 0;
bd->link = head;
- }
}
}
} else {
free_mblock_list = bd->link;
}
- initGroup(n, bd);
+ initGroup(bd);
return bd;
}
else if (bd->blocks > n)
bdescr *bd, *rem;
nat ln;
- // Todo: not true in multithreaded GC, where we use allocBlock_sync().
- // ASSERT_SM_LOCK();
-
if (n == 0) barf("allocGroup: requested zero blocks");
- n_alloc_blocks += n;
- if (n_alloc_blocks > hw_alloc_blocks) hw_alloc_blocks = n_alloc_blocks;
-
if (n >= BLOCKS_PER_MBLOCK)
{
- bd = alloc_mega_group(BLOCKS_TO_MBLOCKS(n));
+ nat mblocks;
+
+ mblocks = BLOCKS_TO_MBLOCKS(n);
+
+ // n_alloc_blocks doesn't count the extra blocks we get in a
+ // megablock group.
+ n_alloc_blocks += mblocks * BLOCKS_PER_MBLOCK;
+ if (n_alloc_blocks > hw_alloc_blocks) hw_alloc_blocks = n_alloc_blocks;
+
+ bd = alloc_mega_group(mblocks);
// only the bdescrs of the first MB are required to be initialised
- initGroup(BLOCKS_PER_MBLOCK, bd);
+ initGroup(bd);
+
IF_DEBUG(sanity, checkFreeListSanity());
return bd;
}
+ n_alloc_blocks += n;
+ if (n_alloc_blocks > hw_alloc_blocks) hw_alloc_blocks = n_alloc_blocks;
+
ln = log_2_ceil(n);
- while (free_list[ln] == NULL && ln < MAX_FREE_LIST) {
+ while (ln < MAX_FREE_LIST && free_list[ln] == NULL) {
ln++;
}
if (ln == MAX_FREE_LIST) {
+#if 0
+ if ((mblocks_allocated * MBLOCK_SIZE_W - n_alloc_blocks * BLOCK_SIZE_W) > (1024*1024)/sizeof(W_)) {
+ debugBelch("Fragmentation, wanted %d blocks:", n);
+ RtsFlags.DebugFlags.block_alloc = 1;
+ checkFreeListSanity();
+ }
+#endif
+
bd = alloc_mega_group(1);
bd->blocks = n;
- initGroup(n,bd); // we know the group will fit
+ initGroup(bd); // we know the group will fit
rem = bd + n;
rem->blocks = BLOCKS_PER_MBLOCK-n;
- initGroup(BLOCKS_PER_MBLOCK-n, rem); // init the slop
+ initGroup(rem); // init the slop
n_alloc_blocks += rem->blocks;
freeGroup(rem); // add the slop on to the free list
IF_DEBUG(sanity, checkFreeListSanity());
{
barf("allocGroup: free list corrupted");
}
- initGroup(n, bd); // initialise it
+ initGroup(bd); // initialise it
IF_DEBUG(sanity, checkFreeListSanity());
ASSERT(bd->blocks == n);
return bd;
ASSERT(p->free != (P_)-1);
- n_alloc_blocks -= p->blocks;
-
p->free = (void *)-1; /* indicates that this block is free */
p->step = NULL;
p->gen_no = 0;
if (p->blocks >= BLOCKS_PER_MBLOCK)
{
+ nat mblocks;
+
+ mblocks = BLOCKS_TO_MBLOCKS(p->blocks);
// If this is an mgroup, make sure it has the right number of blocks
- ASSERT(p->blocks == MBLOCK_GROUP_BLOCKS(BLOCKS_TO_MBLOCKS(p->blocks)));
+ ASSERT(p->blocks == MBLOCK_GROUP_BLOCKS(mblocks));
+
+ n_alloc_blocks -= mblocks * BLOCKS_PER_MBLOCK;
+
free_mega_group(p);
return;
}
+ ASSERT(n_alloc_blocks >= p->blocks);
+ n_alloc_blocks -= p->blocks;
+
// coalesce forwards
{
bdescr *next;
RELEASE_SM_LOCK;
}
+// splitBlockGroup(bd,B) splits bd in two. Afterward, bd will have B
+// blocks, and a new block descriptor pointing to the remainder is
+// returned.
bdescr *
splitBlockGroup (bdescr *bd, nat blocks)
{
}
if (bd->blocks > BLOCKS_PER_MBLOCK) {
- nat mblocks;
+ nat low_mblocks, high_mblocks;
void *new_mblock;
if ((blocks - BLOCKS_PER_MBLOCK) % (MBLOCK_SIZE / BLOCK_SIZE) != 0) {
barf("splitLargeBlock: not a multiple of a megablock");
}
- mblocks = 1 + (blocks - BLOCKS_PER_MBLOCK) / (MBLOCK_SIZE / BLOCK_SIZE);
- new_mblock = (void *) ((P_)MBLOCK_ROUND_DOWN(bd) + mblocks * MBLOCK_SIZE_W);
+ low_mblocks = 1 + (blocks - BLOCKS_PER_MBLOCK) / (MBLOCK_SIZE / BLOCK_SIZE);
+ high_mblocks = (bd->blocks - blocks) / (MBLOCK_SIZE / BLOCK_SIZE);
+
+ new_mblock = (void *) ((P_)MBLOCK_ROUND_DOWN(bd) + low_mblocks * MBLOCK_SIZE_W);
initMBlock(new_mblock);
new_bd = FIRST_BDESCR(new_mblock);
- new_bd->blocks = MBLOCK_GROUP_BLOCKS(mblocks);
+ new_bd->blocks = MBLOCK_GROUP_BLOCKS(high_mblocks);
+
+ ASSERT(blocks + new_bd->blocks ==
+ bd->blocks + BLOCKS_PER_MBLOCK - MBLOCK_SIZE/BLOCK_SIZE);
}
else
{
}
return total_blocks;
}
+
+void
+markBlocks (bdescr *bd)
+{
+ for (; bd != NULL; bd = bd->link) {
+ bd->flags |= BF_KNOWN;
+ }
+}
+
+void
+reportUnmarkedBlocks (void)
+{
+ void *mblock;
+ bdescr *bd;
+
+ debugBelch("Unreachable blocks:\n");
+ for (mblock = getFirstMBlock(); mblock != NULL;
+ mblock = getNextMBlock(mblock)) {
+ for (bd = FIRST_BDESCR(mblock); bd <= LAST_BDESCR(mblock); ) {
+ if (!(bd->flags & BF_KNOWN) && bd->free != (P_)-1) {
+ debugBelch(" %p\n",bd);
+ }
+ if (bd->blocks >= BLOCKS_PER_MBLOCK) {
+ mblock += (BLOCKS_TO_MBLOCKS(bd->blocks) - 1) * MBLOCK_SIZE;
+ break;
+ } else {
+ bd += bd->blocks;
+ }
+ }
+ }
+}
+
#endif