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 */
-------------------------------------------------------------------------- */
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;
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),
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;
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*/);
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);
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)
{
#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.
info = (W_)src->header.info;
src->header.info = &stg_EVACUATED_info;
#endif
-
+
to = alloc_for_copy(size_to_reserve, stp);
*p = (StgClosure *)to;
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
);
}
else {
- copy_noscav_tag(p,q,sizeofW(StgHeader)+1,stp,tag);
+ copy_tag(p,q,sizeofW(StgHeader)+1,stp,tag);
}
return;
}
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:
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:
// 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;
// Initialise stats
copied = 0;
- scavd_copied = 0;
// this is the main thread
gct = &gc_threads[0];
// 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;
#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) {
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);
}
}
}
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))
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);
- }
}
}
// 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
// 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,
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
* -------------------------------------------------------------------------- */