RtsFlags.c 43 KB
Newer Older
1
/* -----------------------------------------------------------------------------
2 3
 *
 * (c) The AQUA Project, Glasgow University, 1994-1997
Simon Marlow's avatar
Simon Marlow committed
4
 * (c) The GHC Team, 1998-2006
5 6 7 8 9
 *
 * Functions for parsing the argument list.
 *
 * ---------------------------------------------------------------------------*/

10
#include "PosixSource.h"
11
#include "Rts.h"
Simon Marlow's avatar
Simon Marlow committed
12

13
#include "RtsOpts.h"
14
#include "RtsUtils.h"
15
#include "Profiling.h"
16

17 18
#ifdef HAVE_CTYPE_H
#include <ctype.h>
19 20
#endif

21 22
#include <string.h>

23 24
// Flag Structure
RTS_FLAGS RtsFlags;
25 26 27 28

/*
 * Split argument lists
 */
sof's avatar
sof committed
29
int     prog_argc = 0;    /* an "int" so as to match normal "argc" */
30
char  **prog_argv = NULL;
31 32
int     full_prog_argc = 0;    /* an "int" so as to match normal "argc" */
char  **full_prog_argv = NULL;
sof's avatar
sof committed
33
char   *prog_name = NULL; /* 'basename' of prog_argv[0] */
34
int     rts_argc = 0;  /* ditto */
35 36 37 38 39 40 41 42 43 44 45 46
char   *rts_argv[MAX_RTS_ARGS];

/*
 * constants, used later 
 */
#define RTS 1
#define PGM 0

/* -----------------------------------------------------------------------------
   Static function decls
   -------------------------------------------------------------------------- */

47
static int		/* return NULL on error */
48 49 50 51
open_stats_file (
    I_ arg,
    int argc, char *argv[],
    int rts_argc, char *rts_argv[],
52 53
    const char *FILENAME_FMT,
    FILE **file_ret);
54

55
static StgWord64 decodeSize(const char *flag, nat offset, StgWord64 min, StgWord64 max);
56
static void bad_option(const char *s);
57 58 59
#ifdef TRACING
static void read_trace_flags(char *arg);
#endif
60 61 62 63 64 65 66 67 68 69

/* -----------------------------------------------------------------------------
 * Command-line option parsing routines.
 * ---------------------------------------------------------------------------*/

void initRtsFlagsDefaults(void)
{
    RtsFlags.GcFlags.statsFile		= NULL;
    RtsFlags.GcFlags.giveStats		= NO_GC_STATS;

70
    RtsFlags.GcFlags.maxStkSize		= (8 * 1024 * 1024) / sizeof(W_);
71
    RtsFlags.GcFlags.initialStkSize	= 1024 / sizeof(W_);
72 73
    RtsFlags.GcFlags.stkChunkSize       = (32 * 1024) / sizeof(W_);
    RtsFlags.GcFlags.stkChunkBufferSize = (1 * 1024) / sizeof(W_);
74

75
    RtsFlags.GcFlags.minAllocAreaSize   = (512 * 1024)        / BLOCK_SIZE;
76
    RtsFlags.GcFlags.minOldGenSize      = (1024 * 1024)       / BLOCK_SIZE;
77
    RtsFlags.GcFlags.maxHeapSize	= 0;    /* off by default */
78
    RtsFlags.GcFlags.heapSizeSuggestion	= 0;    /* none */
79
    RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsFalse;
80
    RtsFlags.GcFlags.pcFreeHeap		= 3;	/* 3% */
81
    RtsFlags.GcFlags.oldGenFactor       = 2;
82
    RtsFlags.GcFlags.generations        = 2;
83
    RtsFlags.GcFlags.squeezeUpdFrames	= rtsTrue;
84
    RtsFlags.GcFlags.compact            = rtsFalse;
85
    RtsFlags.GcFlags.compactThreshold   = 30.0;
86
    RtsFlags.GcFlags.sweep              = rtsFalse;
87 88 89
#ifdef RTS_GTK_FRONTPANEL
    RtsFlags.GcFlags.frontpanel         = rtsFalse;
#endif
90
    RtsFlags.GcFlags.idleGCDelayTime    = 300; /* millisecs */
91

92 93 94 95 96 97 98 99 100 101 102 103
#if osf3_HOST_OS
/* ToDo: Perhaps by adjusting this value we can make linking without
 * -static work (i.e., not generate a core-dumping executable)? */
# if SIZEOF_VOID_P == 8
    RtsFlags.GcFlags.heapBase           = 0x180000000L;
# else
#  error I have no idea where to begin the heap on a non-64-bit osf3 machine.
# endif
#else
    RtsFlags.GcFlags.heapBase           = 0;   /* means don't care */
#endif

104 105
#ifdef DEBUG
    RtsFlags.DebugFlags.scheduler	= rtsFalse;
106
    RtsFlags.DebugFlags.interpreter	= rtsFalse;
107 108 109 110 111 112
    RtsFlags.DebugFlags.weak		= rtsFalse;
    RtsFlags.DebugFlags.gccafs		= rtsFalse;
    RtsFlags.DebugFlags.gc		= rtsFalse;
    RtsFlags.DebugFlags.block_alloc	= rtsFalse;
    RtsFlags.DebugFlags.sanity		= rtsFalse;
    RtsFlags.DebugFlags.stable		= rtsFalse;
113
    RtsFlags.DebugFlags.stm             = rtsFalse;
114
    RtsFlags.DebugFlags.prof		= rtsFalse;
115
    RtsFlags.DebugFlags.apply		= rtsFalse;
116
    RtsFlags.DebugFlags.linker		= rtsFalse;
117
    RtsFlags.DebugFlags.squeeze		= rtsFalse;
118
    RtsFlags.DebugFlags.hpc		= rtsFalse;
119
    RtsFlags.DebugFlags.sparks		= rtsFalse;
120 121
#endif

Simon Marlow's avatar
Simon Marlow committed
122
#if defined(PROFILING)
123
    RtsFlags.CcFlags.doCostCentres	= 0;
Simon Marlow's avatar
Simon Marlow committed
124
#endif /* PROFILING */
125

126
    RtsFlags.ProfFlags.doHeapProfile      = rtsFalse;
127
    RtsFlags.ProfFlags.profileInterval    = 100;
128 129

#ifdef PROFILING
130
    RtsFlags.ProfFlags.includeTSOs        = rtsFalse;
131
    RtsFlags.ProfFlags.showCCSOnException = rtsFalse;
132
    RtsFlags.ProfFlags.maxRetainerSetSize = 8;
ravi@bluespec.com's avatar
ravi@bluespec.com committed
133
    RtsFlags.ProfFlags.ccsLength          = 25;
134 135 136 137
    RtsFlags.ProfFlags.modSelector        = NULL;
    RtsFlags.ProfFlags.descrSelector      = NULL;
    RtsFlags.ProfFlags.typeSelector       = NULL;
    RtsFlags.ProfFlags.ccSelector         = NULL;
138
    RtsFlags.ProfFlags.ccsSelector        = NULL;
139 140
    RtsFlags.ProfFlags.retainerSelector   = NULL;
    RtsFlags.ProfFlags.bioSelector        = NULL;
141 142
#endif

143
#ifdef TRACING
144
    RtsFlags.TraceFlags.tracing       = TRACE_NONE;
145 146
    RtsFlags.TraceFlags.timestamp     = rtsFalse;
    RtsFlags.TraceFlags.scheduler     = rtsFalse;
Simon Marlow's avatar
Simon Marlow committed
147 148
#endif

149 150
    RtsFlags.MiscFlags.tickInterval	= 20;  /* In milliseconds */
    RtsFlags.ConcFlags.ctxtSwitchTime	= 20;  /* In milliseconds */
151

152
    RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
Ian Lynagh's avatar
Ian Lynagh committed
153
    RtsFlags.MiscFlags.machineReadable = rtsFalse;
154
    RtsFlags.MiscFlags.linkerMemBase    = 0;
155

156
#ifdef THREADED_RTS
157
    RtsFlags.ParFlags.nNodes	        = 1;
158 159
    RtsFlags.ParFlags.migrate           = rtsTrue;
    RtsFlags.ParFlags.wakeupMigrate     = rtsFalse;
160
    RtsFlags.ParFlags.parGcEnabled      = 1;
161 162 163
    RtsFlags.ParFlags.parGcGen          = 0;
    RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsTrue;
    RtsFlags.ParFlags.parGcLoadBalancingGen = 1;
164
    RtsFlags.ParFlags.setAffinity       = 0;
165
#endif
166

Simon Marlow's avatar
Simon Marlow committed
167
#if defined(THREADED_RTS)
168
    RtsFlags.ParFlags.maxLocalSparks	= 4096;
Simon Marlow's avatar
Simon Marlow committed
169
#endif /* THREADED_RTS */
170 171

#ifdef TICKY_TICKY
172 173
    RtsFlags.TickyFlags.showTickyStats	 = rtsFalse;
    RtsFlags.TickyFlags.tickyFile	 = NULL;
174
#endif
Simon Marlow's avatar
Simon Marlow committed
175

176
#ifdef USE_PAPI
177 178
    /* By default no special measurements taken */
    RtsFlags.PapiFlags.eventType        = 0;
179
    RtsFlags.PapiFlags.numUserEvents    = 0;
180
#endif
181 182 183 184 185 186 187 188 189 190 191 192 193 194
}

static const char *
usage_text[] = {
"",
"Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
"",
"   +RTS    Indicates run time system options follow",
"   -RTS    Indicates program arguments follow",
"  --RTS    Indicates that ALL subsequent arguments will be given to the",
"           program (including any of these RTS flags)",
"",
"The following run time system options are available:",
"",
195
"  -?       Prints this message and exits; the program is not executed",
196
"  --info   Print information about the RTS used by this program",
197
"",
198
"  -K<size> Sets the maximum stack size (default 8M)  Egs: -K32k   -K512k",
199 200 201
"  -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)",
202
"",
203
"  -A<size> Sets the minimum allocation area size (default 512k) Egs: -A1m -A10k",
204
"  -M<size> Sets the maximum heap size (default unlimited)  Egs: -M256k -M1G",
205
"  -H<size> Sets the minimum heap size (default 0M)   Egs: -H24m  -H1G",
206
"  -m<n>    Minimum % of heap which must be available (default 3%)",
207
"  -G<n>    Number of generations (default: 2)",
208 209 210 211 212
"  -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)",
213
"  -w       Use mark-region for the oldest generation (experimental)",
214
#if defined(THREADED_RTS)
215 216
"  -I<sec>  Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
#endif
217
"",
218 219 220
"  -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
"  -s[<file>] Summary  GC statistics (if <file> omitted, uses stderr)",
"  -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
221 222 223
#ifdef RTS_GTK_FRONTPANEL
"  -f       Display front panel (requires X11 & GTK+)",
#endif
224 225 226 227
"",
"",
"  -Z       Don't squeeze out update frames on stack overflow",
"  -B       Sound the bell at the start of each garbage collection",
Simon Marlow's avatar
Simon Marlow committed
228
#if defined(PROFILING)
229
"",
230
"  -px      Time/allocation profile (XML)  (output file <program>.prof)",
andy's avatar
andy committed
231 232 233
"  -p       Time/allocation profile        (output file <program>.prof)",
"  -P       More detailed Time/Allocation profile",
"  -Pa      Give information about *all* cost centres",
234

235 236
# if defined(PROFILING)
"",
237 238 239 240 241 242 243 244
"  -hx            Heap residency profile (XML)   (output file <program>.prof)",
"  -h<break-down> Heap residency profile (hp2ps) (output file <program>.hp)",
"     break-down: c = cost centre stack (default)",
"                 m = module",
"                 d = closure description",
"                 y = type description",
"                 r = retainer",
"                 b = biography (LAG,DRAG,VOID,USE)",
245
"  A subset of closures may be selected thusly:",
246 247
"    -hc<cc>,...  specific cost centre(s) (top of stack only)",
"    -hC<cc>,...  specific cost centre(s) (anywhere in stack)",
248 249 250 251 252
"    -hm<mod>...  all cost centres from the specified modules(s)",
"    -hd<des>,... closures with specified closure descriptions",
"    -hy<typ>...  closures with specified type descriptions",
"    -hr<cc>...   closures with specified retainers",
"    -hb<bio>...  closures with specified biographies (lag,drag,void,use)",
253 254
"",
"  -R<size>       Set the maximum retainer set size (default: 8)",
ravi@bluespec.com's avatar
ravi@bluespec.com committed
255 256 257
"", 
"  -L<chars>      Maximum length of a cost-centre stack in a heap profile",
"                 (default: 25)",
258
"",
259 260
"  -xt            Include threads (TSOs) in a heap profile",
"",
261
"  -xc      Show current cost centre stack on raising an exception",
262 263
# endif
#endif /* PROFILING or PAR */
Simon Marlow's avatar
Simon Marlow committed
264

265
#ifdef TRACING
Simon Marlow's avatar
Simon Marlow committed
266
"",
267 268 269 270 271 272 273 274 275
"  -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
Simon Marlow's avatar
Simon Marlow committed
276 277
#endif

278
#if !defined(PROFILING)
279
"",
280
"  -hT      Heap residency profile (output file <program>.hp)",
281
#endif
282
"  -i<sec>  Time between heap samples (seconds, default: 0.1)",
283 284
"",
#if defined(TICKY_TICKY)
285
"  -r<file>  Produce ticky-ticky statistics (with -rstderr for stderr)",
286 287
"",
#endif
288 289 290
"  -C<secs>  Context-switch interval in seconds.",
"            0 or no argument means switch as often as possible.",
"            Default: 0.02 sec; resolution is set by -V below.",
291
"  -V<secs>  Master tick interval in seconds (0 == disable timer).",
292 293
"            This sets the resolution for -C and the profile timer -i.",
"            Default: 0.02 sec.",
294 295 296
"",
#if defined(DEBUG)
"  -Ds  DEBUG: scheduler",
297
"  -Di  DEBUG: interpreter",
298 299 300 301 302 303 304
"  -Dw  DEBUG: weak",
"  -DG  DEBUG: gccafs",
"  -Dg  DEBUG: gc",
"  -Db  DEBUG: block",
"  -DS  DEBUG: sanity",
"  -Dt  DEBUG: stable",
"  -Dp  DEBUG: prof",
Simon Marlow's avatar
Simon Marlow committed
305
"  -De  DEBUG: event logging",
306
"  -Da  DEBUG: apply",
307
"  -Dl  DEBUG: linker",
308
"  -Dm  DEBUG: stm",
309
"  -Dz  DEBUG: stack squezing",
310
"  -Dc  DEBUG: program coverage",
311 312
"  -Dr  DEBUG: sparks",
"",
313
"     NOTE: DEBUG events are sent to stderr by default; add -l to create a",
314
"     binary event log file instead.",
315
"",
316
#endif /* DEBUG */
317
#if defined(THREADED_RTS) && !defined(NOSMP)
318 319
"  -N<n>     Use <n> processors (default: 1)",
"  -N        Determine the number of processors to use automatically",
320 321 322 323 324
"  -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)",
325 326
"  -qm       Don't automatically migrate threads between CPUs",
"  -qw       Migrate a thread to the current CPU when it is woken up",
327
#endif
328 329
"  --install-signal-handlers=<yes|no>",
"            Install signal handlers (default: yes)",
Simon Marlow's avatar
Simon Marlow committed
330
#if defined(THREADED_RTS)
331 332
"  -e<n>     Maximum number of outstanding local sparks (default: 4096)",
#endif
333 334 335 336
#if defined(x86_64_HOST_ARCH)
"  -xm       Base address to mmap memory in the GHCi linker",
"            (hex; must be <80000000)",
#endif
337
#if defined(USE_PAPI)
338 339
"  -aX       CPU performance counter measurements using PAPI",
"            (use with the -s<file> option).  X is one of:",
340 341 342 343 344 345
"",
/* "            y - cycles", */
"            1 - level 1 cache misses",
"            2 - level 2 cache misses",
"            b - branch mispredictions",
"            s - stalled cycles",
346
"            e - cache miss and branch misprediction events",
347 348
"            +PAPI_EVENT   - collect papi preset event PAPI_EVENT",
"            #NATIVE_EVENT - collect native event NATIVE_EVENT (in hex)",
349
#endif
350
"",
351 352
"RTS options may also be specified using the GHCRTS environment variable.",
"",
353 354 355 356 357 358
"Other RTS options may be available for programs compiled a different way.",
"The GHC User's Guide has full details.",
"",
0
};

sof's avatar
sof committed
359
STATIC_INLINE rtsBool
360 361 362 363 364
strequal(const char *a, const char * b)
{
    return(strcmp(a, b) == 0);
}

365 366 367 368 369 370 371 372 373 374 375 376 377 378
static void
splitRtsFlags(char *s, int *rts_argc, char *rts_argv[])
{
    char *c1, *c2;

    c1 = s;
    do {
	while (isspace(*c1)) { c1++; };
	c2 = c1;
	while (!isspace(*c2) && *c2 != '\0') { c2++; };
	
	if (c1 == c2) { break; }
	
	if (*rts_argc < MAX_RTS_ARGS-1) {
sof's avatar
sof committed
379
	    s = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
380 381 382 383 384 385 386 387 388 389 390
	    strncpy(s, c1, c2-c1);
	    s[c2-c1] = '\0';
	    rts_argv[(*rts_argc)++] = s;
	} else {
	    barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
	}
	
	c1 = c2;
    } while (*c1 != '\0');
}
    
391 392 393 394 395 396 397
void
setupRtsFlags(int *argc, char *argv[], int *rts_argc, char *rts_argv[])
{
    rtsBool error = rtsFalse;
    I_ mode;
    I_ arg, total_arg;

398
    setProgName (argv);
399 400 401 402 403 404
    total_arg = *argc;
    arg = 1;

    *argc = 1;
    *rts_argc = 0;

405 406 407 408 409 410 411 412 413
    // 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);
	}
    }

414
    // process arguments from the GHCRTS environment variable next
415
    // (arguments from the command line override these).
416 417 418 419
    {
	char *ghc_rts = getenv("GHCRTS");

	if (ghc_rts != NULL) {
Ian Lynagh's avatar
Ian Lynagh committed
420
            if (rtsOptsEnabled != rtsOptsNone) {
421 422 423
                splitRtsFlags(ghc_rts, rts_argc, rts_argv);
            }
            else {
424
                errorBelch("Warning: Ignoring GHCRTS variable as RTS options are disabled.\n         Link with -rtsopts to enable them.");
425 426
                // We don't actually exit, just warn
            }
427 428
	}
    }
429

430 431 432
    // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
    //   argv[0] must be PGM argument -- leave in argv

433 434 435 436 437 438 439 440 441 442 443 444
    for (mode = PGM; arg < total_arg; arg++) {
	// The '--RTS' argument disables all future +RTS ... -RTS processing.
	if (strequal("--RTS", argv[arg])) {
	    arg++;
	    break;
	}
	// The '--' argument is passed through to the program, but
	// disables all further +RTS ... -RTS processing.
	else if (strequal("--", argv[arg])) {
	    break;
	}
	else if (strequal("+RTS", argv[arg])) {
Ian Lynagh's avatar
Ian Lynagh committed
445
            if (rtsOptsEnabled != rtsOptsNone) {
446 447 448
                mode = RTS;
            }
            else {
449
                errorBelch("RTS options are disabled. Link with -rtsopts to enable them.");
450 451
                stg_exit(EXIT_FAILURE);
            }
452 453 454 455 456
	}
	else if (strequal("-RTS", argv[arg])) {
	    mode = PGM;
	}
	else if (mode == RTS && *rts_argc < MAX_RTS_ARGS-1) {
Ian Lynagh's avatar
Ian Lynagh committed
457 458 459 460 461 462 463 464
	    if ((rtsOptsEnabled == rtsOptsAll) ||
            strequal(argv[arg], "--info")) {
            rts_argv[(*rts_argc)++] = argv[arg];
        }
        else {
            errorBelch("Most RTS options are disabled. Link with -rtsopts to enable them.");
            stg_exit(EXIT_FAILURE);
        }
465 466 467 468 469 470 471 472
	}
	else if (mode == PGM) {
	    argv[(*argc)++] = argv[arg];
	}
	else {
	  barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
	}
    }
473 474 475
    // process remaining program arguments
    for (; arg < total_arg; arg++) {
	argv[(*argc)++] = argv[arg];
476 477 478 479 480
    }
    argv[*argc] = (char *) 0;
    rts_argv[*rts_argc] = (char *) 0;

    // Process RTS (rts_argv) part: mainly to determine statsfile
481 482 483
    for (arg = 0; arg < *rts_argc; arg++) {
	if (rts_argv[arg][0] != '-') {
	    fflush(stdout);
484
	    errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
485 486 487 488 489
	    error = rtsTrue;

        } else {
	    switch(rts_argv[arg][1]) {

Simon Marlow's avatar
Simon Marlow committed
490 491 492 493 494
	      /* process: general args, then PROFILING-only ones, then
		 CONCURRENT-only, TICKY-only (same order as defined in
		 RtsFlags.lh); within those groups, mostly in
		 case-insensitive alphabetical order.  Final group is
		 x*, which allows for more options.
495 496 497 498 499 500
	      */

#ifdef TICKY_TICKY
# define TICKY_BUILD_ONLY(x) x
#else
# define TICKY_BUILD_ONLY(x) \
501
errorBelch("the flag %s requires the program to be built with -ticky", rts_argv[arg]); \
502 503 504 505 506 507 508
error = rtsTrue;
#endif

#ifdef PROFILING
# define PROFILING_BUILD_ONLY(x)   x
#else
# define PROFILING_BUILD_ONLY(x) \
509
errorBelch("the flag %s requires the program to be built with -prof", rts_argv[arg]); \
510 511 512
error = rtsTrue;
#endif

513 514
#ifdef TRACING
# define TRACING_BUILD_ONLY(x)   x
Simon Marlow's avatar
Simon Marlow committed
515
#else
516
# define TRACING_BUILD_ONLY(x) \
517
errorBelch("the flag %s requires the program to be built with -eventlog or -debug", rts_argv[arg]); \
Simon Marlow's avatar
Simon Marlow committed
518 519 520
error = rtsTrue;
#endif

521 522 523 524
#ifdef THREADED_RTS
# define THREADED_BUILD_ONLY(x)      x
#else
# define THREADED_BUILD_ONLY(x) \
525 526 527 528 529 530 531 532 533
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]); \
534
error = rtsTrue;
535 536 537 538 539 540 541
#endif

	      /* =========== GENERAL ========================== */
	      case '?':
		error = rtsTrue;
		break;

542 543 544 545 546 547 548 549 550 551 552 553
              /* This isn't going to allow us to keep related options
                 together as we add more --* flags. We really need a
                 proper options parser. */
	      case '-':
                  if (strequal("install-signal-handlers=yes",
                               &rts_argv[arg][2])) {
                      RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
                  }
                  else if (strequal("install-signal-handlers=no",
                               &rts_argv[arg][2])) {
                      RtsFlags.MiscFlags.install_signal_handlers = rtsFalse;
                  }
Ian Lynagh's avatar
Ian Lynagh committed
554 555 556 557
                  else if (strequal("machine-readable",
                               &rts_argv[arg][2])) {
                      RtsFlags.MiscFlags.machineReadable = rtsTrue;
                  }
558 559
                  else if (strequal("info",
                               &rts_argv[arg][2])) {
560
                      printRtsInfo();
561
                      stg_exit(0);
562
                  }
563 564 565 566 567
                  else {
		      errorBelch("unknown RTS option: %s",rts_argv[arg]);
		      error = rtsTrue;
                  }
		  break;
568
	      case 'A':
569 570 571 572
                  RtsFlags.GcFlags.minAllocAreaSize
                      = decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_INT_MAX)
                           / BLOCK_SIZE;
                  break;
573

574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
#ifdef USE_PAPI
	      case 'a':
		switch(rts_argv[arg][2]) {
		case '1':
		  RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L1;
		  break;
		case '2':
		  RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L2;
		  break;
		case 'b':
		  RtsFlags.PapiFlags.eventType = PAPI_FLAG_BRANCH;
		  break;
		case 's':
		  RtsFlags.PapiFlags.eventType = PAPI_FLAG_STALLS;
		  break;
589 590 591
		case 'e':
		  RtsFlags.PapiFlags.eventType = PAPI_FLAG_CB_EVENTS;
		  break;
592
                case '+':
593
                case '#':
594 595 596 597
                  if (RtsFlags.PapiFlags.numUserEvents >= MAX_PAPI_USER_EVENTS) {
                      errorBelch("maximum number of PAPI events reached");
                      stg_exit(EXIT_FAILURE);
                  }
598 599 600 601 602
                  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;
603
                  RtsFlags.PapiFlags.eventType = PAPI_USER_EVENTS;
604
                  RtsFlags.PapiFlags.userEventsKind[eventNum] = eventKind;
605
                  break;
606 607 608 609 610 611
		default:
		  bad_option( rts_argv[arg] );
		}
		break;
#endif

612 613 614 615
	      case 'B':
		RtsFlags.GcFlags.ringBell = rtsTrue;
		break;

616
	      case 'c':
617 618 619 620
		  if (rts_argv[arg][2] != '\0') {
		      RtsFlags.GcFlags.compactThreshold =
			  atof(rts_argv[arg]+2);
		  } else {
621
		      RtsFlags.GcFlags.compact = rtsTrue;
622 623
		  }
		  break;
624

625 626 627 628
              case 'w':
		RtsFlags.GcFlags.sweep = rtsTrue;
		break;

629 630 631 632 633 634 635
	      case 'F':
	        RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
	      
		if (RtsFlags.GcFlags.oldGenFactor < 0)
		  bad_option( rts_argv[arg] );
		break;
	      
636
	      case 'D':
637
              DEBUG_BUILD_ONLY(
638 639 640 641 642 643 644 645
	      { 
		  char *c;

		  for (c  = rts_argv[arg] + 2; *c != '\0'; c++) {
		      switch (*c) {
		      case 's':
			  RtsFlags.DebugFlags.scheduler = rtsTrue;
			  break;
646 647
		      case 'i':
			  RtsFlags.DebugFlags.interpreter = rtsTrue;
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
			  break;
		      case 'w':
			  RtsFlags.DebugFlags.weak = rtsTrue;
			  break;
		      case 'G':
			  RtsFlags.DebugFlags.gccafs = rtsTrue;
			  break;
		      case 'g':
			  RtsFlags.DebugFlags.gc = rtsTrue;
			  break;
		      case 'b':
			  RtsFlags.DebugFlags.block_alloc = rtsTrue;
			  break;
		      case 'S':
			  RtsFlags.DebugFlags.sanity = rtsTrue;
			  break;
		      case 't':
			  RtsFlags.DebugFlags.stable = rtsTrue;
			  break;
		      case 'p':
			  RtsFlags.DebugFlags.prof = rtsTrue;
			  break;
		      case 'l':
			  RtsFlags.DebugFlags.linker = rtsTrue;
			  break;
673 674 675
		      case 'a':
			  RtsFlags.DebugFlags.apply = rtsTrue;
			  break;
676 677 678
		      case 'm':
			  RtsFlags.DebugFlags.stm = rtsTrue;
			  break;
679 680 681
		      case 'z':
			  RtsFlags.DebugFlags.squeeze = rtsTrue;
			  break;
682 683 684
		      case 'c':
			  RtsFlags.DebugFlags.hpc = rtsTrue;
			  break;
685 686 687
		      case 'r':
			  RtsFlags.DebugFlags.sparks = rtsTrue;
			  break;
688 689 690 691
		      default:
			  bad_option( rts_argv[arg] );
		      }
		  }
692 693
                  // -Dx also turns on -v.  Use -l to direct trace
                  // events to the .eventlog file instead.
694
                  RtsFlags.TraceFlags.tracing = TRACE_STDERR;
695 696
	      })
              break;
697 698

	      case 'K':
699
                  RtsFlags.GcFlags.maxStkSize =
700
                      decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
701
                  break;
702 703

	      case 'k':
704 705 706 707 708 709 710 711 712 713 714 715 716 717
		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:
718
                  RtsFlags.GcFlags.initialStkSize =
719
                      decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
720
                  break;
721 722
                }
                break;
723

724
              case 'M':
725 726 727 728
                  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;
729 730

	      case 'm':
731
                  RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
732

733 734 735 736
                  if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
                      RtsFlags.GcFlags.pcFreeHeap > 100)
                      bad_option( rts_argv[arg] );
                  break;
737

738
	      case 'G':
739 740 741
                  RtsFlags.GcFlags.generations =
                      decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
                  break;
742

743
	      case 'H':
744 745 746 747 748 749 750
                  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;
751

752 753 754 755 756 757
#ifdef RTS_GTK_FRONTPANEL
	      case 'f':
		  RtsFlags.GcFlags.frontpanel = rtsTrue;
		  break;
#endif

758 759 760 761 762 763
    	      case 'I':	/* idle GC delay */
		if (rts_argv[arg][2] == '\0') {
		  /* use default */
		} else {
		    I_ cst; /* tmp */

764
		    /* Convert to millisecs */
765
		    cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
766
		    RtsFlags.GcFlags.idleGCDelayTime = cst;
767 768 769
		}
		break;

770
	      case 'S':
771 772
		  RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
		  goto stats;
773

774
	      case 's':
775 776
		  RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
		  goto stats;
777 778

	      case 't':
779 780
		  RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
		  goto stats;
781

782
	    stats:
783 784 785
		{ 
		    int r;
		    r = open_stats_file(arg, *argc, argv,
786
					*rts_argc, rts_argv, NULL,
787 788 789
					&RtsFlags.GcFlags.statsFile);
		    if (r == -1) { error = rtsTrue; }
		}
Simon Marlow's avatar
Simon Marlow committed
790
                break;
791 792 793 794 795 796 797 798 799

	      case 'Z':
		RtsFlags.GcFlags.squeezeUpdFrames = rtsFalse;
		break;

	      /* =========== PROFILING ========================== */

	      case 'P': /* detailed cost centre profiling (time/alloc) */
	      case 'p': /* cost centre profiling (time/alloc) */
Simon Marlow's avatar
Simon Marlow committed
800
		PROFILING_BUILD_ONLY(
801
		switch (rts_argv[arg][2]) {
802 803
		  case 'x':
		    RtsFlags.CcFlags.doCostCentres = COST_CENTRES_XML;
804
		    break;
andy's avatar
andy committed
805 806 807
		  case 'a':
		    RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
		    break;
808
		  default:
809 810 811 812 813 814 815 816
		      if (rts_argv[arg][1] == 'P') {
			  RtsFlags.CcFlags.doCostCentres =
			      COST_CENTRES_VERBOSE;
		      } else {
			  RtsFlags.CcFlags.doCostCentres =
			      COST_CENTRES_SUMMARY;
		      }
		      break;
817 818 819
		}
		) break;

820 821 822 823
	      case 'R':
		  PROFILING_BUILD_ONLY(
		      RtsFlags.ProfFlags.maxRetainerSetSize = atof(rts_argv[arg]+2);
  	          ) break;
ravi@bluespec.com's avatar
ravi@bluespec.com committed
824 825 826 827 828 829 830
	      case 'L':
		  PROFILING_BUILD_ONLY(
		      RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
                      if(RtsFlags.ProfFlags.ccsLength <= 0) {
			bad_option(rts_argv[arg]);
                      }
		  ) break;
831
	      case 'h': /* serial heap profile */
832
#if !defined(PROFILING)
833 834 835 836 837 838
		switch (rts_argv[arg][2]) {
		  case '\0':
		  case 'T':
		    RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
		    break;
		  default:
839
		    errorBelch("invalid heap profile option: %s",rts_argv[arg]);
840 841 842 843 844
		    error = rtsTrue;
		}
#else
		PROFILING_BUILD_ONLY(
		switch (rts_argv[arg][2]) {
845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
		case '\0':
		case 'C':
		case 'c':
		case 'M':
		case 'm':
		case 'D':
		case 'd':
		case 'Y':
		case 'y':
		case 'R':
		case 'r':
		case 'B':
		case 'b':
		    if (rts_argv[arg][2] != '\0' && rts_argv[arg][3] != '\0') {
			{
			    char *left  = strchr(rts_argv[arg], '{');
			    char *right = strrchr(rts_argv[arg], '}');
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878

			    // curly braces are optional, for
			    // backwards compat.
			    if (left)
				left = left+1;
			    else
				left = rts_argv[arg] + 3;

			    if (!right)
				right = rts_argv[arg] + strlen(rts_argv[arg]);

			    *right = '\0';

			    switch (rts_argv[arg][2]) {
			    case 'c': // cost centre label select
				RtsFlags.ProfFlags.ccSelector = left;
				break;
879 880 881
			    case 'C':
				RtsFlags.ProfFlags.ccsSelector = left;
				break;
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
			    case 'M':
			    case 'm': // cost centre module select
				RtsFlags.ProfFlags.modSelector = left;
				break;
			    case 'D':
			    case 'd': // closure descr select 
				RtsFlags.ProfFlags.descrSelector = left;
				break;
			    case 'Y':
			    case 'y': // closure type select
				RtsFlags.ProfFlags.typeSelector = left;
				break;
			    case 'R':
			    case 'r': // retainer select
				RtsFlags.ProfFlags.retainerSelector = left;
				break;
			    case 'B':
			    case 'b': // biography select
				RtsFlags.ProfFlags.bioSelector = left;
				break;
902 903 904 905
			    }
			}
			break;
		    }
906

907
		    if (RtsFlags.ProfFlags.doHeapProfile != 0) {
908
			errorBelch("multiple heap profile options");
909 910 911 912 913 914 915 916 917 918 919 920
			error = rtsTrue;
			break;
		    }

		    switch (rts_argv[arg][2]) {
		    case '\0':
		    case 'C':
		    case 'c':
			RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
			break;
		    case 'M':
		    case 'm':
921 922
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
			  break;
923 924
		    case 'D':
		    case 'd':
925 926
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
			  break;
927 928
		    case 'Y':
		    case 'y':
929 930
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
			  break;
931 932
		    case 'R':
		    case 'r':
933 934
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
			  break;
935 936
		    case 'B':
		    case 'b':
937 938
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
			  break;
939 940
		    }
		    break;
941
		      
942
		default:
943
		    errorBelch("invalid heap profile option: %s",rts_argv[arg]);
944 945 946
		    error = rtsTrue;
		}
		) 
947
#endif /* PROFILING */
andy's avatar
andy committed
948 949 950 951 952 953 954 955 956 957
    	    	break;

    	      case 'i':	/* heap sample interval */
		if (rts_argv[arg][2] == '\0') {
		  /* use default */
		} else {
		    I_ cst; /* tmp */

		    /* Convert to milliseconds */
		    cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
958
		    RtsFlags.ProfFlags.profileInterval = cst;
andy's avatar
andy committed
959 960
		}
		break;
961 962 963 964 965 966 967 968 969 970 971 972 973 974

	      /* =========== CONCURRENT ========================= */
    	      case 'C':	/* context switch interval */
		if (rts_argv[arg][2] == '\0')
    	    	    RtsFlags.ConcFlags.ctxtSwitchTime = 0;
		else {
		    I_ cst; /* tmp */

		    /* Convert to milliseconds */
		    cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
		    RtsFlags.ConcFlags.ctxtSwitchTime = cst;
		}
    	    	break;