[Git][ghc/ghc][wip/perform-blocking-gc] rts: Introduce performBlockingMajorGC

Ben Gamari gitlab at gitlab.haskell.org
Sat May 30 16:51:37 UTC 2020



Ben Gamari pushed to branch wip/perform-blocking-gc at Glasgow Haskell Compiler / GHC


Commits:
da04a864 by Ben Gamari at 2020-05-30T12:51:29-04:00
rts: Introduce performBlockingMajorGC

- - - - -


7 changed files:

- libraries/base/System/Mem.hs
- rts/RtsSymbols.c
- rts/Schedule.c
- rts/sm/GC.c
- rts/sm/GC.h
- rts/sm/NonMoving.c
- rts/sm/NonMoving.h


Changes:

=====================================
libraries/base/System/Mem.hs
=====================================
@@ -3,7 +3,7 @@
 -- Module      :  System.Mem
 -- Copyright   :  (c) The University of Glasgow 2001
 -- License     :  BSD-style (see the file libraries/base/LICENSE)
--- 
+--
 -- Maintainer  :  libraries at haskell.org
 -- Stability   :  provisional
 -- Portability :  portable
@@ -19,6 +19,7 @@ module System.Mem
        (
        -- * Garbage collection
          performGC
+       , performBlockingMajorGC
        , performMajorGC
        , performMinorGC
 
@@ -35,6 +36,12 @@ import GHC.Conc.Sync
 performGC :: IO ()
 performGC = performMajorGC
 
+-- | Triggers an immediate major garbage collection, ensuring that collection
+-- finishes before returning.
+--
+-- @since 4.15.0.0
+foreign import ccall "performBlockingMajorGC" performBlockingMajorGC :: IO ()
+
 -- | Triggers an immediate major garbage collection.
 --
 -- @since 4.7.0.0


=====================================
rts/RtsSymbols.c
=====================================
@@ -717,13 +717,14 @@
       SymI_HasProto(stg_isMutableByteArrayPinnedzh)                     \
       SymI_HasProto(stg_shrinkMutableByteArrayzh)                       \
       SymI_HasProto(stg_resizzeMutableByteArrayzh)                      \
-      SymI_HasProto(stg_shrinkSmallMutableArrayzh)                       \
+      SymI_HasProto(stg_shrinkSmallMutableArrayzh)                      \
       SymI_HasProto(newSpark)                                           \
-      SymI_HasProto(updateRemembSetPushThunk)                             \
-      SymI_HasProto(updateRemembSetPushThunk_)                            \
-      SymI_HasProto(updateRemembSetPushClosure_)                          \
+      SymI_HasProto(updateRemembSetPushThunk)                           \
+      SymI_HasProto(updateRemembSetPushThunk_)                          \
+      SymI_HasProto(updateRemembSetPushClosure_)                        \
       SymI_HasProto(performGC)                                          \
       SymI_HasProto(performMajorGC)                                     \
+      SymI_HasProto(performBlockingMajorGC)                             \
       SymI_HasProto(prog_argc)                                          \
       SymI_HasProto(prog_argv)                                          \
       SymI_HasProto(stg_putMVarzh)                                      \


=====================================
rts/Schedule.c
=====================================
@@ -165,7 +165,9 @@ static bool scheduleHandleThreadFinished( Capability *cap, Task *task,
                                           StgTSO *t );
 static bool scheduleNeedHeapProfile(bool ready_to_gc);
 static void scheduleDoGC( Capability **pcap, Task *task,
-                          bool force_major, bool deadlock_detect );
+                          bool force_major,
+                          bool deadlock_detect,
+                          bool force_nonconcurrent );
 
 static void deleteThread (StgTSO *tso);
 static void deleteAllThreads (void);
@@ -265,7 +267,7 @@ schedule (Capability *initialCapability, Task *task)
     case SCHED_INTERRUPTING:
         debugTrace(DEBUG_sched, "SCHED_INTERRUPTING");
         /* scheduleDoGC() deletes all the threads */
-        scheduleDoGC(&cap,task,true,false);
+        scheduleDoGC(&cap, task, true, false, false);
 
         // after scheduleDoGC(), we must be shutting down.  Either some
         // other Capability did the final GC, or we did it above,
@@ -562,7 +564,7 @@ run_thread:
     }
 
     if (ready_to_gc || scheduleNeedHeapProfile(ready_to_gc)) {
-      scheduleDoGC(&cap,task,false,false);
+      scheduleDoGC(&cap, task, false, false, false);
     }
   } /* end of while() */
 }
@@ -936,7 +938,10 @@ scheduleDetectDeadlock (Capability **pcap, Task *task)
         // they are unreachable and will therefore be sent an
         // exception.  Any threads thus released will be immediately
         // runnable.
-        scheduleDoGC (pcap, task, true/*force major GC*/, true/*deadlock detection*/);
+        scheduleDoGC (pcap, task,
+                      true/*force major GC*/,
+                      true/*deadlock detection*/,
+                      false/*force_nonconcurrent*/);
         cap = *pcap;
         // when force_major == true. scheduleDoGC sets
         // recent_activity to ACTIVITY_DONE_GC and turns off the timer
@@ -1557,7 +1562,7 @@ void releaseAllCapabilities(uint32_t n, Capability *keep_cap, Task *task)
 // behind deadlock_detect argument.
 static void
 scheduleDoGC (Capability **pcap, Task *task USED_IF_THREADS,
-              bool force_major, bool deadlock_detect)
+              bool force_major, bool deadlock_detect, bool force_nonconcurrent)
 {
     Capability *cap = *pcap;
     bool heap_census;
@@ -1850,9 +1855,11 @@ delete_threads_and_gc:
     // emerge they don't immediately re-enter the GC.
     pending_sync = 0;
     signalCondition(&sync_finished_cond);
-    GarbageCollect(collect_gen, heap_census, deadlock_detect, gc_type, cap, idle_cap);
+    GarbageCollect(collect_gen, heap_census, deadlock_detect,
+                   force_nonconcurrent, gc_type, cap, idle_cap);
 #else
-    GarbageCollect(collect_gen, heap_census, deadlock_detect, 0, cap, NULL);
+    GarbageCollect(collect_gen, heap_census, deadlock_detect,
+                   force_nonconcurrent, 0, cap, NULL);
 #endif
 
     // If we're shutting down, don't leave any idle GC work to do.
@@ -2720,7 +2727,7 @@ exitScheduler (bool wait_foreign USED_IF_THREADS)
         nonmovingStop();
         Capability *cap = task->cap;
         waitForCapability(&cap,task);
-        scheduleDoGC(&cap,task,true,false);
+        scheduleDoGC(&cap,task,true,false,false);
         ASSERT(task->incall->tso == NULL);
         releaseCapability(cap);
     }
@@ -2775,7 +2782,7 @@ void markScheduler (evac_fn evac USED_IF_NOT_THREADS,
    -------------------------------------------------------------------------- */
 
 static void
-performGC_(bool force_major)
+performGC_(bool force_major, bool force_nonconcurrent)
 {
     Task *task;
     Capability *cap = NULL;
@@ -2788,7 +2795,7 @@ performGC_(bool force_major)
     // TODO: do we need to traceTask*() here?
 
     waitForCapability(&cap,task);
-    scheduleDoGC(&cap,task,force_major,false);
+    scheduleDoGC(&cap, task, force_major, false, force_nonconcurrent);
     releaseCapability(cap);
     boundTaskExiting(task);
 }
@@ -2796,13 +2803,19 @@ performGC_(bool force_major)
 void
 performGC(void)
 {
-    performGC_(false);
+    performGC_(false, false);
 }
 
 void
 performMajorGC(void)
 {
-    performGC_(true);
+    performGC_(true, false);
+}
+
+void
+performBlockingMajorGC(void)
+{
+    performGC_(true, true);
 }
 
 /* ---------------------------------------------------------------------------


=====================================
rts/sm/GC.c
=====================================
@@ -196,6 +196,7 @@ void
 GarbageCollect (uint32_t collect_gen,
                 const bool do_heap_census,
                 const bool deadlock_detect,
+                const bool force_nonconcurrent,
                 uint32_t gc_type USED_IF_THREADS,
                 Capability *cap,
                 bool idle_cap[])
@@ -779,7 +780,7 @@ GarbageCollect (uint32_t collect_gen,
       // upd_rem_set
       nonmovingAddUpdRemSetBlocks(&gct->cap->upd_rem_set.queue);
 #endif
-      nonmovingCollect(&dead_weak_ptr_list, &resurrected_threads);
+      nonmovingCollect(&dead_weak_ptr_list, &resurrected_threads, force_nonconcurrent);
       ACQUIRE_SM_LOCK;
   }
 


=====================================
rts/sm/GC.h
=====================================
@@ -20,6 +20,7 @@
 void GarbageCollect (uint32_t collect_gen,
                      bool do_heap_census,
                      bool deadlock_detect,
+                     bool force_nonconcurrent,
                      uint32_t gc_type,
                      Capability *cap,
                      bool idle_cap[]);


=====================================
rts/sm/NonMoving.c
=====================================
@@ -900,7 +900,9 @@ static void nonmovingMarkWeakPtrList(MarkQueue *mark_queue, StgWeak *dead_weak_p
     }
 }
 
-void nonmovingCollect(StgWeak **dead_weaks, StgTSO **resurrected_threads)
+void nonmovingCollect(StgWeak **dead_weaks,
+                      StgTSO **resurrected_threads,
+                      bool force_nonmoving)
 {
 #if defined(THREADED_RTS)
     // We can't start a new collection until the old one has finished
@@ -979,7 +981,7 @@ void nonmovingCollect(StgWeak **dead_weaks, StgTSO **resurrected_threads)
     // again for the sync if we let it go, because it'll immediately start doing
     // a major GC, because that's what we do when exiting scheduler (see
     // exitScheduler()).
-    if (sched_state == SCHED_RUNNING) {
+    if (sched_state == SCHED_RUNNING && !force_nonconcurrent) {
         concurrent_coll_running = true;
         nonmoving_write_barrier_enabled = true;
         debugTrace(DEBUG_nonmoving_gc, "Starting concurrent mark thread");


=====================================
rts/sm/NonMoving.h
=====================================
@@ -126,7 +126,8 @@ void nonmovingExit(void);
 //   directly, but in a pause.
 //
 void nonmovingCollect(StgWeak **dead_weaks,
-                       StgTSO **resurrected_threads);
+                      StgTSO **resurrected_threads,
+                      bool force_nonmoving);
 
 void *nonmovingAllocate(Capability *cap, StgWord sz);
 void nonmovingAddCapabilities(uint32_t new_n_caps);



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/da04a8647230fa97e84cfc4b319ce097e2b2d734

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/da04a8647230fa97e84cfc4b319ce097e2b2d734
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20200530/5c2f8d9a/attachment-0001.html>


More information about the ghc-commits mailing list