* We build up a static object list while collecting generations 0..N,
* which is then appended to the static object list of generation N+1.
*/
-StgClosure* static_objects; // live static objects
-StgClosure* scavenged_static_objects; // static objects scavenged so far
-#ifdef THREADED_RTS
-SpinLock static_objects_sync;
-#endif
/* N is the oldest generation being collected, where the generations
* are numbered starting at 0. A major GC (indicated by the major_gc
/* Thread-local data for each GC thread
*/
-gc_thread *gc_threads = NULL;
+gc_thread **gc_threads = NULL;
// gc_thread *gct = NULL; // this thread's gct TODO: make thread-local
// Number of threads running in *this* GC. Affects how many
// check stack sanity *before* GC (ToDo: check all threads)
IF_DEBUG(sanity, checkFreeListSanity());
- /* Initialise the static object lists
- */
- static_objects = END_OF_STATIC_LIST;
- scavenged_static_objects = END_OF_STATIC_LIST;
-
// Initialise all the generations/steps that we're collecting.
for (g = 0; g <= N; g++) {
init_collected_gen(g,n_gc_threads);
// Initialise all our gc_thread structures
for (t = 0; t < n_gc_threads; t++) {
- init_gc_thread(&gc_threads[t]);
+ init_gc_thread(gc_threads[t]);
}
// the main thread is running: this prevents any other threads from
inc_running();
wakeup_gc_threads(n_gc_threads);
- // Initialise stats
- copied = 0;
-
// this is the main thread
- gct = &gc_threads[0];
+ gct = gc_threads[0];
/* -----------------------------------------------------------------------
* follow all the roots that we know about:
bdescr *prev;
for (t = 0; t < n_gc_threads; t++) {
- thr = &gc_threads[t];
-
- for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
- for (s = 0; s < generations[g].n_steps; s++) {
- ws = &thr->steps[g][s];
- if (g==0 && s==0) continue;
-
- // Not true?
- // ASSERT( ws->scan_bd == ws->todo_bd );
- ASSERT( ws->scan_bd ? ws->scan == ws->scan_bd->free : 1 );
-
- // Push the final block
- if (ws->scan_bd) { push_scan_block(ws->scan_bd, ws); }
-
- ASSERT(countBlocks(ws->scavd_list) == ws->n_scavd_blocks);
-
- prev = ws->scavd_list;
- for (bd = ws->scavd_list; bd != NULL; bd = bd->link) {
- bd->flags &= ~BF_EVACUATED; // now from-space
- prev = bd;
- }
- prev->link = ws->stp->blocks;
- ws->stp->blocks = ws->scavd_list;
- ws->stp->n_blocks += ws->n_scavd_blocks;
- ASSERT(countBlocks(ws->stp->blocks) == ws->stp->n_blocks);
- }
+ thr = gc_threads[t];
+
+ // not step 0
+ for (s = 1; s < total_steps; s++) {
+ ws = &thr->steps[s];
+ // Not true?
+ // ASSERT( ws->scan_bd == ws->todo_bd );
+ ASSERT( ws->scan_bd ? ws->scan == ws->scan_bd->free : 1 );
+
+ // Push the final block
+ if (ws->scan_bd) { push_scan_block(ws->scan_bd, ws); }
+
+ ASSERT(countBlocks(ws->scavd_list) == ws->n_scavd_blocks);
+
+ prev = ws->scavd_list;
+ for (bd = ws->scavd_list; bd != NULL; bd = bd->link) {
+ bd->flags &= ~BF_EVACUATED; // now from-space
+ prev = bd;
+ }
+ prev->link = ws->stp->blocks;
+ ws->stp->blocks = ws->scavd_list;
+ ws->stp->n_blocks += ws->n_scavd_blocks;
+ ASSERT(countBlocks(ws->stp->blocks) == ws->stp->n_blocks);
}
}
}
/* run through all the generations/steps and tidy up
*/
+ copied = 0;
+ {
+ nat i;
+ for (i=0; i < n_gc_threads; i++) {
+ if (major_gc) {
+ trace(TRACE_gc,"thread %d:", i);
+ trace(TRACE_gc," copied %ld", gc_threads[i]->copied * sizeof(W_));
+ trace(TRACE_gc," any_work %ld", gc_threads[i]->any_work);
+ trace(TRACE_gc," no_work %ld", gc_threads[i]->no_work);
+ trace(TRACE_gc," scav_global_work %ld", gc_threads[i]->scav_global_work);
+ trace(TRACE_gc," scav_local_work %ld", gc_threads[i]->scav_local_work);
+ }
+ copied += gc_threads[i]->copied;
+ }
+ }
+
for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
if (g <= N) {
#ifdef PROFILING
// resetStaticObjectForRetainerProfiling() must be called before
// zeroing below.
- resetStaticObjectForRetainerProfiling();
+ if (n_gc_threads > 1) {
+ barf("profiling is currently broken with multi-threaded GC");
+ // ToDo: fix the gct->scavenged_static_objects below
+ }
+ resetStaticObjectForRetainerProfiling(gct->scavenged_static_objects);
#endif
// zero the scavenged static object list
if (major_gc) {
- zero_static_object_list(scavenged_static_objects);
+ nat i;
+ for (i = 0; i < n_gc_threads; i++) {
+ zero_static_object_list(gc_threads[i]->scavenged_static_objects);
+ }
}
// Reset the nursery
IF_DEBUG(sanity, checkSanity());
// extra GC trace info
- IF_DEBUG(gc, statDescribeGens());
+ if (traceClass(TRACE_gc)) statDescribeGens();
#ifdef DEBUG
// symbol-table based profiling
Initialise the gc_thread structures.
-------------------------------------------------------------------------- */
-static void
-alloc_gc_thread (gc_thread *t, int n)
+static gc_thread *
+alloc_gc_thread (int n)
{
- nat g, s;
+ nat s;
step_workspace *ws;
+ gc_thread *t;
+
+ t = stgMallocBytes(sizeof(gc_thread) + total_steps * sizeof(step_workspace),
+ "alloc_gc_thread");
#ifdef THREADED_RTS
t->id = 0;
t->papi_events = -1;
#endif
- t->steps = stgMallocBytes(RtsFlags.GcFlags.generations *
- sizeof(step_workspace *),
- "initialise_gc_thread");
-
- for (g = 0; g < RtsFlags.GcFlags.generations; g++)
+ for (s = 0; s < total_steps; s++)
{
- t->steps[g] = stgMallocBytes(generations[g].n_steps *
- sizeof(step_workspace),
- "initialise_gc_thread/2");
-
- for (s = 0; s < generations[g].n_steps; s++)
- {
- ws = &t->steps[g][s];
- ws->stp = &generations[g].steps[s];
- ws->gct = t;
-
- ws->scan_bd = NULL;
- ws->scan = NULL;
-
- ws->todo_bd = NULL;
- ws->buffer_todo_bd = NULL;
-
- ws->scavd_list = NULL;
- ws->n_scavd_blocks = 0;
- }
+ ws = &t->steps[s];
+ ws->stp = &all_steps[s];
+ ASSERT(s == ws->stp->abs_no);
+ ws->gct = t;
+
+ ws->scan_bd = NULL;
+ ws->scan = NULL;
+
+ ws->todo_bd = NULL;
+ ws->buffer_todo_bd = NULL;
+
+ ws->scavd_list = NULL;
+ ws->n_scavd_blocks = 0;
}
+
+ return t;
}
#if defined(THREADED_RTS)
nat i;
gc_threads = stgMallocBytes (RtsFlags.ParFlags.gcThreads *
- sizeof(gc_thread),
+ sizeof(gc_thread*),
"alloc_gc_threads");
for (i = 0; i < RtsFlags.ParFlags.gcThreads; i++) {
- alloc_gc_thread(&gc_threads[i], i);
+ gc_threads[i] = alloc_gc_thread(i);
}
#else
- gc_threads = stgMallocBytes (sizeof(gc_thread),
+ gc_threads = stgMallocBytes (sizeof(gc_thread*),
"alloc_gc_threads");
- alloc_gc_thread(gc_threads, 0);
+ gc_threads[0] = alloc_gc_thread(0);
#endif
}
}
// Start from 1: the main thread is 0
for (i = 1; i < RtsFlags.ParFlags.gcThreads; i++) {
createOSThread(&id, (OSThreadProc*)&gc_thread_entry,
- &gc_threads[i]);
+ gc_threads[i]);
}
done = rtsTrue;
}
nat i;
for (i=1; i < n_threads; i++) {
inc_running();
- ACQUIRE_LOCK(&gc_threads[i].wake_mutex);
- gc_threads[i].wakeup = rtsTrue;
- signalCondition(&gc_threads[i].wake_cond);
- RELEASE_LOCK(&gc_threads[i].wake_mutex);
+ ACQUIRE_LOCK(&gc_threads[i]->wake_mutex);
+ gc_threads[i]->wakeup = rtsTrue;
+ signalCondition(&gc_threads[i]->wake_cond);
+ RELEASE_LOCK(&gc_threads[i]->wake_mutex);
}
#endif
}
// we don't copy objects into g0s0, unless -G0
if (g==0 && s==0 && RtsFlags.GcFlags.generations > 1) continue;
- ws = &gc_threads[t].steps[g][s];
+ ws = &gc_threads[t]->steps[g * RtsFlags.GcFlags.steps + s];
ws->scan_bd = NULL;
ws->scan = NULL;
for (t = 0; t < threads; t++) {
for (s = 0; s < generations[g].n_steps; s++) {
- ws = &gc_threads[t].steps[g][s];
+ ws = &gc_threads[t]->steps[g * RtsFlags.GcFlags.steps + s];
stp = ws->stp;
ws->buffer_todo_bd = NULL;
static void
init_gc_thread (gc_thread *t)
{
+ t->static_objects = END_OF_STATIC_LIST;
+ t->scavenged_static_objects = END_OF_STATIC_LIST;
t->evac_step = 0;
t->failed_to_evac = rtsFalse;
t->eager_promotion = rtsTrue;
t->thunk_selector_depth = 0;
+ t->copied = 0;
+ t->any_work = 0;
+ t->no_work = 0;
+ t->scav_global_work = 0;
+ t->scav_local_work = 0;
+
}
/* -----------------------------------------------------------------------------