Free full_prog_argv at exit, closing a memory leak
[ghc-hetmet.git] / rts / RtsFlags.c
index 1204c59..19954f8 100644 (file)
@@ -51,7 +51,7 @@ open_stats_file (
     const char *FILENAME_FMT,
     FILE **file_ret);
 
-static I_ decode(const char *s);
+static StgWord64 decodeSize(const char *flag, nat offset, StgWord64 min, StgWord64 max);
 static void bad_option(const char *s);
 
 /* -----------------------------------------------------------------------------
@@ -70,6 +70,7 @@ void initRtsFlagsDefaults(void)
     RtsFlags.GcFlags.minOldGenSize      = (1024 * 1024)       / BLOCK_SIZE;
     RtsFlags.GcFlags.maxHeapSize       = 0;    /* off by default */
     RtsFlags.GcFlags.heapSizeSuggestion        = 0;    /* none */
+    RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsFalse;
     RtsFlags.GcFlags.pcFreeHeap                = 3;    /* 3% */
     RtsFlags.GcFlags.oldGenFactor       = 2;
     RtsFlags.GcFlags.generations        = 2;
@@ -106,12 +107,11 @@ void initRtsFlagsDefaults(void)
     RtsFlags.DebugFlags.stable         = rtsFalse;
     RtsFlags.DebugFlags.stm             = rtsFalse;
     RtsFlags.DebugFlags.prof           = rtsFalse;
-    RtsFlags.DebugFlags.eventlog        = rtsFalse;
     RtsFlags.DebugFlags.apply          = rtsFalse;
     RtsFlags.DebugFlags.linker         = rtsFalse;
     RtsFlags.DebugFlags.squeeze                = rtsFalse;
     RtsFlags.DebugFlags.hpc            = rtsFalse;
-    RtsFlags.DebugFlags.timestamp      = rtsFalse;
+    RtsFlags.DebugFlags.sparks         = rtsFalse;
 #endif
 
 #if defined(PROFILING)
@@ -135,8 +135,10 @@ void initRtsFlagsDefaults(void)
     RtsFlags.ProfFlags.bioSelector        = NULL;
 #endif
 
-#ifdef EVENTLOG
-    RtsFlags.EventLogFlags.doEventLogging = rtsFalse;
+#ifdef TRACING
+    RtsFlags.TraceFlags.tracing       = TRACE_NONE;
+    RtsFlags.TraceFlags.timestamp     = rtsFalse;
+    RtsFlags.TraceFlags.scheduler     = rtsFalse;
 #endif
 
     RtsFlags.MiscFlags.tickInterval    = 20;  /* In milliseconds */
@@ -151,8 +153,9 @@ void initRtsFlagsDefaults(void)
     RtsFlags.ParFlags.migrate           = rtsTrue;
     RtsFlags.ParFlags.wakeupMigrate     = rtsFalse;
     RtsFlags.ParFlags.parGcEnabled      = 1;
-    RtsFlags.ParFlags.parGcGen          = 1;
-    RtsFlags.ParFlags.parGcLoadBalancing = 1;
+    RtsFlags.ParFlags.parGcGen          = 0;
+    RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsTrue;
+    RtsFlags.ParFlags.parGcLoadBalancingGen = 1;
     RtsFlags.ParFlags.setAffinity       = 0;
 #endif
 
@@ -196,9 +199,11 @@ usage_text[] = {
 "  -m<n>    Minimum % of heap which must be available (default 3%)",
 "  -G<n>    Number of generations (default: 2)",
 "  -T<n>    Number of steps in younger generations (default: 2)",
-"  -c<n>    Auto-enable compaction of the oldest generation when live data is",
-"           at least <n>% of the maximum heap size set with -M (default: 30%)",
-"  -c       Enable compaction for all major collections",
+"  -c<n>    Use in-place compaction instead of copying in the oldest generation",
+"           when live data is at least <n>% of the maximum heap size set with",
+"           -M (default: 30%)",
+"  -c       Use in-place compaction for all oldest generation collections",
+"           (the default is to use copying)",
 "  -w       Use mark-region for the oldest generation (experimental)",
 #if defined(THREADED_RTS)
 "  -I<sec>  Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
@@ -252,9 +257,13 @@ usage_text[] = {
 # endif
 #endif /* PROFILING or PAR */
 
-#ifdef EVENTLOG
+#ifdef TRACING
 "",
-"  -l       Log runtime events (generates binary trace file <program>.eventlog)",
+"  -v       Log events to stderr",
+"  -l       Log events in binary format to the file <program>.eventlog",
+"  -vt      Include time stamps when tracing events to stderr with -v",
+"",
+"  -ls      Log scheduler events",
 "",
 #endif
 
@@ -275,8 +284,6 @@ usage_text[] = {
 "            This sets the resolution for -C and the profile timer -i.",
 "            Default: 0.02 sec.",
 "",
-"  -vt       Time-stamp debug messages",
-"",
 #if defined(DEBUG)
 "  -Ds  DEBUG: scheduler",
 "  -Di  DEBUG: interpreter",
@@ -293,15 +300,20 @@ usage_text[] = {
 "  -Dm  DEBUG: stm",
 "  -Dz  DEBUG: stack squezing",
 "  -Dc  DEBUG: program coverage",
+"  -Dr  DEBUG: sparks",
+"",
+"     NOTE: all -D options also enable -v automatically.  Use -l to create a",
+"     binary event log file instead.",
 "",
 #endif /* DEBUG */
 #if defined(THREADED_RTS) && !defined(NOSMP)
 "  -N<n>     Use <n> processors (default: 1)",
 "  -N        Determine the number of processors to use automatically",
-"  -q1       Use one OS thread for GC (turns off parallel GC)",
-"  -qg<n>    Use parallel GC only for generations >= <n> (default: 1)",
-"  -qb       Disable load-balancing in the parallel GC",
-"  -qa       Use the OS to set thread affinity",
+"  -qg[<n>]  Use parallel GC only for generations >= <n>",
+"            (default: 0, -qg alone turns off parallel GC)",
+"  -qb[<n>]  Use load-balancing in the parallel GC only for generations >= <n>",
+"            (default: 1, -qb alone turns off load-balancing)",
+"  -qa       Use the OS to set thread affinity (experimental)",
 "  -qm       Don't automatically migrate threads between CPUs",
 "  -qw       Migrate a thread to the current CPU when it is woken up",
 #endif
@@ -472,10 +484,10 @@ errorBelch("not built for: -prof"); \
 error = rtsTrue;
 #endif
 
-#ifdef EVENTLOG
-# define EVENTLOG_BUILD_ONLY(x)   x
+#ifdef TRACING
+# define TRACING_BUILD_ONLY(x)   x
 #else
-# define EVENTLOG_BUILD_ONLY(x) \
+# define TRACING_BUILD_ONLY(x) \
 errorBelch("not built for: -par-prof"); \
 error = rtsTrue;
 #endif
@@ -520,12 +532,10 @@ error = rtsTrue;
                   }
                  break;
              case 'A':
-               RtsFlags.GcFlags.minAllocAreaSize
-                 = decode(rts_argv[arg]+2) / BLOCK_SIZE;
-               if (RtsFlags.GcFlags.minAllocAreaSize <= 0) {
-                 bad_option(rts_argv[arg]);
-               }
-               break;
+                  RtsFlags.GcFlags.minAllocAreaSize
+                      = decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_INT_MAX)
+                           / BLOCK_SIZE;
+                  break;
 
 #ifdef USE_PAPI
              case 'a':
@@ -617,9 +627,6 @@ error = rtsTrue;
                      case 'p':
                          RtsFlags.DebugFlags.prof = rtsTrue;
                          break;
-                     case 'e':
-                         RtsFlags.DebugFlags.eventlog = rtsTrue;
-                          break;
                      case 'l':
                          RtsFlags.DebugFlags.linker = rtsTrue;
                          break;
@@ -635,66 +642,62 @@ error = rtsTrue;
                      case 'c':
                          RtsFlags.DebugFlags.hpc = rtsTrue;
                          break;
+                     case 'r':
+                         RtsFlags.DebugFlags.sparks = rtsTrue;
+                         break;
                      default:
                          bad_option( rts_argv[arg] );
                      }
                  }
+                  // -Dx also turns on -v.  Use -l to direct trace
+                  // events to the .eventlog file instead.
+                  RtsFlags.TraceFlags.tracing = TRACE_STDERR;
                  break;
              }
 #endif
 
              case 'K':
-               RtsFlags.GcFlags.maxStkSize = 
-                 decode(rts_argv[arg]+2) / sizeof(W_);
-
-               if (RtsFlags.GcFlags.maxStkSize == 0) 
-                 bad_option( rts_argv[arg] );
-               break;
+                  RtsFlags.GcFlags.maxStkSize =
+                      decodeSize(rts_argv[arg], 2, 1, HS_WORD_MAX) / sizeof(W_);
+                  break;
 
              case 'k':
-               RtsFlags.GcFlags.initialStkSize = 
-                 decode(rts_argv[arg]+2) / sizeof(W_);
-
-               if (RtsFlags.GcFlags.initialStkSize == 0) 
-                 bad_option( rts_argv[arg] );
-               break;
+                  RtsFlags.GcFlags.initialStkSize =
+                      decodeSize(rts_argv[arg], 2, 1, HS_WORD_MAX) / sizeof(W_);
+                  break;
 
              case 'M':
-               RtsFlags.GcFlags.maxHeapSize = 
-                 decode(rts_argv[arg]+2) / BLOCK_SIZE;
-               /* user give size in *bytes* but "maxHeapSize" is in *blocks* */
-
-               if (RtsFlags.GcFlags.maxHeapSize <= 0) {
-                 bad_option(rts_argv[arg]);
-               }
-               break;
+                  RtsFlags.GcFlags.maxHeapSize =
+                      decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX) / BLOCK_SIZE;
+                  /* user give size in *bytes* but "maxHeapSize" is in *blocks* */
+                  break;
 
              case 'm':
-               RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
+                  RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
 
-               if (RtsFlags.GcFlags.pcFreeHeap < 0 || 
-                   RtsFlags.GcFlags.pcFreeHeap > 100)
-                 bad_option( rts_argv[arg] );
-               break;
+                  if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
+                      RtsFlags.GcFlags.pcFreeHeap > 100)
+                      bad_option( rts_argv[arg] );
+                  break;
 
              case 'G':
-               RtsFlags.GcFlags.generations = decode(rts_argv[arg]+2);
-               if (RtsFlags.GcFlags.generations < 1) {
-                 bad_option(rts_argv[arg]);
-               }
-               break;
+                  RtsFlags.GcFlags.generations =
+                      decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
+                  break;
 
-             case 'T':
-               RtsFlags.GcFlags.steps = decode(rts_argv[arg]+2);
-               if (RtsFlags.GcFlags.steps < 1) {
-                 bad_option(rts_argv[arg]);
-               }
+              case 'T':
+                  RtsFlags.GcFlags.steps =
+                      decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
                break;
 
              case 'H':
-               RtsFlags.GcFlags.heapSizeSuggestion = 
-                 decode(rts_argv[arg]+2) / BLOCK_SIZE;
-               break;
+                  if (rts_argv[arg][2] == '\0') {
+                      RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsTrue;
+                  } else {
+                      RtsFlags.GcFlags.heapSizeSuggestion =
+                          (nat)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX) / BLOCK_SIZE);
+                  }
+                  break;
 
 #ifdef RTS_GTK_FRONTPANEL
              case 'f':
@@ -743,12 +746,24 @@ error = rtsTrue;
              /* =========== PROFILING ========================== */
 
               case 'l':
-#ifdef EVENTLOG
-                  RtsFlags.EventLogFlags.doEventLogging = rtsTrue;
+#ifdef TRACING
+                switch(rts_argv[arg][2]) {
+               case '\0':
+                    RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
+                    break;
+                case 's':
+                    RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
+                    RtsFlags.TraceFlags.scheduler = rtsTrue;
+                    break;
+               default:
+                   errorBelch("unknown RTS option: %s",rts_argv[arg]);
+                   error = rtsTrue;
+                   break;
+                }
 #else
-                  errorBelch("not built for: -eventlog");
+                errorBelch("not built for: -eventlog");
 #endif
-                  break;
+                break;
 
              case 'P': /* detailed cost centre profiling (time/alloc) */
              case 'p': /* cost centre profiling (time/alloc) */
@@ -985,21 +1000,25 @@ error = rtsTrue;
                        errorBelch("incomplete RTS option: %s",rts_argv[arg]);
                        error = rtsTrue;
                        break;
-                    case '1':
-                        RtsFlags.ParFlags.parGcEnabled = rtsFalse;
-                        break;
                     case 'g':
-                        if (rts_argv[arg][3] != '\0') {
+                        if (rts_argv[arg][3] == '\0') {
+                            RtsFlags.ParFlags.parGcEnabled = rtsFalse;
+                        } else {
+                            RtsFlags.ParFlags.parGcEnabled = rtsTrue;
                             RtsFlags.ParFlags.parGcGen
                                 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
-                        } else {
-                            errorBelch("bad value for -qg");
-                            error = rtsTrue;
                         }
                         break;
                    case 'b':
-                       RtsFlags.ParFlags.parGcLoadBalancing = rtsFalse;
-                       break;
+                        if (rts_argv[arg][3] == '\0') {
+                            RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsFalse;
+                        }
+                        else {
+                            RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsTrue;
+                            RtsFlags.ParFlags.parGcLoadBalancingGen
+                                = strtol(rts_argv[arg]+3, (char **) NULL, 10);
+                        }
+                        break;
                    case 'a':
                        RtsFlags.ParFlags.setAffinity = rtsTrue;
                        break;
@@ -1049,13 +1068,14 @@ error = rtsTrue;
 
              case 'v':
                 switch(rts_argv[arg][2]) {
-               case '\0':
-                   errorBelch("incomplete RTS option: %s",rts_argv[arg]);
-                   error = rtsTrue;
-                   break;
+#ifdef TRACING
+                case '\0':
+                    RtsFlags.TraceFlags.tracing = TRACE_STDERR;
+                    break;
                case 't':
-                   RtsFlags.DebugFlags.timestamp = rtsTrue;
+                   RtsFlags.TraceFlags.timestamp = rtsTrue;
                    break;
+#endif
                case 's':
                case 'g':
                     // ignored for backwards-compat
@@ -1247,28 +1267,44 @@ open_stats_file (
 
 
 
-static I_
-decode(const char *s)
+static StgWord64
+decodeSize(const char *flag, nat offset, StgWord64 min, StgWord64 max)
 {
-    I_ c;
+    char c;
+    const char *s;
     StgDouble m;
+    StgWord64 val;
+
+    s = flag + offset;
 
     if (!*s)
-       return 0;
+    {
+        m = 0;
+    }
+    else
+    {
+        m = atof(s);
+        c = s[strlen(s)-1];
+
+        if (c == 'g' || c == 'G') 
+            m *= 1024*1024*1024;
+        else if (c == 'm' || c == 'M')
+            m *= 1024*1024;
+        else if (c == 'k' || c == 'K')
+            m *= 1024;
+        else if (c == 'w' || c == 'W')
+            m *= sizeof(W_);
+    }
 
-    m = atof(s);
-    c = s[strlen(s)-1];
+    val = (StgWord64)m;
 
-    if (c == 'g' || c == 'G')
-       m *= 1000*1000*1000;    /* UNchecked! */
-    else if (c == 'm' || c == 'M')
-       m *= 1000*1000;                 /* We do not use powers of 2 (1024) */
-    else if (c == 'k' || c == 'K')     /* to avoid possible bad effects on */
-       m *= 1000;                      /* a direct-mapped cache.           */ 
-    else if (c == 'w' || c == 'W')
-       m *= sizeof(W_);
+    if (m < 0 || val < min || val > max) {
+        errorBelch("error in RTS option %s: size outside allowed range (%" FMT_Word64 " - %" FMT_Word64 ")", 
+                   flag, min, max);
+        stg_exit(EXIT_FAILURE);
+    }
 
-    return (I_)m;
+    return val;
 }
 
 static void GNU_ATTRIBUTE(__noreturn__)
@@ -1353,3 +1389,18 @@ setFullProgArgv(int argc, char *argv[])
     full_prog_argv[argc] = NULL;
 }
 
+void
+freeFullProgArgv (void)
+{
+    int i;
+
+    if (full_prog_argv != NULL) {
+        for (i = 0; i < full_prog_argc; i++) {
+            stgFree(full_prog_argv[i]);
+        }
+        stgFree(full_prog_argv);
+    }
+
+    full_prog_argc = 0;
+    full_prog_argv = NULL;
+}