diff options
Diffstat (limited to 'rts')
-rw-r--r-- | rts/RtsFlags.c | 15 | ||||
-rw-r--r-- | rts/hooks/Hooks.h | 2 | ||||
-rw-r--r-- | rts/hooks/LongGCSync.c | 41 | ||||
-rw-r--r-- | rts/sm/GC.c | 22 | ||||
-rw-r--r-- | rts/sm/GCThread.h | 6 |
5 files changed, 80 insertions, 6 deletions
diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c index c0571368cd..ecb9228234 100644 --- a/rts/RtsFlags.c +++ b/rts/RtsFlags.c @@ -69,7 +69,9 @@ const RtsConfig defaultRtsConfig = { .stackOverflowHook = StackOverflowHook, .outOfHeapHook = OutOfHeapHook, .mallocFailHook = MallocFailHook, - .gcDoneHook = NULL + .gcDoneHook = NULL, + .longGCSync = LongGCSync, + .longGCSyncEnd = LongGCSyncEnd }; /* @@ -165,6 +167,7 @@ void initRtsFlagsDefaults(void) RtsFlags.GcFlags.numa = false; RtsFlags.GcFlags.numaMask = 1; RtsFlags.GcFlags.ringBell = false; + RtsFlags.GcFlags.longGCSync = 0; /* detection turned off */ RtsFlags.DebugFlags.scheduler = false; RtsFlags.DebugFlags.interpreter = false; @@ -937,6 +940,16 @@ error = true; } } #endif + else if (!strncmp("long-gc-sync=", &rts_argv[arg][2], 13)) { + OPTION_SAFE; + if (rts_argv[arg][2] == '\0') { + /* use default */ + } else { + RtsFlags.GcFlags.longGCSync = + fsecondsToTime(atof(rts_argv[arg]+16)); + } + break; + } else { OPTION_SAFE; errorBelch("unknown RTS option: %s",rts_argv[arg]); diff --git a/rts/hooks/Hooks.h b/rts/hooks/Hooks.h index 760e1daefc..24500f19e7 100644 --- a/rts/hooks/Hooks.h +++ b/rts/hooks/Hooks.h @@ -22,5 +22,7 @@ extern void StackOverflowHook (W_ stack_size); extern void OutOfHeapHook (W_ request_size, W_ heap_size); extern void MallocFailHook (W_ request_size /* in bytes */, const char *msg); extern void FlagDefaultsHook (void); +extern void LongGCSync (uint32_t capno, Time t); +extern void LongGCSyncEnd (Time t); #include "EndPrivate.h" diff --git a/rts/hooks/LongGCSync.c b/rts/hooks/LongGCSync.c new file mode 100644 index 0000000000..351406df98 --- /dev/null +++ b/rts/hooks/LongGCSync.c @@ -0,0 +1,41 @@ +/* ----------------------------------------------------------------------------- + * + * User-overridable RTS hooks. + * + * ---------------------------------------------------------------------------*/ + +#include "PosixSource.h" +#include "Rts.h" +#include "sm/GC.h" +#include "sm/GCThread.h" +#include "Hooks.h" + +/* + * Called when --long-gc-sync=<time> has expired during a GC sync. The idea is + * that you can set a breakpoint on this function in gdb and try to determine + * which thread was holding up the GC sync. + */ +void LongGCSync (uint32_t me USED_IF_THREADS, Time t STG_UNUSED) +{ +#if defined(THREADED_RTS) + { + uint32_t i; + for (i=0; i < n_capabilities; i++) { + if (i != me && gc_threads[i]->wakeup != GC_THREAD_STANDING_BY) { + debugBelch("Warning: slow GC sync: still waiting for cap %d\n", + i); + } + } + } +#endif +} + +/* + * Called at the end of a GC sync which was longer than --long-gc-sync=<time>. + * The idea is that you can use this function to log stats about the length of + * GC syncs. + */ +void LongGCSyncEnd (Time t) +{ + debugBelch("Warning: waited %" FMT_Word64 "us for GC sync\n", TimeToUS(t)); +} diff --git a/rts/sm/GC.c b/rts/sm/GC.c index aa804a8b76..4dbc5e0aa6 100644 --- a/rts/sm/GC.c +++ b/rts/sm/GC.c @@ -48,6 +48,7 @@ #include "Stable.h" #include "CheckUnload.h" #include "CNF.h" +#include "RtsFlags.h" #include <string.h> // for memset() #include <unistd.h> @@ -825,11 +826,6 @@ static void heapOverflow(void) Initialise the gc_thread structures. -------------------------------------------------------------------------- */ -#define GC_THREAD_INACTIVE 0 -#define GC_THREAD_STANDING_BY 1 -#define GC_THREAD_RUNNING 2 -#define GC_THREAD_WAITING_TO_CONTINUE 3 - static void new_gc_thread (uint32_t n, gc_thread *t) { @@ -1132,6 +1128,9 @@ waitForGcThreads (Capability *cap USED_IF_THREADS, bool idle_cap[]) const uint32_t me = cap->no; uint32_t i, j; bool retry = true; + Time t0, t1, t2; + + t0 = t1 = t2 = getProcessElapsedTime(); while(retry) { for (i=0; i < n_threads; i++) { @@ -1153,6 +1152,19 @@ waitForGcThreads (Capability *cap USED_IF_THREADS, bool idle_cap[]) if (!retry) break; yieldThread(); } + + t2 = getProcessElapsedTime(); + if (RtsFlags.GcFlags.longGCSync != 0 && + t2 - t1 > RtsFlags.GcFlags.longGCSync) { + /* call this every longGCSync of delay */ + rtsConfig.longGCSync(cap->no, t2 - t0); + t1 = t2; + } + } + + if (RtsFlags.GcFlags.longGCSync != 0 && + t2 - t0 > RtsFlags.GcFlags.longGCSync) { + rtsConfig.longGCSyncEnd(t2 - t0); } } diff --git a/rts/sm/GCThread.h b/rts/sm/GCThread.h index bb206db64c..e865dabe5d 100644 --- a/rts/sm/GCThread.h +++ b/rts/sm/GCThread.h @@ -116,6 +116,12 @@ typedef struct gen_workspace_ { of the GC threads ------------------------------------------------------------------------- */ +/* values for the wakeup field */ +#define GC_THREAD_INACTIVE 0 +#define GC_THREAD_STANDING_BY 1 +#define GC_THREAD_RUNNING 2 +#define GC_THREAD_WAITING_TO_CONTINUE 3 + typedef struct gc_thread_ { Capability *cap; |