diff options
-rw-r--r-- | docs/users_guide/runtime_control.rst | 20 | ||||
-rw-r--r-- | includes/rts/Flags.h | 1 | ||||
-rw-r--r-- | rts/RtsFlags.c | 41 | ||||
-rw-r--r-- | rts/Timer.c | 21 |
4 files changed, 63 insertions, 20 deletions
diff --git a/docs/users_guide/runtime_control.rst b/docs/users_guide/runtime_control.rst index 738d981a18..0b9cdfbfbc 100644 --- a/docs/users_guide/runtime_control.rst +++ b/docs/users_guide/runtime_control.rst @@ -653,6 +653,26 @@ performance. This is an experimental feature, please let us know if it causes problems and/or could benefit from further tuning. +.. rts-flag:: -Iw ⟨seconds⟩ + + :default: 0 seconds + + .. index:: + single: idle GC + + By default, if idle GC is enabled in the threaded runtime, a major + GC will be performed every time the process goes idle for a + sufficiently long duration (see :rts-flag:`-I ⟨seconds⟩`). For + large server processes accepting regular but infrequent requests + (e.g., once per second), an expensive, major GC may run after + every request. As an alternative to shutting off idle GC entirely + (with ``-I0``), a minimum wait time between idle GCs can be + specified with this flag. For example, ``-Iw60`` will ensure that + an idle GC runs at most once per minute. + + This is an experimental feature, please let us know if it causes + problems and/or could benefit from further tuning. + .. rts-flag:: -ki ⟨size⟩ :default: 1k diff --git a/includes/rts/Flags.h b/includes/rts/Flags.h index 4af19aa953..d0c41a1576 100644 --- a/includes/rts/Flags.h +++ b/includes/rts/Flags.h @@ -66,6 +66,7 @@ typedef struct _GC_FLAGS { bool ringBell; Time idleGCDelayTime; /* units: TIME_RESOLUTION */ + Time interIdleGCWait; /* units: TIME_RESOLUTION */ bool doIdleGC; Time longGCSync; /* units: TIME_RESOLUTION */ diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c index 2c5f69a76f..4d40810bc6 100644 --- a/rts/RtsFlags.c +++ b/rts/RtsFlags.c @@ -164,6 +164,7 @@ void initRtsFlagsDefaults(void) RtsFlags.GcFlags.compactThreshold = 30.0; RtsFlags.GcFlags.sweep = false; RtsFlags.GcFlags.idleGCDelayTime = USToTime(300000); // 300ms + RtsFlags.GcFlags.interIdleGCWait = 0; #if defined(THREADED_RTS) RtsFlags.GcFlags.doIdleGC = true; #else @@ -1179,19 +1180,33 @@ error = true; break; case 'I': /* idle GC delay */ - OPTION_UNSAFE; - if (rts_argv[arg][2] == '\0') { - /* use default */ - } else { - Time t = fsecondsToTime(atof(rts_argv[arg]+2)); - if (t == 0) { - RtsFlags.GcFlags.doIdleGC = false; - } else { - RtsFlags.GcFlags.doIdleGC = true; - RtsFlags.GcFlags.idleGCDelayTime = t; - } - } - break; + OPTION_UNSAFE; + switch (rts_argv[arg][2]) { + /* minimum inter-idle GC wait time */ + case 'w': + if (rts_argv[arg][3] == '\0') { + /* use default */ + } else { + RtsFlags.GcFlags.interIdleGCWait = fsecondsToTime(atof(rts_argv[arg]+3)); + } + break; + /* idle delay before GC */ + case '\0': + /* use default */ + break; + default: + { + Time t = fsecondsToTime(atof(rts_argv[arg]+2)); + if (t == 0) { + RtsFlags.GcFlags.doIdleGC = false; + } else { + RtsFlags.GcFlags.doIdleGC = true; + RtsFlags.GcFlags.idleGCDelayTime = t; + } + } + break; + } + break; case 'T': OPTION_SAFE; diff --git a/rts/Timer.c b/rts/Timer.c index 8e2fb4a835..4fafbe09e8 100644 --- a/rts/Timer.c +++ b/rts/Timer.c @@ -28,8 +28,11 @@ /* ticks left before next pre-emptive context switch */ static int ticks_to_ctxt_switch = 0; -/* idle ticks left before we perform a GC */ -static int ticks_to_gc = 0; +/* idle ticks left before GC allowed */ +static int idle_ticks_to_gc = 0; + +/* inter-idle GC ticks left before GC allowed */ +static int inter_gc_ticks_to_gc = 0; /* * Function: handle_tick() @@ -53,18 +56,21 @@ handle_tick(int unused STG_UNUSED) /* * If we've been inactive for idleGCDelayTime (set by +RTS * -I), tell the scheduler to wake up and do a GC, to check - * for threads that are deadlocked. + * for threads that are deadlocked. However, ensure we wait + * at least interIdleGCWait (+RTS -Iw) between idle GCs. */ switch (recent_activity) { case ACTIVITY_YES: recent_activity = ACTIVITY_MAYBE_NO; - ticks_to_gc = RtsFlags.GcFlags.idleGCDelayTime / - RtsFlags.MiscFlags.tickInterval; + idle_ticks_to_gc = RtsFlags.GcFlags.idleGCDelayTime / + RtsFlags.MiscFlags.tickInterval; break; case ACTIVITY_MAYBE_NO: - if (ticks_to_gc == 0) { + if (idle_ticks_to_gc == 0 && inter_gc_ticks_to_gc == 0) { if (RtsFlags.GcFlags.doIdleGC) { recent_activity = ACTIVITY_INACTIVE; + inter_gc_ticks_to_gc = RtsFlags.GcFlags.interIdleGCWait / + RtsFlags.MiscFlags.tickInterval; #if defined(THREADED_RTS) wakeUpRts(); // The scheduler will call stopTimer() when it has done @@ -86,7 +92,8 @@ handle_tick(int unused STG_UNUSED) #endif } } else { - ticks_to_gc--; + if (idle_ticks_to_gc) idle_ticks_to_gc--; + if (inter_gc_ticks_to_gc) inter_gc_ticks_to_gc--; } break; default: |