#include "PosixSource.h"
#include "Rts.h"
+#include "RtsOpts.h"
#include "RtsUtils.h"
#include "Profiling.h"
+#include "RtsFlags.h"
#ifdef HAVE_CTYPE_H
#include <ctype.h>
Static function decls
-------------------------------------------------------------------------- */
-static int /* return NULL on error */
-open_stats_file (
- I_ arg,
- int argc, char *argv[],
- int rts_argc, char *rts_argv[],
- const char *FILENAME_FMT,
- FILE **file_ret);
+static void procRtsOpts (int rts_argc0, RtsOptsEnabledEnum enabled);
-static I_ decode(const char *s);
-static void bad_option(const char *s);
+static void normaliseRtsOpts (void);
+
+static void initStatsFile (FILE *f);
+
+static int openStatsFile (char *filename, const char *FILENAME_FMT,
+ FILE **file_ret);
+
+static StgWord64 decodeSize (const char *flag, nat offset,
+ StgWord64 min, StgWord64 max);
+
+static void bad_option (const char *s);
+
+#ifdef TRACING
+static void read_trace_flags(char *arg);
+#endif
+
+static void errorUsage (void) GNU_ATTRIBUTE(__noreturn__);
/* -----------------------------------------------------------------------------
* Command-line option parsing routines.
RtsFlags.GcFlags.maxStkSize = (8 * 1024 * 1024) / sizeof(W_);
RtsFlags.GcFlags.initialStkSize = 1024 / sizeof(W_);
+ RtsFlags.GcFlags.stkChunkSize = (32 * 1024) / sizeof(W_);
+ RtsFlags.GcFlags.stkChunkBufferSize = (1 * 1024) / sizeof(W_);
RtsFlags.GcFlags.minAllocAreaSize = (512 * 1024) / BLOCK_SIZE;
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;
- RtsFlags.GcFlags.steps = 2;
RtsFlags.GcFlags.squeezeUpdFrames = rtsTrue;
RtsFlags.GcFlags.compact = rtsFalse;
RtsFlags.GcFlags.compactThreshold = 30.0;
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)
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 */
#ifdef THREADED_RTS
RtsFlags.ParFlags.nNodes = 1;
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
" --info Print information about the RTS used by this program",
"",
" -K<size> Sets the maximum stack size (default 8M) Egs: -K32k -K512k",
-" -k<size> Sets the initial thread stack size (default 1k) Egs: -k4k -k2m",
+" -ki<size> Sets the initial thread stack size (default 1k) Egs: -ki4k -ki2m",
+" -kc<size> Sets the stack chunk size (default 32k)",
+" -kb<size> Sets the stack chunk buffer size (default 1k)",
"",
" -A<size> Sets the minimum allocation area size (default 512k) Egs: -A1m -A10k",
" -M<size> Sets the maximum heap size (default unlimited) Egs: -M256k -M1G",
" -H<size> Sets the minimum heap size (default 0M) Egs: -H24m -H1G",
" -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)",
" -xt Include threads (TSOs) in a heap profile",
"",
" -xc Show current cost centre stack on raising an exception",
-"",
# endif
#endif /* PROFILING or PAR */
-#ifdef EVENTLOG
-"",
-" -l Log runtime events (generates binary trace file <program>.eventlog)",
+#ifdef TRACING
"",
+" -l[flags] Log events in binary format to the file <program>.eventlog",
+# ifdef DEBUG
+" -v[flags] Log events to stderr",
+# endif
+" where [flags] can contain:",
+" s scheduler events",
+# ifdef DEBUG
+" t add time stamps (only useful with -v)",
+# endif
#endif
#if !defined(PROFILING)
" 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",
" -Da DEBUG: apply",
" -Dl DEBUG: linker",
" -Dm DEBUG: stm",
-" -Dz DEBUG: stack squezing",
+" -Dz DEBUG: stack squeezing",
" -Dc DEBUG: program coverage",
+" -Dr DEBUG: sparks",
+"",
+" NOTE: DEBUG events are sent to stderr by default; add -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
" --install-signal-handlers=<yes|no>",
" Install signal handlers (default: yes)",
#if defined(THREADED_RTS)
-" -e<size> Size of spark pools (default 100)",
-#endif
-#if defined(THREADED_RTS)
" -e<n> Maximum number of outstanding local sparks (default: 4096)",
#endif
#if defined(x86_64_HOST_ARCH)
" b - branch mispredictions",
" s - stalled cycles",
" e - cache miss and branch misprediction events",
+" +PAPI_EVENT - collect papi preset event PAPI_EVENT",
+" #NATIVE_EVENT - collect native event NATIVE_EVENT (in hex)",
#endif
"",
"RTS options may also be specified using the GHCRTS environment variable.",
return(strcmp(a, b) == 0);
}
-static void
-splitRtsFlags(char *s, int *rts_argc, char *rts_argv[])
+static void splitRtsFlags(char *s)
{
char *c1, *c2;
if (c1 == c2) { break; }
- if (*rts_argc < MAX_RTS_ARGS-1) {
+ if (rts_argc < MAX_RTS_ARGS-1) {
s = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
strncpy(s, c1, c2-c1);
s[c2-c1] = '\0';
- rts_argv[(*rts_argc)++] = s;
+ rts_argv[rts_argc++] = s;
} else {
barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
}
} while (*c1 != '\0');
}
-void
-setupRtsFlags(int *argc, char *argv[], int *rts_argc, char *rts_argv[])
+/* -----------------------------------------------------------------------------
+ Parse the command line arguments, collecting options for the RTS.
+
+ On return:
+ - argv[] is *modified*, any RTS options have been stripped out
+ - *argc contains the new count of arguments in argv[]
+
+ - rts_argv[] (global) contains the collected RTS args
+ - rts_argc (global) contains the count of args in rts_argv
+
+ - prog_argv[] (global) contains the non-RTS args (== argv)
+ - prog_argc (global) contains the count of args in prog_argv
+
+ - prog_name (global) contains the basename of argv[0]
+
+ -------------------------------------------------------------------------- */
+
+void setupRtsFlags (int *argc, char *argv[])
{
- rtsBool error = rtsFalse;
- I_ mode;
- I_ arg, total_arg;
+ nat mode;
+ nat total_arg;
+ nat arg, rts_argc0;
setProgName (argv);
total_arg = *argc;
arg = 1;
*argc = 1;
- *rts_argc = 0;
+ rts_argc = 0;
+
+ rts_argc0 = rts_argc;
// process arguments from the ghc_rts_opts global variable first.
// (arguments from the GHCRTS environment variable and the command
// line override these).
{
if (ghc_rts_opts != NULL) {
- splitRtsFlags(ghc_rts_opts, rts_argc, rts_argv);
- }
+ splitRtsFlags(ghc_rts_opts);
+ // opts from ghc_rts_opts are always enabled:
+ procRtsOpts(rts_argc0, RtsOptsAll);
+ rts_argc0 = rts_argc;
+ }
}
// process arguments from the GHCRTS environment variable next
char *ghc_rts = getenv("GHCRTS");
if (ghc_rts != NULL) {
- splitRtsFlags(ghc_rts, rts_argc, rts_argv);
- }
+ if (rtsOptsEnabled == RtsOptsNone) {
+ errorBelch("Warning: Ignoring GHCRTS variable as RTS options are disabled.\n Link with -rtsopts to enable them.");
+ // We don't actually exit, just warn
+ } else {
+ splitRtsFlags(ghc_rts);
+ procRtsOpts(rts_argc0, rtsOptsEnabled);
+ rts_argc0 = rts_argc;
+ }
+ }
}
// Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
break;
}
else if (strequal("+RTS", argv[arg])) {
- mode = RTS;
- }
+ mode = RTS;
+ }
else if (strequal("-RTS", argv[arg])) {
mode = PGM;
}
- else if (mode == RTS && *rts_argc < MAX_RTS_ARGS-1) {
- rts_argv[(*rts_argc)++] = argv[arg];
- }
- else if (mode == PGM) {
+ else if (mode == RTS && rts_argc < MAX_RTS_ARGS-1) {
+ rts_argv[rts_argc++] = argv[arg];
+ }
+ else if (mode == PGM) {
argv[(*argc)++] = argv[arg];
}
else {
argv[(*argc)++] = argv[arg];
}
argv[*argc] = (char *) 0;
- rts_argv[*rts_argc] = (char *) 0;
+ rts_argv[rts_argc] = (char *) 0;
+
+ procRtsOpts(rts_argc0, rtsOptsEnabled);
+
+ normaliseRtsOpts();
+
+ setProgArgv(*argc, argv);
+
+ if (RtsFlags.GcFlags.statsFile != NULL) {
+ initStatsFile (RtsFlags.GcFlags.statsFile);
+ }
+ if (RtsFlags.TickyFlags.tickyFile != NULL) {
+ initStatsFile (RtsFlags.GcFlags.statsFile);
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * procRtsOpts: Process rts_argv between rts_argc0 and rts_argc.
+ * -------------------------------------------------------------------------- */
+
+static void procRtsOpts (int rts_argc0, RtsOptsEnabledEnum enabled)
+{
+ rtsBool error = rtsFalse;
+ int arg;
// Process RTS (rts_argv) part: mainly to determine statsfile
- for (arg = 0; arg < *rts_argc; arg++) {
- if (rts_argv[arg][0] != '-') {
+ for (arg = rts_argc0; arg < rts_argc; arg++) {
+ if (rts_argv[arg][0] != '-') {
fflush(stdout);
errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
error = rtsTrue;
} else {
- switch(rts_argv[arg][1]) {
+
+ if (enabled == RtsOptsNone) {
+ errorBelch("RTS options are disabled. Link with -rtsopts to enable them.");
+ stg_exit(EXIT_FAILURE);
+ }
+
+ switch(rts_argv[arg][1]) {
+ case '-':
+ if (strequal("info", &rts_argv[arg][2])) {
+ printRtsInfo();
+ stg_exit(0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (enabled == RtsOptsSafeOnly) {
+ errorBelch("Most RTS options are disabled. Link with -rtsopts to enable them.");
+ stg_exit(EXIT_FAILURE);
+ }
+
+ switch(rts_argv[arg][1]) {
/* process: general args, then PROFILING-only ones, then
CONCURRENT-only, TICKY-only (same order as defined in
# define TICKY_BUILD_ONLY(x) x
#else
# define TICKY_BUILD_ONLY(x) \
-errorBelch("not built for: ticky-ticky stats"); \
+errorBelch("the flag %s requires the program to be built with -ticky", rts_argv[arg]); \
error = rtsTrue;
#endif
# define PROFILING_BUILD_ONLY(x) x
#else
# define PROFILING_BUILD_ONLY(x) \
-errorBelch("not built for: -prof"); \
+errorBelch("the flag %s requires the program to be built with -prof", rts_argv[arg]); \
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) \
-errorBelch("not built for: -par-prof"); \
+# define TRACING_BUILD_ONLY(x) \
+errorBelch("the flag %s requires the program to be built with -eventlog or -debug", rts_argv[arg]); \
error = rtsTrue;
#endif
# define THREADED_BUILD_ONLY(x) x
#else
# define THREADED_BUILD_ONLY(x) \
-errorBelch("not built for: -smp"); \
+errorBelch("the flag %s requires the program to be built with -threaded", rts_argv[arg]); \
+error = rtsTrue;
+#endif
+
+#ifdef DEBUG
+# define DEBUG_BUILD_ONLY(x) x
+#else
+# define DEBUG_BUILD_ONLY(x) \
+errorBelch("the flag %s requires the program to be built with -debug", rts_argv[arg]); \
error = rtsTrue;
#endif
else if (strequal("info",
&rts_argv[arg][2])) {
printRtsInfo();
- exit(0);
+ stg_exit(0);
}
else {
errorBelch("unknown RTS option: %s",rts_argv[arg]);
}
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':
RtsFlags.PapiFlags.eventType = PAPI_FLAG_CB_EVENTS;
break;
case '+':
+ case '#':
if (RtsFlags.PapiFlags.numUserEvents >= MAX_PAPI_USER_EVENTS) {
errorBelch("maximum number of PAPI events reached");
stg_exit(EXIT_FAILURE);
}
+ nat eventNum = RtsFlags.PapiFlags.numUserEvents++;
+ char kind = rts_argv[arg][2];
+ nat eventKind = kind == '+' ? PAPI_PRESET_EVENT_KIND : PAPI_NATIVE_EVENT_KIND;
+
+ RtsFlags.PapiFlags.userEvents[eventNum] = rts_argv[arg] + 3;
RtsFlags.PapiFlags.eventType = PAPI_USER_EVENTS;
- RtsFlags.PapiFlags.userEvents[RtsFlags.PapiFlags.numUserEvents++] = rts_argv[arg] + 3;
+ RtsFlags.PapiFlags.userEventsKind[eventNum] = eventKind;
break;
default:
bad_option( rts_argv[arg] );
bad_option( rts_argv[arg] );
break;
-#ifdef DEBUG
case 'D':
+ DEBUG_BUILD_ONLY(
{
char *c;
case 'p':
RtsFlags.DebugFlags.prof = rtsTrue;
break;
- case 'e':
- RtsFlags.DebugFlags.eventlog = rtsTrue;
- break;
case 'l':
RtsFlags.DebugFlags.linker = rtsTrue;
break;
case 'c':
RtsFlags.DebugFlags.hpc = rtsTrue;
break;
+ case 'r':
+ RtsFlags.DebugFlags.sparks = rtsTrue;
+ break;
default:
bad_option( rts_argv[arg] );
}
}
- break;
- }
-#endif
+ // -Dx also turns on -v. Use -l to direct trace
+ // events to the .eventlog file instead.
+ RtsFlags.TraceFlags.tracing = TRACE_STDERR;
+ })
+ break;
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, sizeof(W_), 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;
-
- case 'M':
- RtsFlags.GcFlags.maxHeapSize =
- decode(rts_argv[arg]+2) / BLOCK_SIZE;
- /* user give size in *bytes* but "maxHeapSize" is in *blocks* */
+ switch(rts_argv[arg][2]) {
+ case 'c':
+ RtsFlags.GcFlags.stkChunkSize =
+ decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
+ break;
+ case 'b':
+ RtsFlags.GcFlags.stkChunkBufferSize =
+ decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
+ break;
+ case 'i':
+ RtsFlags.GcFlags.initialStkSize =
+ decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
+ break;
+ default:
+ RtsFlags.GcFlags.initialStkSize =
+ decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
+ break;
+ }
+ break;
- if (RtsFlags.GcFlags.maxHeapSize <= 0) {
- bad_option(rts_argv[arg]);
- }
- break;
+ case 'M':
+ 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;
-
- case 'T':
- RtsFlags.GcFlags.steps = decode(rts_argv[arg]+2);
- if (RtsFlags.GcFlags.steps < 1) {
- bad_option(rts_argv[arg]);
- }
- break;
+ RtsFlags.GcFlags.generations =
+ 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':
stats:
{
int r;
- r = open_stats_file(arg, *argc, argv,
- *rts_argc, rts_argv, NULL,
- &RtsFlags.GcFlags.statsFile);
+ r = openStatsFile(rts_argv[arg]+2, NULL,
+ &RtsFlags.GcFlags.statsFile);
if (r == -1) { error = rtsTrue; }
}
break;
/* =========== PROFILING ========================== */
- case 'l':
-#ifdef EVENTLOG
- RtsFlags.EventLogFlags.doEventLogging = rtsTrue;
-#else
- errorBelch("not built for: -eventlog");
-#endif
- break;
-
case 'P': /* detailed cost centre profiling (time/alloc) */
case 'p': /* cost centre profiling (time/alloc) */
PROFILING_BUILD_ONLY(
}
break;
-#if defined(THREADED_RTS) && !defined(NOSMP)
+#if !defined(NOSMP)
case 'N':
THREADED_BUILD_ONLY(
if (rts_argv[arg][2] == '\0') {
) break;
case 'q':
+ THREADED_BUILD_ONLY(
switch (rts_argv[arg][2]) {
case '\0':
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;
case 'm':
RtsFlags.ParFlags.migrate = rtsFalse;
break;
- case 'w':
- RtsFlags.ParFlags.wakeupMigrate = rtsTrue;
- break;
- default:
+ case 'w':
+ // -qw was removed; accepted for backwards compat
+ break;
+ default:
errorBelch("unknown RTS option: %s",rts_argv[arg]);
error = rtsTrue;
break;
}
- break;
+ ) break;
#endif
/* =========== PARALLEL =========================== */
case 'e':
{
int r;
- r = open_stats_file(arg, *argc, argv,
- *rts_argc, rts_argv, TICKY_FILENAME_FMT,
- &RtsFlags.TickyFlags.tickyFile);
+ r = openStatsFile(rts_argv[arg]+2,
+ TICKY_FILENAME_FMT,
+ &RtsFlags.TickyFlags.tickyFile);
if (r == -1) { error = rtsTrue; }
}
) break;
/* =========== TRACING ---------=================== */
+ case 'l':
+ TRACING_BUILD_ONLY(
+ RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
+ read_trace_flags(&rts_argv[arg][2]);
+ );
+ break;
+
case 'v':
- switch(rts_argv[arg][2]) {
- case '\0':
- errorBelch("incomplete RTS option: %s",rts_argv[arg]);
- error = rtsTrue;
- break;
- case 't':
- RtsFlags.DebugFlags.timestamp = rtsTrue;
- break;
- case 's':
- case 'g':
- // ignored for backwards-compat
- break;
- default:
- errorBelch("unknown RTS option: %s",rts_argv[arg]);
- error = rtsTrue;
- break;
- }
- break;
+ DEBUG_BUILD_ONLY(
+ RtsFlags.TraceFlags.tracing = TRACE_STDERR;
+ read_trace_flags(&rts_argv[arg][2]);
+ );
+ break;
/* =========== EXTENDED OPTIONS =================== */
}
}
+ if (error) errorUsage();
+}
+
+/* -----------------------------------------------------------------------------
+ * normaliseRtsOpts: Set some derived values, and make sure things are
+ * within sensible ranges.
+ * -------------------------------------------------------------------------- */
+
+static void normaliseRtsOpts (void)
+{
if (RtsFlags.MiscFlags.tickInterval < 0) {
RtsFlags.MiscFlags.tickInterval = 50;
}
RtsFlags.ProfFlags.profileIntervalTicks = 0;
}
- if (error) {
- const char **p;
-
- fflush(stdout);
- for (p = usage_text; *p; p++)
- errorBelch("%s", *p);
- stg_exit(EXIT_FAILURE);
+ if (RtsFlags.GcFlags.stkChunkBufferSize >
+ RtsFlags.GcFlags.stkChunkSize / 2) {
+ errorBelch("stack chunk buffer size (-kb) must be less than 50%% of the stack chunk size (-kc)");
+ errorUsage();
}
}
+static void errorUsage (void)
+{
+ const char **p;
+
+ fflush(stdout);
+ for (p = usage_text; *p; p++)
+ errorBelch("%s", *p);
+ stg_exit(EXIT_FAILURE);
+}
static void
stats_fprintf(FILE *f, char *s, ...)
va_end(ap);
}
-static int /* return -1 on error */
-open_stats_file (
- I_ arg,
- int argc, char *argv[],
- int rts_argc, char *rts_argv[],
- const char *FILENAME_FMT,
- FILE **file_ret)
+/* -----------------------------------------------------------------------------
+ * openStatsFile: open a file in which to put some runtime stats
+ * -------------------------------------------------------------------------- */
+
+static int // return -1 on error
+openStatsFile (char *filename, // filename, or NULL
+ const char *filename_fmt, // if filename == NULL, use
+ // this fmt with sprintf to
+ // generate the filename. %s
+ // expands to the program name.
+ FILE **file_ret) // return the FILE*
{
FILE *f = NULL;
- if (strequal(rts_argv[arg]+2, "stderr")
- || (FILENAME_FMT == NULL && rts_argv[arg][2] == '\0')) {
+ if (strequal(filename, "stderr")
+ || (filename_fmt == NULL && *filename == '\0')) {
f = NULL; /* NULL means use debugBelch */
} else {
- if (rts_argv[arg][2] != '\0') { /* stats file specified */
- f = fopen(rts_argv[arg]+2,"w");
+ if (*filename != '\0') { /* stats file specified */
+ f = fopen(filename,"w");
} else {
char stats_filename[STATS_FILENAME_MAXLEN]; /* default <program>.<ext> */
- sprintf(stats_filename, FILENAME_FMT, argv[0]);
+ sprintf(stats_filename, filename_fmt, prog_name);
f = fopen(stats_filename,"w");
}
if (f == NULL) {
- errorBelch("Can't open stats file %s\n", rts_argv[arg]+2);
+ errorBelch("Can't open stats file %s\n", filename);
return -1;
}
}
*file_ret = f;
- {
- /* Write argv and rtsv into start of stats file */
- int count;
- for(count = 0; count < argc; count++) {
- stats_fprintf(f, "%s ", argv[count]);
- }
- stats_fprintf(f, "+RTS ");
- for(count = 0; count < rts_argc; count++)
- stats_fprintf(f, "%s ", rts_argv[count]);
- stats_fprintf(f, "\n");
- }
return 0;
}
+/* -----------------------------------------------------------------------------
+ * initStatsFile: write a line to the file containing the program name
+ * and the arguments it was invoked with.
+-------------------------------------------------------------------------- */
+static void initStatsFile (FILE *f)
+{
+ /* Write prog_argv and rts_argv into start of stats file */
+ int count;
+ for (count = 0; count < prog_argc; count++) {
+ stats_fprintf(f, "%s ", prog_argv[count]);
+ }
+ stats_fprintf(f, "+RTS ");
+ for (count = 0; count < rts_argc; count++)
+ stats_fprintf(f, "%s ", rts_argv[count]);
+ stats_fprintf(f, "\n");
+}
-static I_
-decode(const char *s)
+/* -----------------------------------------------------------------------------
+ * decodeSize: parse a string containing a size, like 300K or 1.2M
+-------------------------------------------------------------------------- */
+
+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) {
+ // printf doesn't like 64-bit format specs on Windows
+ // apparently, so fall back to unsigned long.
+ errorBelch("error in RTS option %s: size outside allowed range (%lu - %lu)", flag, (lnat)min, (lnat)max);
+ stg_exit(EXIT_FAILURE);
+ }
- return (I_)m;
+ return val;
}
+#if defined(TRACING)
+static void read_trace_flags(char *arg)
+{
+ char *c;
+
+ for (c = arg; *c != '\0'; c++) {
+ switch(*c) {
+ case '\0':
+ break;
+ case 's':
+ RtsFlags.TraceFlags.scheduler = rtsTrue;
+ break;
+ case 't':
+ RtsFlags.TraceFlags.timestamp = rtsTrue;
+ break;
+ case 'g':
+ // ignored for backwards-compat
+ break;
+ default:
+ errorBelch("unknown trace option: %c",*c);
+ break;
+ }
+ }
+}
+#endif
+
static void GNU_ATTRIBUTE(__noreturn__)
bad_option(const char *s)
{
void
setProgArgv(int argc, char *argv[])
{
- /* Usually this is done by startupHaskell, so we don't need to call this.
- However, sometimes Hugs wants to change the arguments which Haskell
- getArgs >>= ... will be fed. So you can do that by calling here
- _after_ calling startupHaskell.
- */
- prog_argc = argc;
- prog_argv = argv;
- setProgName(prog_argv);
+ prog_argc = argc;
+ prog_argv = argv;
+ setProgName(prog_argv);
}
/* These functions record and recall the full arguments, including the
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;
+}