Commit cacd714c authored by Simon Marlow's avatar Simon Marlow

Remove the optimisation of avoiding scavenging for certain objects

Some objects don't need to be scavenged, in particular if they have no
pointers.  This seems like an obvious optimisation, but in fact it
only accounts for about 1% of objects (in GHC, for example), and the
extra complication means it probably isn't worth doing.
parent c3572443
......@@ -41,7 +41,6 @@ static Ticks ExitElapsedTime = 0;
static ullong GC_tot_alloc = 0;
static ullong GC_tot_copied = 0;
static ullong GC_tot_scavd_copied = 0;
static Ticks GC_start_time = 0, GC_tot_time = 0; /* User GC Time */
static Ticks GCe_start_time = 0, GCe_tot_time = 0; /* Elapsed GC time */
......@@ -288,8 +287,7 @@ stat_startGC(void)
-------------------------------------------------------------------------- */
void
stat_endGC (lnat alloc, lnat live, lnat copied,
lnat scavd_copied, lnat gen)
stat_endGC (lnat alloc, lnat live, lnat copied, lnat gen)
{
if (RtsFlags.GcFlags.giveStats != NO_GC_STATS) {
Ticks time, etime, gc_time, gc_etime;
......@@ -302,7 +300,7 @@ stat_endGC (lnat alloc, lnat live, lnat copied,
nat faults = getPageFaults();
statsPrintf("%9ld %9ld %9ld",
alloc*sizeof(W_), (copied+scavd_copied)*sizeof(W_),
alloc*sizeof(W_), copied*sizeof(W_),
live*sizeof(W_));
statsPrintf(" %5.2f %5.2f %7.2f %7.2f %4ld %4ld (Gen: %2ld)\n",
TICK_TO_DBL(gc_time),
......@@ -320,7 +318,6 @@ stat_endGC (lnat alloc, lnat live, lnat copied,
GC_coll_times[gen] += gc_time;
GC_tot_copied += (ullong) copied;
GC_tot_scavd_copied += (ullong) scavd_copied;
GC_tot_alloc += (ullong) alloc;
GC_tot_time += gc_time;
GCe_tot_time += gc_etime;
......@@ -522,12 +519,8 @@ stat_exit(int alloc)
ullong_format_string(GC_tot_copied*sizeof(W_),
temp, rtsTrue/*commas*/);
statsPrintf("%11s bytes copied during GC (scavenged)\n", temp);
statsPrintf("%11s bytes copied during GC\n", temp);
ullong_format_string(GC_tot_scavd_copied*sizeof(W_),
temp, rtsTrue/*commas*/);
statsPrintf("%11s bytes copied during GC (not scavenged)\n", temp);
if ( ResidencySamples > 0 ) {
ullong_format_string(MaxResidency*sizeof(W_),
temp, rtsTrue/*commas*/);
......
......@@ -16,7 +16,7 @@ void stat_endInit(void);
void stat_startGC(void);
void stat_endGC (lnat alloc, lnat live,
lnat copied, lnat scavd_copied, lnat gen);
lnat copied, lnat gen);
#ifdef PROFILING
void stat_startRP(void);
......
......@@ -63,42 +63,6 @@ alloc_for_copy (nat size, step *stp)
return to;
}
STATIC_INLINE StgPtr
alloc_for_copy_noscav (nat size, step *stp)
{
StgPtr to;
step_workspace *ws;
bdescr *bd;
/* Find out where we're going, using the handy "to" pointer in
* the step of the source object. If it turns out we need to
* evacuate to an older generation, adjust it here (see comment
* by evacuate()).
*/
if (stp < gct->evac_step) {
if (gct->eager_promotion) {
stp = gct->evac_step;
} else {
gct->failed_to_evac = rtsTrue;
}
}
ws = &gct->steps[stp->gen_no][stp->no];
/* chain a new block onto the to-space for the destination step if
* necessary.
*/
bd = ws->scavd_list;
to = bd->free;
if (to + size >= bd->start + BLOCK_SIZE_W) {
bd = gc_alloc_scavd_block(ws);
to = bd->free;
}
bd->free = to + size;
return to;
}
STATIC_INLINE void
copy_tag(StgClosure **p, StgClosure *src, nat size, step *stp,StgWord tag)
{
......@@ -152,57 +116,6 @@ copy_tag(StgClosure **p, StgClosure *src, nat size, step *stp,StgWord tag)
#endif
}
// Same as copy() above, except the object will be allocated in memory
// that will not be scavenged. Used for object that have no pointer
// fields.
STATIC_INLINE void
copy_noscav_tag(StgClosure **p, StgClosure *src, nat size, step *stp, StgWord tag)
{
StgPtr to, tagged_to, from;
nat i;
StgWord info;
#ifdef THREADED_RTS
do {
info = xchg((StgPtr)&src->header.info, (W_)&stg_WHITEHOLE_info);
} while (info == (W_)&stg_WHITEHOLE_info);
if (info == (W_)&stg_EVACUATED_info) {
src->header.info = (const StgInfoTable *)info;
return evacuate(p); // does the failed_to_evac stuff
}
#else
info = (W_)src->header.info;
src->header.info = &stg_EVACUATED_info;
#endif
to = alloc_for_copy_noscav(size,stp);
tagged_to = (StgPtr)TAG_CLOSURE(tag,(StgClosure*)to);
*p = (StgClosure *)tagged_to;
TICK_GC_WORDS_COPIED(size);
from = (StgPtr)src;
to[0] = info;
for (i = 1; i < size; i++) { // unroll for small i
to[i] = from[i];
}
((StgEvacuated*)from)->evacuee = (StgClosure *)tagged_to;
#ifdef THREADED_RTS
write_barrier();
((StgEvacuated*)from)->header.info = &stg_EVACUATED_info;
#endif
#ifdef PROFILING
// We store the size of the just evacuated object in the LDV word so that
// the profiler can guess the position of the next object later.
SET_EVACUAEE_FOR_LDV(from, size);
#endif
}
/* Special version of copy() for when we only want to copy the info
* pointer of an object, but reserve some padding after it. This is
* used to optimise evacuation of BLACKHOLEs.
......@@ -226,7 +139,7 @@ copyPart(StgClosure **p, StgClosure *src, nat size_to_reserve, nat size_to_copy,
info = (W_)src->header.info;
src->header.info = &stg_EVACUATED_info;
#endif
to = alloc_for_copy(size_to_reserve, stp);
*p = (StgClosure *)to;
......@@ -262,12 +175,6 @@ copy(StgClosure **p, StgClosure *src, nat size, step *stp)
copy_tag(p,src,size,stp,0);
}
STATIC_INLINE void
copy_noscav(StgClosure **p, StgClosure *src, nat size, step *stp)
{
copy_noscav_tag(p,src,size,stp,0);
}
/* -----------------------------------------------------------------------------
Evacuate a large object
......@@ -561,7 +468,7 @@ loop:
);
}
else {
copy_noscav_tag(p,q,sizeofW(StgHeader)+1,stp,tag);
copy_tag(p,q,sizeofW(StgHeader)+1,stp,tag);
}
return;
}
......@@ -599,7 +506,7 @@ loop:
return;
case CONSTR_0_2:
copy_noscav_tag(p,q,sizeofW(StgHeader)+2,stp,tag);
copy_tag(p,q,sizeofW(StgHeader)+2,stp,tag);
return;
case THUNK:
......@@ -693,7 +600,7 @@ loop:
case ARR_WORDS:
// just copy the block
copy_noscav(p,q,arr_words_sizeW((StgArrWords *)q),stp);
copy(p,q,arr_words_sizeW((StgArrWords *)q),stp);
return;
case MUT_ARR_PTRS_CLEAN:
......
......@@ -122,7 +122,6 @@ gc_thread *gc_threads = NULL;
// For stats:
long copied; // *words* copied & scavenged during this GC
long scavd_copied; // *words* copied only during this GC
#ifdef THREADED_RTS
SpinLock recordMutableGen_sync;
......@@ -310,7 +309,6 @@ GarbageCollect ( rtsBool force_major_gc )
// Initialise stats
copied = 0;
scavd_copied = 0;
// this is the main thread
gct = &gc_threads[0];
......@@ -434,10 +432,6 @@ GarbageCollect ( rtsBool force_major_gc )
// Push the final block
if (ws->scan_bd) { push_scan_block(ws->scan_bd, ws); }
// update stats: we haven't counted the block at the
// front of the scavd_list yet.
scavd_copied += ws->scavd_list->free - ws->scavd_list->start;
ASSERT(countBlocks(ws->scavd_list) == ws->n_scavd_blocks);
prev = ws->scavd_list;
......@@ -672,7 +666,7 @@ GarbageCollect ( rtsBool force_major_gc )
#endif
// ok, GC over: tell the stats department what happened.
stat_endGC(allocated, live, copied, scavd_copied, N);
stat_endGC(allocated, live, copied, N);
#if defined(RTS_USER_SIGNALS)
if (RtsFlags.MiscFlags.install_signal_handlers) {
......@@ -1182,12 +1176,8 @@ init_collected_gen (nat g, nat n_threads)
ws->buffer_todo_bd = NULL;
gc_alloc_todo_block(ws);
// allocate a block for "already scavenged" objects. This goes
// on the front of the stp->blocks list, so it won't be
// traversed by the scavenging sweep.
ws->scavd_list = NULL;
ws->n_scavd_blocks = 0;
gc_alloc_scavd_block(ws);
}
}
}
......@@ -1220,6 +1210,9 @@ init_uncollected_gen (nat g, nat threads)
ws->buffer_todo_bd = NULL;
ws->todo_large_objects = NULL;
ws->scavd_list = NULL;
ws->n_scavd_blocks = 0;
// If the block at the head of the list in this generation
// is less than 3/4 full, then use it as a todo block.
if (isPartiallyFull(stp->blocks))
......@@ -1245,25 +1238,6 @@ init_uncollected_gen (nat g, nat threads)
ws->todo_bd = NULL;
gc_alloc_todo_block(ws);
}
// Do the same trick for the scavd block
if (isPartiallyFull(stp->blocks))
{
ws->scavd_list = stp->blocks;
stp->blocks = stp->blocks->link;
stp->n_blocks -= 1;
ws->scavd_list->link = NULL;
ws->n_scavd_blocks = 1;
// subtract the contents of this block from the stats,
// because we'll count the whole block later.
scavd_copied -= ws->scavd_list->free - ws->scavd_list->start;
}
else
{
ws->scavd_list = NULL;
ws->n_scavd_blocks = 0;
gc_alloc_scavd_block(ws);
}
}
}
......
......@@ -88,11 +88,7 @@ typedef struct step_workspace_ {
// where large objects to be scavenged go
bdescr * todo_large_objects;
// Objects that need not be, or have already been, scavenged. The
// block at the front of the list is special: objects that don't
// need to be scavenged are copied directly to this block.
// Completed scan blocks also go on this list; but we put them
// after the head block.
// Objects that need not be, or have already been, scavenged.
bdescr * scavd_list;
lnat n_scavd_blocks; // count of blocks in this list
......
......@@ -82,11 +82,9 @@ push_scan_block (bdescr *bd, step_workspace *ws)
// update stats: this is a block that has been copied & scavenged
copied += bd->free - bd->start;
// put the scan block *second* in ws->scavd_list. The first block
// in this list is for evacuating objects that don't need to be
// scavenged.
bd->link = ws->scavd_list->link;
ws->scavd_list->link = bd;
// put the scan block on the ws->scavd_list.
bd->link = ws->scavd_list;
ws->scavd_list = bd;
ws->n_scavd_blocks ++;
IF_DEBUG(sanity,
......@@ -130,36 +128,6 @@ gc_alloc_todo_block (step_workspace *ws)
return bd;
}
bdescr *
gc_alloc_scavd_block (step_workspace *ws)
{
bdescr *bd;
bd = allocBlock_sync();
bd->gen_no = ws->stp->gen_no;
bd->step = ws->stp;
// blocks in to-space in generations up to and including N
// get the BF_EVACUATED flag.
if (ws->stp->gen_no <= N) {
bd->flags = BF_EVACUATED;
} else {
bd->flags = 0;
}
// update stats: this is a block that has been copied only
if (ws->scavd_list != NULL) {
scavd_copied += ws->scavd_list->free - ws->scavd_list->start;
}
bd->link = ws->scavd_list;
ws->scavd_list = bd;
ws->n_scavd_blocks++;
return bd;
}
/* -----------------------------------------------------------------------------
* Debugging
* -------------------------------------------------------------------------- */
......
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