Don't get a new nursery if we exceeded large_alloc_lim
authorSimon Marlow <marlowsd@gmail.com>
Wed, 15 Jul 2015 12:07:35 +0000 (13:07 +0100)
committerSimon Marlow <marlowsd@gmail.com>
Wed, 15 Jul 2015 13:59:28 +0000 (14:59 +0100)
Summary:
When using nursery chunks, if we failed a heap check due to
large_alloc_lim, we would pointlessly keep grabbing new nursery
chunks when we should just GC immediately.

Test Plan: validate

Reviewers: austin, bgamari, niteria

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D1072

rts/Schedule.c

index f1e95bf..257e39a 100644 (file)
@@ -1084,6 +1084,17 @@ schedulePostRunThread (Capability *cap, StgTSO *t)
 static rtsBool
 scheduleHandleHeapOverflow( Capability *cap, StgTSO *t )
 {
+    if (cap->r.rHpLim == NULL || cap->context_switch) {
+        // Sometimes we miss a context switch, e.g. when calling
+        // primitives in a tight loop, MAYBE_GC() doesn't check the
+        // context switch flag, and we end up waiting for a GC.
+        // See #1984, and concurrent/should_run/1984
+        cap->context_switch = 0;
+        appendToRunQueue(cap,t);
+    } else {
+        pushOnRunQueue(cap,t);
+    }
+
     // did the task ask for a large block?
     if (cap->r.rHpAlloc > BLOCK_SIZE) {
         // if so, get one and push it on the front of the nursery.
@@ -1141,27 +1152,23 @@ scheduleHandleHeapOverflow( Capability *cap, StgTSO *t )
             // run queue before us and steal the large block, but in that
             // case the thread will just end up requesting another large
             // block.
-            pushOnRunQueue(cap,t);
             return rtsFalse;  /* not actually GC'ing */
         }
     }
 
+    // if we got here because we exceeded large_alloc_lim, then
+    // proceed straight to GC.
+    if (g0->n_new_large_words >= large_alloc_lim) {
+        return rtsTrue;
+    }
+
+    // Otherwise, we just ran out of space in the current nursery.
+    // Grab another nursery if we can.
     if (getNewNursery(cap)) {
         debugTrace(DEBUG_sched, "thread %ld got a new nursery", t->id);
-        pushOnRunQueue(cap,t);
         return rtsFalse;
     }
 
-    if (cap->r.rHpLim == NULL || cap->context_switch) {
-        // Sometimes we miss a context switch, e.g. when calling
-        // primitives in a tight loop, MAYBE_GC() doesn't check the
-        // context switch flag, and we end up waiting for a GC.
-        // See #1984, and concurrent/should_run/1984
-        cap->context_switch = 0;
-        appendToRunQueue(cap,t);
-    } else {
-        pushOnRunQueue(cap,t);
-    }
     return rtsTrue;
     /* actual GC is done at the end of the while loop in schedule() */
 }