[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