Refactor PAPI support, and add profiling of multithreaded GC
[ghc-hetmet.git] / rts / sm / GC.c
index eed2da7..f248a75 100644 (file)
@@ -40,6 +40,7 @@
 #include "RetainerProfile.h"
 #include "RaiseAsync.h"
 #include "Sparks.h"
+#include "Papi.h"
 
 #include "GC.h"
 #include "Compact.h"
@@ -122,7 +123,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;
@@ -183,9 +183,12 @@ GarbageCollect ( rtsBool force_major_gc )
   lnat live, allocated;
   lnat oldgen_saved_blocks = 0;
   nat n_threads; // number of threads participating in GC
-
+  gc_thread *saved_gct;
   nat g, s, t;
 
+  // necessary if we stole a callee-saves register for gct:
+  saved_gct = gct;
+
 #ifdef PROFILING
   CostCentreStack *prev_CCS;
 #endif
@@ -307,7 +310,6 @@ GarbageCollect ( rtsBool force_major_gc )
 
   // Initialise stats
   copied = 0;
-  scavd_copied = 0;
 
   // this is the main thread
   gct = &gc_threads[0];
@@ -332,11 +334,11 @@ GarbageCollect ( rtsBool force_major_gc )
   }
 
   // follow roots from the CAF list (used by GHCi)
-  gct->evac_gen = 0;
+  gct->evac_step = 0;
   markCAFs(mark_root);
 
   // follow all the roots that the application knows about.
-  gct->evac_gen = 0;
+  gct->evac_step = 0;
   GetRoots(mark_root);
 
   // Mark the weak pointer list, and prepare to detect dead weak pointers.
@@ -431,10 +433,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;
@@ -669,7 +667,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) {
@@ -679,6 +677,8 @@ GarbageCollect ( rtsBool force_major_gc )
 #endif
 
   RELEASE_SM_LOCK;
+
+  gct = saved_gct;
 }
 
 /* ---------------------------------------------------------------------------
@@ -874,6 +874,10 @@ alloc_gc_thread (gc_thread *t, int n)
 
     init_gc_thread(t);
     
+#ifdef USE_PAPI
+    t->papi_events = -1;
+#endif
+
     t->steps = stgMallocBytes(RtsFlags.GcFlags.generations * 
                                sizeof(step_workspace *), 
                                "initialise_gc_thread");
@@ -1012,7 +1016,20 @@ gc_thread_mainloop (void)
        gct->wakeup = rtsFalse;
        if (gct->exit) break;
 
+#ifdef USE_PAPI
+        // start performance counters in this thread...
+        if (gct->papi_events == -1) {
+            papi_init_eventset(&gct->papi_events);
+        }
+        papi_thread_start_gc_count(gct->papi_events);
+#endif
+
        gc_thread_work();
+
+#ifdef USE_PAPI
+        // count events in this thread towards the GC totals
+        papi_thread_stop_gc_count(gct->papi_events);
+#endif
     }
 }      
 #endif
@@ -1177,12 +1194,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);
        }
     }
 }
@@ -1215,6 +1228,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))
@@ -1240,25 +1256,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);
-           }
        }
     }
 
@@ -1282,7 +1279,7 @@ init_uncollected_gen (nat g, nat threads)
 static void
 init_gc_thread (gc_thread *t)
 {
-    t->evac_gen = 0;
+    t->evac_step = 0;
     t->failed_to_evac = rtsFalse;
     t->eager_promotion = rtsTrue;
     t->thunk_selector_depth = 0;
@@ -1295,7 +1292,7 @@ init_gc_thread (gc_thread *t)
 static void
 mark_root(StgClosure **root)
 {
-  *root = evacuate(*root);
+  evacuate(root);
 }
 
 /* -----------------------------------------------------------------------------