From: simonmar Date: Mon, 16 May 2005 14:27:08 +0000 (+0000) Subject: [project @ 2005-05-16 14:27:07 by simonmar] X-Git-Tag: Initial_conversion_from_CVS_complete~543 X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=33a84b8c79f0ccd2400996a0e571b0659d4c16ed;p=ghc-hetmet.git [project @ 2005-05-16 14:27:07 by simonmar] Allow the amount of idle time which must pass before we force a major GC to be configured at runtime with the +RTS -I option. The idle GC only happens in the threaded RTS, and it is useful because it can make finalizers run more promptly, and also detect cases of deadlock. Without the idle GC, Haskell computation must be taking place in order for finalizers to run or deadlock to be detected, and the only way some Haskell computation can take place is usually by in-calls. +RTS -I0 turns off the idle GC, the default is +RTS -I0.3. We might need to add more tuning if it turns out that the idle GC is problematic, for example we don't check how long the GC actually took, and we should probably back off if major GCs are taking too long and adversely affecting interactive responsiveness. --- diff --git a/ghc/includes/RtsFlags.h b/ghc/includes/RtsFlags.h index d0ab562..a4c6d9b 100644 --- a/ghc/includes/RtsFlags.h +++ b/ghc/includes/RtsFlags.h @@ -41,6 +41,8 @@ struct GC_FLAGS { rtsBool ringBell; rtsBool frontpanel; + + int idleGCDelayTicks; /* in milliseconds */ }; struct DEBUG_FLAGS { diff --git a/ghc/rts/RtsFlags.c b/ghc/rts/RtsFlags.c index 3b88496..b0accf9 100644 --- a/ghc/rts/RtsFlags.c +++ b/ghc/rts/RtsFlags.c @@ -173,6 +173,7 @@ void initRtsFlagsDefaults(void) #ifdef RTS_GTK_FRONTPANEL RtsFlags.GcFlags.frontpanel = rtsFalse; #endif + RtsFlags.GcFlags.idleGCDelayTicks = 300 / TICK_MILLISECS; /* ticks */ #ifdef DEBUG RtsFlags.DebugFlags.scheduler = rtsFalse; @@ -346,6 +347,9 @@ usage_text[] = { " -c Auto-enable compaction of the oldest generation when live data is", " at least % of the maximum heap size set with -M (default: 30%)", " -c Enable compaction for all major collections", +#if defined(RTS_SUPPORTS_THREADS) +" -I Perform full GC after idle time (default: 0.3, 0 == off)", +#endif "", " -t One-line GC statistics (default file: .stat)", " -s Summary GC statistics (with -Sstderr going to stderr)", @@ -793,6 +797,23 @@ error = rtsTrue; break; #endif + case 'I': /* idle GC delay */ + if (rts_argv[arg][2] == '\0') { + /* use default */ + } else { + I_ cst; /* tmp */ + + /* Convert to ticks */ + cst = (I_) ((atof(rts_argv[arg]+2) * 1000)); + if (cst > 0 && cst < TICK_MILLISECS) { + cst = TICK_MILLISECS; + } else { + cst = cst / TICK_MILLISECS; + } + RtsFlags.GcFlags.idleGCDelayTicks = cst; + } + break; + case 'S': RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS; goto stats; diff --git a/ghc/rts/Timer.c b/ghc/rts/Timer.c index da4c852..99a76c3 100644 --- a/ghc/rts/Timer.c +++ b/ghc/rts/Timer.c @@ -30,6 +30,9 @@ /* 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; + /* * Function: handle_tick() * @@ -51,22 +54,28 @@ handle_tick(int unused STG_UNUSED) #if defined(RTS_SUPPORTS_THREADS) /* - * If we've been inactive for a whole time slice, tell the - * scheduler to wake up and do a GC, to check for threads - * that are deadlocked. + * If we've been inactive for idleGCDelayTicks (set by +RTS + * -I), tell the scheduler to wake up and do a GC, to check + * for threads that are deadlocked. */ switch (recent_activity) { case ACTIVITY_YES: recent_activity = ACTIVITY_MAYBE_NO; + ticks_to_gc = RtsFlags.GcFlags.idleGCDelayTicks; break; case ACTIVITY_MAYBE_NO: - recent_activity = ACTIVITY_INACTIVE; - blackholes_need_checking = rtsTrue; - /* hack: re-use the blackholes_need_checking flag */ - threadRunnable(); - /* ToDo: this threadRunnable only works if there's - * another thread (not this one) waiting to be woken up - */ + if (ticks_to_gc == 0) break; /* 0 ==> no idle GC */ + ticks_to_gc--; + if (ticks_to_gc == 0) { + ticks_to_gc = RtsFlags.GcFlags.idleGCDelayTicks; + recent_activity = ACTIVITY_INACTIVE; + blackholes_need_checking = rtsTrue; + /* hack: re-use the blackholes_need_checking flag */ + threadRunnable(); + /* ToDo: this threadRunnable only works if there's + * another thread (not this one) waiting to be woken up + */ + } break; default: break;