Bugfixes; take large objects into account in stats output.
/* -----------------------------------------------------------------------------
- * $Id: StgStorage.h,v 1.9 2001/07/23 17:23:19 simonmar Exp $
+ * $Id: StgStorage.h,v 1.10 2001/07/24 16:36:44 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
*/
typedef struct _step {
- unsigned int no; /* step number */
- bdescr *blocks; /* blocks in this step */
- unsigned int n_blocks; /* number of blocks */
- struct _step *to; /* where collected objects from this step go */
- struct _generation *gen; /* generation this step belongs to */
- unsigned int gen_no; /* generation number (cached) */
- bdescr *large_objects; /* large objects (doubly linked) */
- int is_compacted; /* compact this step */
+ unsigned int no; /* step number */
+ bdescr * blocks; /* blocks in this step */
+ unsigned int n_blocks; /* number of blocks */
+ struct _step * to; /* destination step for live objects */
+ struct _generation * gen; /* generation this step belongs to */
+ unsigned int gen_no; /* generation number (cached) */
+ bdescr * large_objects; /* large objects (doubly linked) */
+ unsigned int n_large_blocks; /* no. of blocks used by large objs */
+ int is_compacted; /* compact this step? (old gen only) */
/* temporary use during GC: */
- StgPtr hp; /* next free locn in to-space */
- StgPtr hpLim; /* end of current to-space block */
- bdescr *hp_bd; /* bdescr of current to-space block */
- bdescr *to_blocks; /* bdescr of first to-space block */
- unsigned int n_to_blocks; /* number of blocks in to-space */
- bdescr *scan_bd; /* block currently being scanned */
- StgPtr scan; /* scan pointer in current block */
- bdescr *new_large_objects; /* large objects collected so far */
- bdescr *scavenged_large_objects; /* live large objects after GC (dbl link) */
- bdescr *bitmap; /* bitmap for compacting collection */
+ StgPtr hp; /* next free locn in to-space */
+ StgPtr hpLim; /* end of current to-space block */
+ bdescr * hp_bd; /* bdescr of current to-space block */
+ bdescr * to_blocks; /* bdescr of first to-space block */
+ unsigned int n_to_blocks; /* number of blocks in to-space */
+ bdescr * scan_bd; /* block currently being scanned */
+ StgPtr scan; /* scan pointer in current block */
+ bdescr * new_large_objects; /* large objects collected so far */
+ bdescr * scavenged_large_objects; /* live large objs after GC (d-link) */
+ unsigned int n_scavenged_large_blocks;/* size of above */
+ bdescr * bitmap; /* bitmap for compacting collection */
} step;
typedef struct _generation {
- unsigned int no; /* generation number */
- step *steps; /* steps */
- unsigned int n_steps; /* number of steps */
- unsigned int max_blocks; /* max blocks in step 0 */
- StgMutClosure *mut_list; /* mutable objects in this generation (not G0)*/
- StgMutClosure *mut_once_list; /* objects that point to younger generations */
+ unsigned int no; /* generation number */
+ step * steps; /* steps */
+ unsigned int n_steps; /* number of steps */
+ unsigned int max_blocks; /* max blocks in step 0 */
+ StgMutClosure *mut_list; /* mut objects in this gen (not G0)*/
+ StgMutClosure *mut_once_list; /* objects that point to younger gens */
/* temporary use during GC: */
- StgMutClosure *saved_mut_list;
+ StgMutClosure * saved_mut_list;
/* stats information */
unsigned int collections;
/* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.106 2001/07/24 06:31:36 ken Exp $
+ * $Id: GC.c,v 1.107 2001/07/24 16:36:43 simonmar Exp $
*
* (c) The GHC Team 1998-1999
*
bdescr *bd;
step *stp;
lnat live, allocated, collected = 0, copied = 0;
+ lnat oldgen_saved_blocks = 0;
nat g, s;
#ifdef PROFILING
} else {
N = 0;
for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
- if (generations[g].steps[0].n_blocks >= generations[g].max_blocks) {
+ if (generations[g].steps[0].n_blocks +
+ generations[g].steps[0].n_large_blocks
+ >= generations[g].max_blocks) {
N = g;
}
}
stp->scan_bd = bd;
stp->new_large_objects = NULL;
stp->scavenged_large_objects = NULL;
+ stp->n_scavenged_large_blocks = 0;
new_blocks++;
// mark the large objects as not evacuated yet
for (bd = stp->large_objects; bd; bd = bd->link) {
stp->n_to_blocks = 0;
stp->new_large_objects = NULL;
stp->scavenged_large_objects = NULL;
+ stp->n_scavenged_large_blocks = 0;
}
}
// NO MORE EVACUATION AFTER THIS POINT!
// Finally: compaction of the oldest generation.
if (major_gc && RtsFlags.GcFlags.compact) {
+ // save number of blocks for stats
+ oldgen_saved_blocks = oldest_gen->steps[0].n_blocks;
compact(get_roots);
}
// for generations we collected...
if (g <= N) {
- collected += stp->n_blocks * BLOCK_SIZE_W; // for stats
+ // rough calculation of garbage collected, for stats output
+ if (stp->is_compacted) {
+ collected += (oldgen_saved_blocks - stp->n_blocks) * BLOCK_SIZE_W;
+ } else {
+ collected += stp->n_blocks * BLOCK_SIZE_W;
+ }
/* free old memory and shift to-space into from-space for all
* the collected steps (except the allocation area). These
freeGroup(bd);
bd = next;
}
+
+ // update the count of blocks used by large objects
for (bd = stp->scavenged_large_objects; bd != NULL; bd = bd->link) {
bd->flags &= ~BF_EVACUATED;
}
- stp->large_objects = stp->scavenged_large_objects;
+ stp->large_objects = stp->scavenged_large_objects;
+ stp->n_large_blocks = stp->n_scavenged_large_blocks;
/* Set the maximum blocks for this generation, interpolating
* between the maximum size of the oldest and youngest
// add the new blocks we promoted during this GC
stp->n_blocks += stp->n_to_blocks;
+ stp->n_large_blocks += stp->n_scavenged_large_blocks;
}
}
}
-
+
/* Set the maximum blocks for the oldest generation, based on twice
* the amount of live data now, adjusted to fit the maximum heap
* size if necessary.
nat needed = calcNeeded(); // approx blocks needed at next GC
/* Guess how much will be live in generation 0 step 0 next time.
- * A good approximation is the obtained by finding the
+ * A good approximation is obtained by finding the
* percentage of g0s0 that was live at the last minor GC.
*/
if (N == 0) {
return p;
}
// large objects have an evacuated flag
- if ((bd->flags & BF_LARGE) && (bd->flags & BF_EVACUATED)) {
- return p;
+ if (bd->flags & BF_LARGE) {
+ if (bd->flags & BF_EVACUATED) {
+ return p;
+ } else {
+ return NULL;
+ }
}
// check the mark bit for compacted steps
if (bd->step->is_compacted && is_marked((P_)p,bd)) {
case CONSTR_2_0:
((StgClosure *)p)->payload[1] = evacuate(((StgClosure *)p)->payload[1]);
((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
+ mark(p+1,Bdescr(p));
break;
case FUN_1_0:
case CONSTR_1_0:
case CONSTR_1_1:
((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
+ mark(p+1,Bdescr(p));
break;
case FUN_0_1:
scavenge_srt(info);
case CONSTR_0_1:
case CONSTR_0_2:
+ mark(p+1,Bdescr(p));
break;
case FUN:
recordOldToNewPtrs((StgMutClosure *)p);
}
failed_to_evac = rtsFalse;
+ mark(p+1,Bdescr(p));
break;
case MUT_VAR:
((StgMutVar *)p)->var = evacuate(((StgMutVar *)p)->var);
evac_gen = saved_evac_gen;
failed_to_evac = rtsFalse;
+ mark(p+1,Bdescr(p));
break;
case MUT_CONS:
continue;
}
+ // Happens if a MUT_ARR_PTRS in the old generation is frozen
+ case MUT_ARR_PTRS_FROZEN:
+ {
+ StgPtr end, q;
+
+ evac_gen = gen->no;
+ end = (P_)p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
+ for (q = (P_)((StgMutArrPtrs *)p)->payload; q < end; q++) {
+ (StgClosure *)*q = evacuate((StgClosure *)*q);
+ }
+ evac_gen = 0;
+ p->mut_link = NULL;
+ if (failed_to_evac) {
+ failed_to_evac = rtsFalse;
+ mkMutCons((StgClosure *)p, gen);
+ }
+ continue;
+ }
+
case MUT_VAR:
((StgMutVar *)p)->var = evacuate(((StgMutVar *)p)->var);
p->mut_link = gen->mut_list;
gen->mut_list = p;
continue;
-
+
case MVAR:
{
StgMVar *mvar = (StgMVar *)p;
stp->new_large_objects = bd->link;
dbl_link_onto(bd, &stp->scavenged_large_objects);
+ // update the block count in this step.
+ stp->n_scavenged_large_blocks += bd->blocks;
+
p = bd->start;
info = get_itbl((StgClosure *)p);
/* -----------------------------------------------------------------------------
- * $Id: Storage.c,v 1.41 2001/07/23 17:23:20 simonmar Exp $
+ * $Id: Storage.c,v 1.42 2001/07/24 16:36:43 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
continue;
}
stp = &generations[g].steps[s];
- live += (stp->n_blocks - 1) * BLOCK_SIZE_W;
+ live += (stp->n_large_blocks + stp->n_blocks - 1) * BLOCK_SIZE_W;
if (stp->hp_bd != NULL) {
live += ((lnat)stp->hp_bd->free - (lnat)stp->hp_bd->start)
/ sizeof(W_);
for (s = 0; s < generations[g].n_steps; s++) {
if (g == 0 && s == 0) { continue; }
stp = &generations[g].steps[s];
- if (generations[g].steps[0].n_blocks > generations[g].max_blocks
+ if (generations[g].steps[0].n_blocks +
+ generations[g].steps[0].n_large_blocks
+ > generations[g].max_blocks
&& stp->is_compacted == 0) {
needed += 2 * stp->n_blocks;
} else {
{
nat n;
for (n=0; bd != NULL; bd=bd->link) {
- n++;
+ n += bd->blocks;
}
return n;
}
for (s = 0; s < generations[g].n_steps; s++) {
if (g == 0 && s == 0) { continue; }
checkHeap(generations[g].steps[s].blocks);
+ checkChain(generations[g].steps[s].large_objects);
ASSERT(countBlocks(generations[g].steps[s].blocks)
== generations[g].steps[s].n_blocks);
- checkChain(generations[g].steps[s].large_objects);
+ ASSERT(countBlocks(generations[g].steps[s].large_objects)
+ == generations[g].steps[s].n_large_blocks);
if (g > 0) {
checkMutableList(generations[g].mut_list, g);
checkMutOnceList(generations[g].mut_once_list, g);