Commit 27a28cf6 authored by simonmarhaskell@gmail.com's avatar simonmarhaskell@gmail.com
Browse files

Keep track of an accurate count of live words in each step

This means we can calculate slop easily, and also improve
predictability of GC.
parent dbbf15c0
......@@ -62,6 +62,7 @@ typedef struct step_ {
bdescr * blocks; // blocks in this step
unsigned int n_blocks; // number of blocks
unsigned int n_words; // number of words
struct step_ * to; // destination step for live objects
......
......@@ -675,40 +675,46 @@ void
statDescribeGens(void)
{
nat g, s, mut, lge;
lnat live;
lnat live, slop;
lnat tot_live, tot_slop;
bdescr *bd;
step *step;
debugBelch(
" Gen Steps Max Mut-list Step Blocks Live Large\n"
" Blocks Bytes Objects\n");
"-----------------------------------------------------------------\n"
" Gen Max Mut-list Step Blocks Large Live Slop\n"
" Blocks Bytes Objects \n"
"-----------------------------------------------------------------\n");
mut = 0;
tot_live = 0;
tot_slop = 0;
for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
mut = 0;
for (bd = generations[g].mut_list; bd != NULL; bd = bd->link) {
mut += (bd->free - bd->start) * sizeof(W_);
}
debugBelch("%8d %8d %8d %9d", g, generations[g].n_steps,
generations[g].max_blocks, mut);
debugBelch("%5d %7d %9d", g, generations[g].max_blocks, mut);
for (s = 0; s < generations[g].n_steps; s++) {
step = &generations[g].steps[s];
live = 0;
for (bd = step->large_objects, lge = 0; bd; bd = bd->link) {
lge++;
}
// This live figure will be slightly less that the "live" figure
// given by +RTS -Sstderr, because we take don't count the
// slop at the end of each block.
live += countOccupied(step->blocks) + countOccupied(step->large_objects);
live = step->n_words + countOccupied(step->large_objects);
if (s != 0) {
debugBelch("%36s","");
debugBelch("%23s","");
}
debugBelch("%6d %8d %8ld %8d\n", s, step->n_blocks,
live, lge);
slop = (step->n_blocks + step->n_large_blocks) * BLOCK_SIZE_W - live;
debugBelch("%6d %8d %8d %8ld %8ld\n", s, step->n_blocks, lge,
live*sizeof(W_), slop*sizeof(W_));
tot_live += live;
tot_slop += slop;
}
}
debugBelch("-----------------------------------------------------------------\n");
debugBelch("%48s%8ld %8ld\n","",tot_live*sizeof(W_),tot_slop*sizeof(W_));
debugBelch("-----------------------------------------------------------------\n");
debugBelch("\n");
}
......
......@@ -195,8 +195,6 @@ GarbageCollect ( rtsBool force_major_gc )
ACQUIRE_SM_LOCK;
debugTrace(DEBUG_gc, "starting GC");
#if defined(RTS_USER_SIGNALS)
if (RtsFlags.MiscFlags.install_signal_handlers) {
// block signals
......@@ -248,11 +246,11 @@ GarbageCollect ( rtsBool force_major_gc )
} else {
n_gc_threads = RtsFlags.ParFlags.gcThreads;
}
trace(TRACE_gc|DEBUG_gc, "GC (gen %d): %dKB to collect, using %d thread(s)",
N, n * (BLOCK_SIZE / 1024), n_gc_threads);
#else
n_gc_threads = 1;
#endif
trace(TRACE_gc|DEBUG_gc, "GC (gen %d): %dKB to collect, using %d thread(s)",
N, n * (BLOCK_SIZE / 1024), n_gc_threads);
#ifdef RTS_GTK_FRONTPANEL
if (RtsFlags.GcFlags.frontpanel) {
......@@ -432,6 +430,7 @@ GarbageCollect ( rtsBool force_major_gc )
prev = ws->part_list;
for (bd = ws->part_list; bd != NULL; bd = bd->link) {
bd->flags &= ~BF_EVACUATED; // now from-space
ws->step->n_words += bd->free - bd->start;
prev = bd;
}
if (prev != NULL) {
......@@ -439,6 +438,7 @@ GarbageCollect ( rtsBool force_major_gc )
}
for (bd = ws->scavd_list; bd != NULL; bd = bd->link) {
bd->flags &= ~BF_EVACUATED; // now from-space
ws->step->n_words += bd->free - bd->start;
prev = bd;
}
prev->link = ws->step->blocks;
......@@ -450,6 +450,7 @@ GarbageCollect ( rtsBool force_major_gc )
ws->step->n_blocks += ws->n_part_blocks;
ws->step->n_blocks += ws->n_scavd_blocks;
ASSERT(countBlocks(ws->step->blocks) == ws->step->n_blocks);
ASSERT(countOccupied(ws->step->blocks) == ws->step->n_words);
}
}
}
......@@ -523,6 +524,7 @@ GarbageCollect ( rtsBool force_major_gc )
// onto the front of the now-compacted existing blocks.
for (bd = stp->blocks; bd != NULL; bd = bd->link) {
bd->flags &= ~BF_EVACUATED; // now from-space
stp->n_words += bd->free - bd->start;
}
// tack the new blocks on the end of the existing blocks
if (stp->old_blocks != NULL) {
......@@ -542,6 +544,7 @@ GarbageCollect ( rtsBool force_major_gc )
// add the new blocks to the block tally
stp->n_blocks += stp->n_old_blocks;
ASSERT(countBlocks(stp->blocks) == stp->n_blocks);
ASSERT(countOccupied(stp->blocks) == stp->n_words);
}
else // not copacted
{
......@@ -591,10 +594,8 @@ GarbageCollect ( rtsBool force_major_gc )
// update the max size of older generations after a major GC
resize_generations();
// Guess the amount of live data for stats.
live = calcLiveBlocks() * BLOCK_SIZE_W;
debugTrace(DEBUG_gc, "Slop: %ldKB",
(live - calcLiveWords()) / (1024/sizeof(W_)));
// Calculate the amount of live data for stats.
live = calcLiveWords();
// Free the small objects allocated via allocate(), since this will
// all have been copied into G0S1 now.
......@@ -604,6 +605,7 @@ GarbageCollect ( rtsBool force_major_gc )
g0s0->blocks = NULL;
}
g0s0->n_blocks = 0;
g0s0->n_words = 0;
}
alloc_blocks = 0;
alloc_blocks_lim = RtsFlags.GcFlags.minAllocAreaSize;
......@@ -941,7 +943,7 @@ initialise_N (rtsBool force_major_gc)
for (g = RtsFlags.GcFlags.generations - 1; g >= 0; g--) {
blocks = 0;
for (s = 0; s < generations[g].n_steps; s++) {
blocks += generations[g].steps[s].n_blocks;
blocks += generations[g].steps[s].n_words / BLOCK_SIZE_W;
blocks += generations[g].steps[s].n_large_blocks;
}
if (blocks >= generations[g].max_blocks) {
......@@ -1254,6 +1256,7 @@ init_collected_gen (nat g, nat n_threads)
stp->n_old_blocks = stp->n_blocks;
stp->blocks = NULL;
stp->n_blocks = 0;
stp->n_words = 0;
// we don't have any to-be-scavenged blocks yet
stp->todos = NULL;
......@@ -1379,6 +1382,7 @@ init_uncollected_gen (nat g, nat threads)
ws->todo_lim = ws->todo_bd->start + BLOCK_SIZE_W;
stp->blocks = stp->blocks->link;
stp->n_blocks -= 1;
stp->n_words -= ws->todo_bd->free - ws->todo_bd->start;
ws->todo_bd->link = NULL;
// this block is also the scan block; we must scan
......@@ -1549,7 +1553,7 @@ resize_generations (void)
nat gens = RtsFlags.GcFlags.generations;
// live in the oldest generations
live = oldest_gen->steps[0].n_blocks +
live = (oldest_gen->steps[0].n_words + BLOCK_SIZE_W - 1) / BLOCK_SIZE_W+
oldest_gen->steps[0].n_large_blocks;
// default max size for all generations except zero
......
......@@ -92,7 +92,7 @@ typedef struct step_workspace_ {
// Objects that have already been, scavenged.
bdescr * scavd_list;
lnat n_scavd_blocks; // count of blocks in this list
nat n_scavd_blocks; // count of blocks in this list
// Partially-full, scavenged, blocks
bdescr * part_list;
......
......@@ -87,6 +87,7 @@ initStep (step *stp, int g, int s)
stp->abs_no = RtsFlags.GcFlags.steps * g + s;
stp->blocks = NULL;
stp->n_blocks = 0;
stp->n_words = 0;
stp->old_blocks = NULL;
stp->n_old_blocks = 0;
stp->gen = &generations[g];
......@@ -999,7 +1000,7 @@ calcLiveWords(void)
step *stp;
if (RtsFlags.GcFlags.generations == 1) {
return countOccupied(g0s0->blocks) + countOccupied(g0s0->large_objects);
return g0s0->n_words + countOccupied(g0s0->large_objects);
}
live = 0;
......@@ -1007,8 +1008,7 @@ calcLiveWords(void)
for (s = 0; s < generations[g].n_steps; s++) {
if (g == 0 && s == 0) continue;
stp = &generations[g].steps[s];
live += countOccupied(stp->blocks) +
countOccupied(stp->large_objects);
live += stp->n_words + countOccupied(stp->large_objects);
}
}
return live;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment