Remove the optimisation of avoiding scavenging for certain objects
authorSimon Marlow <simonmar@microsoft.com>
Wed, 31 Oct 2007 14:45:42 +0000 (14:45 +0000)
committerSimon Marlow <simonmar@microsoft.com>
Wed, 31 Oct 2007 14:45:42 +0000 (14:45 +0000)
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.

rts/Stats.c
rts/Stats.h
rts/sm/Evac.c
rts/sm/GC.c
rts/sm/GC.h
rts/sm/GCUtils.c

index f18e26f..1b0abaa 100644 (file)
@@ -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*/);
index f7a14a1..2d7e655 100644 (file)
@@ -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);
index 14b80a7..891da0a 100644 (file)
@@ -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:
index 4ca0c9d..2fc3f4d 100644 (file)
@@ -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);
-           }
        }
     }
 
index d45efb9..488a2db 100644 (file)
@@ -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
 
index cee17c4..a65131a 100644 (file)
@@ -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
  * -------------------------------------------------------------------------- */