[commit: ghc] master: Fix crash with large objects (#7919) (d8dd3cf)

Simon Marlow marlowsd at gmail.com
Fri May 24 13:47:10 CEST 2013


Repository : http://darcs.haskell.org/ghc.git/

On branch  : master

https://github.com/ghc/ghc/commit/d8dd3cf954a9bb77d9caa64290fcea0d1abb32ec

>---------------------------------------------------------------

commit d8dd3cf954a9bb77d9caa64290fcea0d1abb32ec
Author: Simon Marlow <marlowsd at gmail.com>
Date:   Fri May 24 08:30:25 2013 +0100

    Fix crash with large objects (#7919)
    
    See comments for details.

>---------------------------------------------------------------

 rts/sm/GCUtils.c | 58 ++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 44 insertions(+), 14 deletions(-)

diff --git a/rts/sm/GCUtils.c b/rts/sm/GCUtils.c
index 2148721..d8633f9 100644
--- a/rts/sm/GCUtils.c
+++ b/rts/sm/GCUtils.c
@@ -161,6 +161,7 @@ push_scanned_block (bdescr *bd, gen_workspace *ws)
 StgPtr
 todo_block_full (nat size, gen_workspace *ws)
 {
+    rtsBool urgent_to_push, can_extend;
     StgPtr p;
     bdescr *bd;
 
@@ -174,20 +175,49 @@ todo_block_full (nat size, gen_workspace *ws)
     ASSERT(bd->link == NULL);
     ASSERT(bd->gen == ws->gen);
 
-    // If the global list is not empty, or there's not much work in
-    // this block to push, and there's enough room in
-    // this block to evacuate the current object, then just increase
-    // the limit.
-    if (!looksEmptyWSDeque(ws->todo_q) || 
-        (ws->todo_free - bd->u.scan < WORK_UNIT_WORDS / 2)) {
-        if (ws->todo_free + size <= bd->start + bd->blocks * BLOCK_SIZE_W) {
-            ws->todo_lim = stg_min(bd->start + bd->blocks * BLOCK_SIZE_W,
-                                   ws->todo_lim + stg_max(WORK_UNIT_WORDS,size));
-            debugTrace(DEBUG_gc, "increasing limit for %p to %p", bd->start, ws->todo_lim);
-            p = ws->todo_free;
-            ws->todo_free += size;
-            return p;
-        }
+    // We intentionally set ws->todo_lim lower than the full size of
+    // the block, so that we can push out some work to the global list
+    // and get the parallel threads working as soon as possible.
+    //
+    // So when ws->todo_lim is reached, we end up here and have to
+    // decide whether it's worth pushing out the work we have or not.
+    // If we have enough room in the block to evacuate the current
+    // object, and it's not urgent to push this work, then we just
+    // extend the limit and keep going.  Where "urgent" is defined as:
+    // the global pool is empty, and there's enough work in this block
+    // to make it worth pushing.
+    //
+    urgent_to_push =
+        looksEmptyWSDeque(ws->todo_q) &&
+        (ws->todo_free - bd->u.scan >= WORK_UNIT_WORDS / 2);
+
+    // We can extend the limit for the current block if there's enough
+    // room for the current object, *and* we're not into the second or
+    // subsequent block of a large block.  The second condition occurs
+    // when we evacuate an object that is larger than a block.  In
+    // that case, alloc_todo_block() sets todo_lim to be exactly the
+    // size of the large object, and we don't evacuate any more
+    // objects into this block.  The reason is that the rest of the GC
+    // is not set up to handle objects that start in the second or
+    // later blocks of a group.  We just about manage this in the
+    // nursery (see scheduleHandleHeapOverflow()) so evacuate() can
+    // handle this, but other parts of the GC can't.  We could
+    // probably fix this, but it's a rare case anyway.
+    //
+    can_extend =
+        ws->todo_free + size <= bd->start + bd->blocks * BLOCK_SIZE_W
+        && ws->todo_free < ws->todo_bd->start + BLOCK_SIZE_W;
+
+    if (!urgent_to_push && can_extend)
+    {
+        ws->todo_lim = stg_min(bd->start + bd->blocks * BLOCK_SIZE_W,
+                               ws->todo_lim + stg_max(WORK_UNIT_WORDS,size));
+        debugTrace(DEBUG_gc, "increasing limit for %p to %p",
+                   bd->start, ws->todo_lim);
+        p = ws->todo_free;
+        ws->todo_free += size;
+
+        return p;
     }
     
     gct->copied += ws->todo_free - bd->free;





More information about the ghc-commits mailing list