X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2Fsm%2FGCUtils.c;h=39a79f6b9f7439bbe0a39da39e941d38ea300ea3;hb=f6013eedb4dea47afac8167dfa08561ae90454db;hp=465954fac44901047f93f2070953547984969e95;hpb=f86e7206ea94b48b94fb61007a1c5d55b8c60f45;p=ghc-hetmet.git diff --git a/rts/sm/GCUtils.c b/rts/sm/GCUtils.c index 465954f..39a79f6 100644 --- a/rts/sm/GCUtils.c +++ b/rts/sm/GCUtils.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------------- * - * (c) The GHC Team 1998-2006 + * (c) The GHC Team 1998-2008 * * Generational garbage collector: utilities * @@ -11,14 +11,19 @@ * * ---------------------------------------------------------------------------*/ +#include "PosixSource.h" #include "Rts.h" -#include "RtsFlags.h" + +#include "BlockAlloc.h" #include "Storage.h" #include "GC.h" #include "GCThread.h" #include "GCUtils.h" #include "Printer.h" #include "Trace.h" +#ifdef THREADED_RTS +#include "WSDeque.h" +#endif #ifdef THREADED_RTS SpinLock gc_alloc_block_sync; @@ -34,7 +39,18 @@ allocBlock_sync(void) return bd; } +static bdescr * +allocGroup_sync(nat n) +{ + bdescr *bd; + ACQUIRE_SPIN_LOCK(&gc_alloc_block_sync); + bd = allocGroup(n); + RELEASE_SPIN_LOCK(&gc_alloc_block_sync); + return bd; +} + +#if 0 static void allocBlocks_sync(nat n, bdescr **hd, bdescr **tl, nat gen_no, step *stp, @@ -56,6 +72,7 @@ allocBlocks_sync(nat n, bdescr **hd, bdescr **tl, *tl = &bd[n-1]; RELEASE_SPIN_LOCK(&gc_alloc_block_sync); } +#endif void freeChain_sync(bdescr *bd) @@ -70,35 +87,50 @@ freeChain_sync(bdescr *bd) -------------------------------------------------------------------------- */ bdescr * -grab_todo_block (step_workspace *ws) +grab_local_todo_block (step_workspace *ws) { bdescr *bd; step *stp; stp = ws->step; - bd = NULL; - if (ws->buffer_todo_bd) + bd = ws->todo_overflow; + if (bd != NULL) + { + ws->todo_overflow = bd->link; + bd->link = NULL; + ws->n_todo_overflow--; + return bd; + } + + bd = popWSDeque(ws->todo_q); + if (bd != NULL) { - bd = ws->buffer_todo_bd; ASSERT(bd->link == NULL); - ws->buffer_todo_bd = NULL; return bd; } - ACQUIRE_SPIN_LOCK(&stp->sync_todo); - if (stp->todos) { - bd = stp->todos; - if (stp->todos == stp->todos_last) { - stp->todos_last = NULL; + return NULL; +} + +#if defined(THREADED_RTS) +bdescr * +steal_todo_block (nat s) +{ + nat n; + bdescr *bd; + + // look for work to steal + for (n = 0; n < n_gc_threads; n++) { + if (n == gct->thread_index) continue; + bd = stealWSDeque(gc_threads[n]->steps[s].todo_q); + if (bd) { + return bd; } - stp->todos = bd->link; - stp->n_todos--; - bd->link = NULL; - } - RELEASE_SPIN_LOCK(&stp->sync_todo); - return bd; + } + return NULL; } +#endif void push_scanned_block (bdescr *bd, step_workspace *ws) @@ -108,12 +140,12 @@ push_scanned_block (bdescr *bd, step_workspace *ws) ASSERT(bd->step == ws->step); ASSERT(bd->u.scan == bd->free); - if (bd->start + BLOCK_SIZE_W - bd->free > WORK_UNIT_WORDS) + if (bd->start + bd->blocks * BLOCK_SIZE_W - bd->free > WORK_UNIT_WORDS) { // a partially full block: put it on the part_list list. bd->link = ws->part_list; ws->part_list = bd; - ws->n_part_blocks++; + ws->n_part_blocks += bd->blocks; IF_DEBUG(sanity, ASSERT(countBlocks(ws->part_list) == ws->n_part_blocks)); } @@ -122,7 +154,7 @@ push_scanned_block (bdescr *bd, step_workspace *ws) // put the scan block on the ws->scavd_list. bd->link = ws->scavd_list; ws->scavd_list = bd; - ws->n_scavd_blocks ++; + ws->n_scavd_blocks += bd->blocks; IF_DEBUG(sanity, ASSERT(countBlocks(ws->scavd_list) == ws->n_scavd_blocks)); } @@ -131,8 +163,13 @@ push_scanned_block (bdescr *bd, step_workspace *ws) StgPtr todo_block_full (nat size, step_workspace *ws) { + StgPtr p; bdescr *bd; + // todo_free has been pre-incremented by Evac.c:alloc_for_copy(). We + // are expected to leave it bumped when we've finished here. + ws->todo_free -= size; + bd = ws->todo_bd; ASSERT(bd != NULL); @@ -143,13 +180,15 @@ todo_block_full (nat size, step_workspace *ws) // this block to push, and there's enough room in // this block to evacuate the current object, then just increase // the limit. - if (ws->step->todos != NULL || + if (!looksEmptyWSDeque(ws->todo_q) || (ws->todo_free - bd->u.scan < WORK_UNIT_WORDS / 2)) { - if (ws->todo_free + size < bd->start + BLOCK_SIZE_W) { - ws->todo_lim = stg_min(bd->start + BLOCK_SIZE_W, + if (ws->todo_free + size < bd->start + bd->blocks * BLOCK_SIZE_W) { + ws->todo_lim = stg_min(bd->start + bd->blocks * BLOCK_SIZE_W, ws->todo_lim + stg_max(WORK_UNIT_WORDS,size)); debugTrace(DEBUG_gc, "increasing limit for %p to %p", bd->start, ws->todo_lim); - return ws->todo_free; + p = ws->todo_free; + ws->todo_free += size; + return p; } } @@ -176,19 +215,15 @@ todo_block_full (nat size, step_workspace *ws) { step *stp; stp = ws->step; - trace(TRACE_gc|DEBUG_gc, "push todo block %p (%d words), step %d, n_todos: %d", - bd->start, bd->free - bd->u.scan, stp->abs_no, stp->n_todos); - // ToDo: use buffer_todo - ACQUIRE_SPIN_LOCK(&stp->sync_todo); - if (stp->todos_last == NULL) { - stp->todos_last = bd; - stp->todos = bd; - } else { - stp->todos_last->link = bd; - stp->todos_last = bd; + debugTrace(DEBUG_gc, "push todo block %p (%ld words), step %d, todo_q: %ld", + bd->start, (unsigned long)(bd->free - bd->u.scan), + stp->abs_no, dequeElements(ws->todo_q)); + + if (!pushWSDeque(ws->todo_q, bd)) { + bd->link = ws->todo_overflow; + ws->todo_overflow = bd; + ws->n_todo_overflow++; } - stp->n_todos++; - RELEASE_SPIN_LOCK(&stp->sync_todo); } } @@ -198,47 +233,53 @@ todo_block_full (nat size, step_workspace *ws) alloc_todo_block(ws, size); - return ws->todo_free; + p = ws->todo_free; + ws->todo_free += size; + return p; } StgPtr alloc_todo_block (step_workspace *ws, nat size) { - bdescr *bd, *hd, *tl; - StgWord32 flags; + bdescr *bd/*, *hd, *tl */; // Grab a part block if we have one, and it has enough room - if (ws->part_list != NULL && - ws->part_list->start + BLOCK_SIZE_W - ws->part_list->free > (int)size) + bd = ws->part_list; + if (bd != NULL && + bd->start + bd->blocks * BLOCK_SIZE_W - bd->free > (int)size) { - bd = ws->part_list; ws->part_list = bd->link; - ws->n_part_blocks--; + ws->n_part_blocks -= bd->blocks; } else { - // blocks in to-space in generations up to and including N - // get the BF_EVACUATED flag. - if (ws->step->gen_no <= N) { - flags = BF_EVACUATED; + // blocks in to-space get the BF_EVACUATED flag. + +// allocBlocks_sync(16, &hd, &tl, +// ws->step->gen_no, ws->step, BF_EVACUATED); +// +// tl->link = ws->part_list; +// ws->part_list = hd->link; +// ws->n_part_blocks += 15; +// +// bd = hd; + + if (size > BLOCK_SIZE_W) { + bd = allocGroup_sync((lnat)BLOCK_ROUND_UP(size*sizeof(W_)) + / BLOCK_SIZE); } else { - flags = 0; + bd = allocBlock_sync(); } - allocBlocks_sync(4, &hd, &tl, - ws->step->gen_no, ws->step, flags); - - tl->link = ws->part_list; - ws->part_list = hd->link; - ws->n_part_blocks += 3; - - bd = hd; + initBdescr(bd, ws->step); + bd->flags = BF_EVACUATED; + bd->u.scan = bd->free = bd->start; } bd->link = NULL; ws->todo_bd = bd; ws->todo_free = bd->free; - ws->todo_lim = stg_min(bd->start + BLOCK_SIZE_W, + ws->todo_lim = stg_min(bd->start + bd->blocks * BLOCK_SIZE_W, bd->free + stg_max(WORK_UNIT_WORDS,size)); debugTrace(DEBUG_gc, "alloc new todo block %p for step %d",