Repository : ssh://darcs.haskell.org//srv/darcs/ghc

On branch  : ghc-7.6

http://hackage.haskell.org/trac/ghc/changeset/f9077d98b9e58b0eca518c8ae370b0f5c4df8800

>---------------------------------------------------------------

commit f9077d98b9e58b0eca518c8ae370b0f5c4df8800
Author: Simon Marlow <marlo...@gmail.com>
Date:   Fri Sep 21 15:49:22 2012 +0100

    Another overhaul of the recent_activity / idle GC handling (#5991)
    
    Improvements:
    
     - we now turn off the timer signal in the non-threaded RTS after
       idleGCDelay.  This should make the xmonad users on #5991 happy.
    
     - we now turn off the timer signal after idleGCDelay even if the
       idle GC is disabled with +RTS -I0.
    
     - we now do *not* turn off the timer when profiling.
    
     - more comments to explain the meaning of the various ACTIVITY_*
       values
    
    MERGED from commit 0b79d5cd4687dacf7efd430df7fba9d9a5a5ce32

>---------------------------------------------------------------

 includes/rts/Flags.h |    1 +
 rts/RtsFlags.c       |   14 ++++++++++++--
 rts/Schedule.c       |   16 ++++++++++++----
 rts/Schedule.h       |   28 +++++++++++++++++++++++-----
 rts/Timer.c          |   27 ++++++++++++++-------------
 5 files changed, 62 insertions(+), 24 deletions(-)

diff --git a/includes/rts/Flags.h b/includes/rts/Flags.h
index da71a4b..9ca7fb9 100644
--- a/includes/rts/Flags.h
+++ b/includes/rts/Flags.h
@@ -53,6 +53,7 @@ struct GC_FLAGS {
     rtsBool frontpanel;
 
     Time    idleGCDelayTime;    /* units: TIME_RESOLUTION */
+    rtsBool doIdleGC;
 
     StgWord heapBase;           /* address to ask the OS for memory */
 };
diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c
index cfe5c1b..bb260c2 100644
--- a/rts/RtsFlags.c
+++ b/rts/RtsFlags.c
@@ -115,6 +115,11 @@ void initRtsFlagsDefaults(void)
     RtsFlags.GcFlags.frontpanel         = rtsFalse;
 #endif
     RtsFlags.GcFlags.idleGCDelayTime    = USToTime(300000); // 300ms
+#ifdef THREADED_RTS
+    RtsFlags.GcFlags.doIdleGC           = rtsTrue;
+#else
+    RtsFlags.GcFlags.doIdleGC           = rtsFalse;
+#endif
 
 #if osf3_HOST_OS
 /* ToDo: Perhaps by adjusting this value we can make linking without
@@ -915,8 +920,13 @@ error = rtsTrue;
                if (rts_argv[arg][2] == '\0') {
                  /* use default */
                } else {
-                    RtsFlags.GcFlags.idleGCDelayTime =
-                        fsecondsToTime(atof(rts_argv[arg]+2));
+                    Time t = fsecondsToTime(atof(rts_argv[arg]+2));
+                    if (t == 0) {
+                        RtsFlags.GcFlags.doIdleGC = rtsFalse;
+                    } else {
+                        RtsFlags.GcFlags.doIdleGC = rtsTrue;
+                        RtsFlags.GcFlags.idleGCDelayTime = t;
+                    }
                }
                break;
 
diff --git a/rts/Schedule.c b/rts/Schedule.c
index a3e11bb..0ab6d69 100644
--- a/rts/Schedule.c
+++ b/rts/Schedule.c
@@ -452,23 +452,29 @@ run_thread:
     dirty_TSO(cap,t);
     dirty_STACK(cap,t->stackobj);
 
-#if defined(THREADED_RTS)
-    if (recent_activity == ACTIVITY_DONE_GC) {
+    switch (recent_activity)
+    {
+    case ACTIVITY_DONE_GC: {
         // ACTIVITY_DONE_GC means we turned off the timer signal to
         // conserve power (see #1623).  Re-enable it here.
         nat prev;
         prev = xchg((P_)&recent_activity, ACTIVITY_YES);
+#ifndef PROFILING
         if (prev == ACTIVITY_DONE_GC) {
             startTimer();
         }
-    } else if (recent_activity != ACTIVITY_INACTIVE) {
+#endif
+        break;
+    }
+    case ACTIVITY_INACTIVE:
         // If we reached ACTIVITY_INACTIVE, then don't reset it until
         // we've done the GC.  The thread running here might just be
         // the IO manager thread that handle_tick() woke up via
         // wakeUpRts().
+        break;
+    default:
         recent_activity = ACTIVITY_YES;
     }
-#endif
 
     traceEventRunThread(cap, t);
 
@@ -1661,7 +1667,9 @@ delete_threads_and_gc:
             // fact that we've done a GC and turn off the timer signal;
             // it will get re-enabled if we run any threads after the GC.
             recent_activity = ACTIVITY_DONE_GC;
+#ifndef PROFILING
             stopTimer();
+#endif
             break;
         }
         // fall through...
diff --git a/rts/Schedule.h b/rts/Schedule.h
index 4eb3830..a44949e 100644
--- a/rts/Schedule.h
+++ b/rts/Schedule.h
@@ -61,12 +61,30 @@ void scheduleWorker (Capability *cap, Task *task);
 extern volatile StgWord sched_state;
 
 /* 
- * flag that tracks whether we have done any execution in this time slice.
+ * flag that tracks whether we have done any execution in this time
+ * slice, and controls the disabling of the interval timer.
+ *
+ * The timer interrupt transitions ACTIVITY_YES into
+ * ACTIVITY_MAYBE_NO, waits for RtsFlags.GcFlags.idleGCDelayTime,
+ * and then:
+ *   - if idle GC is no, set ACTIVITY_INACTIVE and wakeUpRts()
+ *   - if idle GC is off, set ACTIVITY_DONE_GC and stopTimer()
+ *
+ * If the scheduler finds ACTIVITY_INACTIVE, then it sets
+ * ACTIVITY_DONE_GC, performs the GC and calls stopTimer().
+ *
+ * If the scheduler finds ACTIVITY_DONE_GC and it has a thread to run,
+ * it enables the timer again with startTimer().
  */
-#define ACTIVITY_YES      0 /* there has been activity in the current slice */
-#define ACTIVITY_MAYBE_NO 1 /* no activity in the current slice */
-#define ACTIVITY_INACTIVE 2 /* a complete slice has passed with no activity */
-#define ACTIVITY_DONE_GC  3 /* like 2, but we've done a GC too */
+#define ACTIVITY_YES      0
+  // the RTS is active
+#define ACTIVITY_MAYBE_NO 1
+  // no activity since the last timer signal
+#define ACTIVITY_INACTIVE 2
+  // RtsFlags.GcFlags.idleGCDelayTime has passed with no activity
+#define ACTIVITY_DONE_GC  3
+  // like ACTIVITY_INACTIVE, but we've done a GC too (if idle GC is
+  // enabled) and the interval timer is now turned off.
 
 /* Recent activity flag.
  * Locks required  : Transition from MAYBE_NO to INACTIVE
diff --git a/rts/Timer.c b/rts/Timer.c
index 3f9bc8a..aa4b8d8 100644
--- a/rts/Timer.c
+++ b/rts/Timer.c
@@ -28,10 +28,8 @@
 /* ticks left before next pre-emptive context switch */
 static int ticks_to_ctxt_switch = 0;
 
-#if defined(THREADED_RTS)
 /* idle ticks left before we perform a GC */
 static int ticks_to_gc = 0;
-#endif
 
 /*
  * Function: handle_tick()
@@ -52,7 +50,6 @@ handle_tick(int unused STG_UNUSED)
       }
   }
 
-#if defined(THREADED_RTS)
   /* 
    * If we've been inactive for idleGCDelayTime (set by +RTS
    * -I), tell the scheduler to wake up and do a GC, to check
@@ -66,24 +63,28 @@ handle_tick(int unused STG_UNUSED)
       break;
   case ACTIVITY_MAYBE_NO:
       if (ticks_to_gc == 0) {
-          /* 0 ==> no idle GC */
-          recent_activity = ACTIVITY_DONE_GC;
-          // disable timer signals (see #1623)
-          stopTimer();
-      } else {
-          ticks_to_gc--;
-          if (ticks_to_gc == 0) {
-              ticks_to_gc = RtsFlags.GcFlags.idleGCDelayTime /
-                  RtsFlags.MiscFlags.tickInterval;
+          if (RtsFlags.GcFlags.doIdleGC) {
               recent_activity = ACTIVITY_INACTIVE;
+#ifdef THREADED_RTS
               wakeUpRts();
+              // The scheduler will call stopTimer() when it has done
+              // the GC.
+#endif
+          } else {
+              recent_activity = ACTIVITY_DONE_GC;
+              // disable timer signals (see #1623, #5991)
+              // but only if we're not profiling
+#ifndef PROFILING
+              stopTimer();
+#endif
           }
+      } else {
+          ticks_to_gc--;
       }
       break;
   default:
       break;
   }
-#endif
 }
 
 // This global counter is used to allow multiple threads to stop the



_______________________________________________
Cvs-ghc mailing list
Cvs-ghc@haskell.org
http://www.haskell.org/mailman/listinfo/cvs-ghc

Reply via email to