diff options
author | Ben Gamari <ben@smart-cactus.org> | 2020-03-02 18:13:52 -0500 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-03-09 06:10:52 -0400 |
commit | 70d2b9956d1ecc9d40d1e2d4920983af00ea846d (patch) | |
tree | a1bda450d47a274098e779432415a18108c342f6 /rts/sm | |
parent | 067632342cf2f063b0f23c255740e2717e5e14c7 (diff) | |
download | haskell-70d2b9956d1ecc9d40d1e2d4920983af00ea846d.tar.gz |
nonmoving: Fix collection of sparks
Previously sparks living in the non-moving heap would be promptly GC'd
by the minor collector since pruneSparkQueue uses the BF_EVACUATED flag,
which non-moving heap blocks do not have set.
Fix this by implementing proper support in pruneSparkQueue for
determining reachability in the non-moving heap. The story is told in
Note [Spark management in the nonmoving heap].
Diffstat (limited to 'rts/sm')
-rw-r--r-- | rts/sm/GC.c | 6 | ||||
-rw-r--r-- | rts/sm/NonMoving.c | 27 |
2 files changed, 30 insertions, 3 deletions
diff --git a/rts/sm/GC.c b/rts/sm/GC.c index 16d8c77453..f6698f5b9e 100644 --- a/rts/sm/GC.c +++ b/rts/sm/GC.c @@ -470,12 +470,12 @@ GarbageCollect (uint32_t collect_gen, #if defined(THREADED_RTS) if (n_gc_threads == 1) { for (n = 0; n < n_capabilities; n++) { - pruneSparkQueue(capabilities[n]); + pruneSparkQueue(false, capabilities[n]); } } else { for (n = 0; n < n_capabilities; n++) { if (n == cap->no || idle_cap[n]) { - pruneSparkQueue(capabilities[n]); + pruneSparkQueue(false, capabilities[n]); } } } @@ -1250,7 +1250,7 @@ gcWorkerThread (Capability *cap) // non-deterministic whether a spark will be retained if it is // only reachable via weak pointers. To fix this problem would // require another GC barrier, which is too high a price. - pruneSparkQueue(cap); + pruneSparkQueue(false, cap); #endif // Wait until we're told to continue diff --git a/rts/sm/NonMoving.c b/rts/sm/NonMoving.c index 2dd201f0f9..fe9d22b479 100644 --- a/rts/sm/NonMoving.c +++ b/rts/sm/NonMoving.c @@ -9,6 +9,7 @@ #include "Rts.h" #include "RtsUtils.h" #include "Capability.h" +#include "Sparks.h" #include "Printer.h" #include "Storage.h" // We call evacuate, which expects the thread-local gc_thread to be valid; @@ -368,6 +369,24 @@ Mutex concurrent_coll_finished_lock; * approximate due to concurrent collection and ultimately seems more costly * than the problem demands. * + * Note [Spark management under the nonmoving collector] + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Every GC, both minor and major, prunes the spark queue (using + * Sparks.c:pruneSparkQueue) of sparks which are no longer reachable. + * Doing this with concurrent collection is a tad subtle since the minor + * collections cannot rely on the mark bitmap to accurately reflect the + * reachability of a spark. + * + * We use a conservative reachability approximation: + * + * - Minor collections assume that all sparks living in the non-moving heap + * are reachable. + * + * - Major collections prune the spark queue during the final sync. This pruning + * assumes that all sparks in the young generations are reachable (since the + * BF_EVACUATED flag won't be set on the nursery blocks) and will consequently + * only prune dead sparks living in the non-moving heap. + * */ memcount nonmoving_live_words = 0; @@ -1056,6 +1075,14 @@ static void nonmovingMark_(MarkQueue *mark_queue, StgWeak **dead_weaks, StgTSO * nonmoving_old_weak_ptr_list = NULL; } + // Prune spark lists + // See Note [Spark management under the nonmoving collector]. +#if defined(THREADED_RTS) + for (uint32_t n = 0; n < n_capabilities; n++) { + pruneSparkQueue(true, capabilities[n]); + } +#endif + // Everything has been marked; allow the mutators to proceed #if defined(THREADED_RTS) nonmoving_write_barrier_enabled = false; |