RtsFlags.c 37.9 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 12 13
#include "Rts.h"
#include "RtsFlags.h"
#include "RtsUtils.h"
14
#include "Profiling.h"
15

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

20 21 22
#include <stdlib.h>
#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 56 57 58 59 60 61 62 63 64 65 66

static I_ decode(const char *s);
static void bad_option(const char *s);

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

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

67
    RtsFlags.GcFlags.maxStkSize		= (8 * 1024 * 1024) / sizeof(W_);
68 69
    RtsFlags.GcFlags.initialStkSize	= 1024 / sizeof(W_);

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

87 88 89 90 91 92 93 94 95 96 97 98
#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

99 100
#ifdef DEBUG
    RtsFlags.DebugFlags.scheduler	= rtsFalse;
101
    RtsFlags.DebugFlags.interpreter	= rtsFalse;
102 103 104 105 106 107
    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;
108
    RtsFlags.DebugFlags.stm             = rtsFalse;
109
    RtsFlags.DebugFlags.prof		= rtsFalse;
Simon Marlow's avatar
Simon Marlow committed
110
    RtsFlags.DebugFlags.eventlog        = rtsFalse;
111
    RtsFlags.DebugFlags.apply		= rtsFalse;
112
    RtsFlags.DebugFlags.linker		= rtsFalse;
113
    RtsFlags.DebugFlags.squeeze		= rtsFalse;
114
    RtsFlags.DebugFlags.hpc		= rtsFalse;
Simon Marlow's avatar
Simon Marlow committed
115
    RtsFlags.DebugFlags.timestamp	= rtsFalse;
116 117
#endif

Simon Marlow's avatar
Simon Marlow committed
118
#if defined(PROFILING)
119
    RtsFlags.CcFlags.doCostCentres	= 0;
Simon Marlow's avatar
Simon Marlow committed
120
#endif /* PROFILING */
121

122
    RtsFlags.ProfFlags.doHeapProfile      = rtsFalse;
123
    RtsFlags.ProfFlags.profileInterval    = 100;
124 125

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

Simon Marlow's avatar
Simon Marlow committed
139 140 141 142
#ifdef EVENTLOG
    RtsFlags.EventLogFlags.doEventLogging = rtsFalse;
#endif

143 144
    RtsFlags.MiscFlags.tickInterval	= 20;  /* In milliseconds */
    RtsFlags.ConcFlags.ctxtSwitchTime	= 20;  /* In milliseconds */
145

146
    RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
Ian Lynagh's avatar
Ian Lynagh committed
147
    RtsFlags.MiscFlags.machineReadable = rtsFalse;
148
    RtsFlags.MiscFlags.linkerMemBase    = 0;
149

150
#ifdef THREADED_RTS
151
    RtsFlags.ParFlags.nNodes	        = 1;
152 153
    RtsFlags.ParFlags.migrate           = rtsTrue;
    RtsFlags.ParFlags.wakeupMigrate     = rtsFalse;
154 155
    RtsFlags.ParFlags.parGcEnabled      = 1;
    RtsFlags.ParFlags.parGcGen          = 1;
156
    RtsFlags.ParFlags.parGcLoadBalancing = 1;
157
    RtsFlags.ParFlags.setAffinity       = 0;
158
#endif
159

Simon Marlow's avatar
Simon Marlow committed
160
#if defined(THREADED_RTS)
161
    RtsFlags.ParFlags.maxLocalSparks	= 4096;
Simon Marlow's avatar
Simon Marlow committed
162
#endif /* THREADED_RTS */
163 164

#ifdef TICKY_TICKY
165 166
    RtsFlags.TickyFlags.showTickyStats	 = rtsFalse;
    RtsFlags.TickyFlags.tickyFile	 = NULL;
167
#endif
Simon Marlow's avatar
Simon Marlow committed
168

169
#ifdef USE_PAPI
170 171
    /* By default no special measurements taken */
    RtsFlags.PapiFlags.eventType        = 0;
172
    RtsFlags.PapiFlags.numUserEvents    = 0;
173
#endif
174 175 176 177 178 179 180 181 182 183 184 185 186 187
}

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:",
"",
188
"  -?       Prints this message and exits; the program is not executed",
189
"  --info   Print information about the RTS used by this program",
190
"",
191
"  -K<size> Sets the maximum stack size (default 8M)  Egs: -K32k   -K512k",
sof's avatar
sof committed
192
"  -k<size> Sets the initial thread stack size (default 1k)  Egs: -k4k   -k2m",
193
"",
194
"  -A<size> Sets the minimum allocation area size (default 512k) Egs: -A1m -A10k",
195
"  -M<size> Sets the maximum heap size (default unlimited)  Egs: -M256k -M1G",
196
"  -H<size> Sets the minimum heap size (default 0M)   Egs: -H24m  -H1G",
197
"  -m<n>    Minimum % of heap which must be available (default 3%)",
198
"  -G<n>    Number of generations (default: 2)",
199
"  -T<n>    Number of steps in younger generations (default: 2)",
200 201
"  -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%)",
202
"  -c       Enable compaction for all major collections",
203
"  -w       Use mark-region for the oldest generation (experimental)",
204
#if defined(THREADED_RTS)
205 206
"  -I<sec>  Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
#endif
207
"",
208 209 210
"  -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)",
211 212 213
#ifdef RTS_GTK_FRONTPANEL
"  -f       Display front panel (requires X11 & GTK+)",
#endif
214 215 216 217
"",
"",
"  -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
218
#if defined(PROFILING)
219
"",
220
"  -px      Time/allocation profile (XML)  (output file <program>.prof)",
andy's avatar
andy committed
221 222 223
"  -p       Time/allocation profile        (output file <program>.prof)",
"  -P       More detailed Time/Allocation profile",
"  -Pa      Give information about *all* cost centres",
224

225 226
# if defined(PROFILING)
"",
227 228 229 230 231 232 233 234
"  -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)",
235
"  A subset of closures may be selected thusly:",
236 237
"    -hc<cc>,...  specific cost centre(s) (top of stack only)",
"    -hC<cc>,...  specific cost centre(s) (anywhere in stack)",
238 239 240 241 242
"    -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)",
243 244
"",
"  -R<size>       Set the maximum retainer set size (default: 8)",
ravi@bluespec.com's avatar
ravi@bluespec.com committed
245 246 247
"", 
"  -L<chars>      Maximum length of a cost-centre stack in a heap profile",
"                 (default: 25)",
248
"",
249 250
"  -xt            Include threads (TSOs) in a heap profile",
"",
251
"  -xc      Show current cost centre stack on raising an exception",
252
"",
253 254
# endif
#endif /* PROFILING or PAR */
Simon Marlow's avatar
Simon Marlow committed
255 256 257 258 259 260 261

#ifdef EVENTLOG
"",
"  -l       Log runtime events (generates binary trace file <program>.eventlog)",
"",
#endif

262
#if !defined(PROFILING)
263
"",
264
"  -hT      Heap residency profile (output file <program>.hp)",
265
#endif
266
"  -i<sec>  Time between heap samples (seconds, default: 0.1)",
267 268
"",
#if defined(TICKY_TICKY)
269
"  -r<file>  Produce ticky-ticky statistics (with -rstderr for stderr)",
270 271
"",
#endif
272 273 274
"  -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.",
275
"  -V<secs>  Master tick interval in seconds (0 == disable timer).",
276 277
"            This sets the resolution for -C and the profile timer -i.",
"            Default: 0.02 sec.",
278
"",
Simon Marlow's avatar
Simon Marlow committed
279
"  -vt       Time-stamp debug messages",
Simon Marlow's avatar
Simon Marlow committed
280
"",
281 282
#if defined(DEBUG)
"  -Ds  DEBUG: scheduler",
283
"  -Di  DEBUG: interpreter",
284 285 286 287 288 289 290
"  -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
291
"  -De  DEBUG: event logging",
292
"  -Da  DEBUG: apply",
293
"  -Dl  DEBUG: linker",
294
"  -Dm  DEBUG: stm",
295
"  -Dz  DEBUG: stack squezing",
296
"  -Dc  DEBUG: program coverage",
297
"",
298
#endif /* DEBUG */
299
#if defined(THREADED_RTS) && !defined(NOSMP)
300 301
"  -N<n>     Use <n> processors (default: 1)",
"  -N        Determine the number of processors to use automatically",
302 303
"  -q1       Use one OS thread for GC (turns off parallel GC)",
"  -qg<n>    Use parallel GC only for generations >= <n> (default: 1)",
304 305
"  -qb       Disable load-balancing in the parallel GC",
"  -qa       Use the OS to set thread affinity",
306 307
"  -qm       Don't automatically migrate threads between CPUs",
"  -qw       Migrate a thread to the current CPU when it is woken up",
308
#endif
309 310
"  --install-signal-handlers=<yes|no>",
"            Install signal handlers (default: yes)",
Simon Marlow's avatar
Simon Marlow committed
311
#if defined(THREADED_RTS)
312 313
"  -e<size>  Size of spark pools (default 100)",
#endif
Simon Marlow's avatar
Simon Marlow committed
314
#if defined(THREADED_RTS)
315 316
"  -e<n>     Maximum number of outstanding local sparks (default: 4096)",
#endif
317 318 319 320
#if defined(x86_64_HOST_ARCH)
"  -xm       Base address to mmap memory in the GHCi linker",
"            (hex; must be <80000000)",
#endif
321
#if defined(USE_PAPI)
322 323
"  -aX       CPU performance counter measurements using PAPI",
"            (use with the -s<file> option).  X is one of:",
324 325 326 327 328 329
"",
/* "            y - cycles", */
"            1 - level 1 cache misses",
"            2 - level 2 cache misses",
"            b - branch mispredictions",
"            s - stalled cycles",
330
"            e - cache miss and branch misprediction events",
331
#endif
332
"",
333 334
"RTS options may also be specified using the GHCRTS environment variable.",
"",
335 336 337 338 339 340
"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
341
STATIC_INLINE rtsBool
342 343 344 345 346
strequal(const char *a, const char * b)
{
    return(strcmp(a, b) == 0);
}

347 348 349 350 351 352 353 354 355 356 357 358 359 360
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
361
	    s = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
362 363 364 365 366 367 368 369 370 371 372
	    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');
}
    
373 374 375 376 377 378 379
void
setupRtsFlags(int *argc, char *argv[], int *rts_argc, char *rts_argv[])
{
    rtsBool error = rtsFalse;
    I_ mode;
    I_ arg, total_arg;

380
    setProgName (argv);
381 382 383 384 385 386
    total_arg = *argc;
    arg = 1;

    *argc = 1;
    *rts_argc = 0;

387 388 389 390 391 392 393 394 395
    // 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);
	}
    }

396
    // process arguments from the GHCRTS environment variable next
397
    // (arguments from the command line override these).
398 399 400 401
    {
	char *ghc_rts = getenv("GHCRTS");

	if (ghc_rts != NULL) {
402
	    splitRtsFlags(ghc_rts, rts_argc, rts_argv);
403 404
	}
    }
405

406 407 408
    // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
    //   argv[0] must be PGM argument -- leave in argv

409 410 411 412 413 414 415 416 417 418 419 420
    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])) {
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
	    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) {
	    argv[(*argc)++] = argv[arg];
	}
	else {
	  barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
	}
    }
436 437 438
    // process remaining program arguments
    for (; arg < total_arg; arg++) {
	argv[(*argc)++] = argv[arg];
439 440 441 442 443
    }
    argv[*argc] = (char *) 0;
    rts_argv[*rts_argc] = (char *) 0;

    // Process RTS (rts_argv) part: mainly to determine statsfile
444 445 446
    for (arg = 0; arg < *rts_argc; arg++) {
	if (rts_argv[arg][0] != '-') {
	    fflush(stdout);
447
	    errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
448 449 450 451 452
	    error = rtsTrue;

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

Simon Marlow's avatar
Simon Marlow committed
453 454 455 456 457
	      /* 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.
458 459 460 461 462 463
	      */

#ifdef TICKY_TICKY
# define TICKY_BUILD_ONLY(x) x
#else
# define TICKY_BUILD_ONLY(x) \
464
errorBelch("not built for: ticky-ticky stats"); \
465 466 467 468 469 470 471
error = rtsTrue;
#endif

#ifdef PROFILING
# define PROFILING_BUILD_ONLY(x)   x
#else
# define PROFILING_BUILD_ONLY(x) \
472
errorBelch("not built for: -prof"); \
473 474 475
error = rtsTrue;
#endif

Simon Marlow's avatar
Simon Marlow committed
476 477 478 479 480 481 482 483
#ifdef EVENTLOG
# define EVENTLOG_BUILD_ONLY(x)   x
#else
# define EVENTLOG_BUILD_ONLY(x) \
errorBelch("not built for: -par-prof"); \
error = rtsTrue;
#endif

484 485 486 487 488 489
#ifdef THREADED_RTS
# define THREADED_BUILD_ONLY(x)      x
#else
# define THREADED_BUILD_ONLY(x) \
errorBelch("not built for: -smp"); \
error = rtsTrue;
490 491 492 493 494 495 496
#endif

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

497 498 499 500 501 502 503 504 505 506 507 508
              /* 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
509 510 511 512
                  else if (strequal("machine-readable",
                               &rts_argv[arg][2])) {
                      RtsFlags.MiscFlags.machineReadable = rtsTrue;
                  }
513 514
                  else if (strequal("info",
                               &rts_argv[arg][2])) {
515
                      printRtsInfo();
516 517
                      exit(0);
                  }
518 519 520 521 522
                  else {
		      errorBelch("unknown RTS option: %s",rts_argv[arg]);
		      error = rtsTrue;
                  }
		  break;
523 524 525 526 527 528 529 530
	      case 'A':
		RtsFlags.GcFlags.minAllocAreaSize
		  = decode(rts_argv[arg]+2) / BLOCK_SIZE;
		if (RtsFlags.GcFlags.minAllocAreaSize <= 0) {
		  bad_option(rts_argv[arg]);
		}
		break;

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
#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;
546 547 548
		case 'e':
		  RtsFlags.PapiFlags.eventType = PAPI_FLAG_CB_EVENTS;
		  break;
549 550 551 552 553 554 555 556
                case '+':
                  if (RtsFlags.PapiFlags.numUserEvents >= MAX_PAPI_USER_EVENTS) {
                      errorBelch("maximum number of PAPI events reached");
                      stg_exit(EXIT_FAILURE);
                  }
                  RtsFlags.PapiFlags.eventType = PAPI_USER_EVENTS;
                  RtsFlags.PapiFlags.userEvents[RtsFlags.PapiFlags.numUserEvents++] = rts_argv[arg] + 3;
                  break;
557 558 559 560 561 562
		default:
		  bad_option( rts_argv[arg] );
		}
		break;
#endif

563 564 565 566
	      case 'B':
		RtsFlags.GcFlags.ringBell = rtsTrue;
		break;

567
	      case 'c':
568 569 570 571
		  if (rts_argv[arg][2] != '\0') {
		      RtsFlags.GcFlags.compactThreshold =
			  atof(rts_argv[arg]+2);
		  } else {
572
		      RtsFlags.GcFlags.compact = rtsTrue;
573 574
		  }
		  break;
575

576 577 578 579
              case 'w':
		RtsFlags.GcFlags.sweep = rtsTrue;
		break;

580 581 582 583 584 585 586
	      case 'F':
	        RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
	      
		if (RtsFlags.GcFlags.oldGenFactor < 0)
		  bad_option( rts_argv[arg] );
		break;
	      
587 588
#ifdef DEBUG
	      case 'D':
589 590 591 592 593 594 595 596
	      { 
		  char *c;

		  for (c  = rts_argv[arg] + 2; *c != '\0'; c++) {
		      switch (*c) {
		      case 's':
			  RtsFlags.DebugFlags.scheduler = rtsTrue;
			  break;
597 598
		      case 'i':
			  RtsFlags.DebugFlags.interpreter = rtsTrue;
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
			  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;
Simon Marlow's avatar
Simon Marlow committed
621 622 623
		      case 'e':
			  RtsFlags.DebugFlags.eventlog = rtsTrue;
                          break;
624 625 626
		      case 'l':
			  RtsFlags.DebugFlags.linker = rtsTrue;
			  break;
627 628 629
		      case 'a':
			  RtsFlags.DebugFlags.apply = rtsTrue;
			  break;
630 631 632
		      case 'm':
			  RtsFlags.DebugFlags.stm = rtsTrue;
			  break;
633 634 635
		      case 'z':
			  RtsFlags.DebugFlags.squeeze = rtsTrue;
			  break;
636 637 638
		      case 'c':
			  RtsFlags.DebugFlags.hpc = rtsTrue;
			  break;
639 640 641 642 643 644
		      default:
			  bad_option( rts_argv[arg] );
		      }
		  }
		  break;
	      }
645 646 647 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 673 674 675 676 677 678 679 680
#endif

	      case 'K':
		RtsFlags.GcFlags.maxStkSize = 
		  decode(rts_argv[arg]+2) / sizeof(W_);

		if (RtsFlags.GcFlags.maxStkSize == 0) 
		  bad_option( rts_argv[arg] );
		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* */

		if (RtsFlags.GcFlags.maxHeapSize <= 0) {
		  bad_option(rts_argv[arg]);
		}
		break;

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

		if (RtsFlags.GcFlags.pcFreeHeap < 0 || 
		    RtsFlags.GcFlags.pcFreeHeap > 100)
		  bad_option( rts_argv[arg] );
		break;

681 682
	      case 'G':
		RtsFlags.GcFlags.generations = decode(rts_argv[arg]+2);
683
		if (RtsFlags.GcFlags.generations < 1) {
684 685 686 687
		  bad_option(rts_argv[arg]);
		}
		break;

688 689 690 691 692 693 694
	      case 'T':
		RtsFlags.GcFlags.steps = decode(rts_argv[arg]+2);
		if (RtsFlags.GcFlags.steps < 1) {
		  bad_option(rts_argv[arg]);
		}
		break;

695
	      case 'H':
696 697
		RtsFlags.GcFlags.heapSizeSuggestion = 
		  decode(rts_argv[arg]+2) / BLOCK_SIZE;
698 699
		break;

700 701 702 703 704 705
#ifdef RTS_GTK_FRONTPANEL
	      case 'f':
		  RtsFlags.GcFlags.frontpanel = rtsTrue;
		  break;
#endif

706 707 708 709 710 711
    	      case 'I':	/* idle GC delay */
		if (rts_argv[arg][2] == '\0') {
		  /* use default */
		} else {
		    I_ cst; /* tmp */

712
		    /* Convert to millisecs */
713
		    cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
714
		    RtsFlags.GcFlags.idleGCDelayTime = cst;
715 716 717
		}
		break;

718
	      case 'S':
719 720
		  RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
		  goto stats;
721

722
	      case 's':
723 724
		  RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
		  goto stats;
725 726

	      case 't':
727 728
		  RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
		  goto stats;
729

730
	    stats:
731 732 733
		{ 
		    int r;
		    r = open_stats_file(arg, *argc, argv,
734
					*rts_argc, rts_argv, NULL,
735 736 737
					&RtsFlags.GcFlags.statsFile);
		    if (r == -1) { error = rtsTrue; }
		}
Simon Marlow's avatar
Simon Marlow committed
738
                break;
739 740 741 742 743 744 745

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

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

Simon Marlow's avatar
Simon Marlow committed
746 747 748 749 750 751 752 753
              case 'l':
#ifdef EVENTLOG
                  RtsFlags.EventLogFlags.doEventLogging = rtsTrue;
#else
                  errorBelch("not built for: -eventlog");
#endif
                  break;

754 755
	      case 'P': /* detailed cost centre profiling (time/alloc) */
	      case 'p': /* cost centre profiling (time/alloc) */
Simon Marlow's avatar
Simon Marlow committed
756
		PROFILING_BUILD_ONLY(
757
		switch (rts_argv[arg][2]) {
758 759
		  case 'x':
		    RtsFlags.CcFlags.doCostCentres = COST_CENTRES_XML;
760
		    break;
andy's avatar
andy committed
761 762 763
		  case 'a':
		    RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
		    break;
764
		  default:
765 766 767 768 769 770 771 772
		      if (rts_argv[arg][1] == 'P') {
			  RtsFlags.CcFlags.doCostCentres =
			      COST_CENTRES_VERBOSE;
		      } else {
			  RtsFlags.CcFlags.doCostCentres =
			      COST_CENTRES_SUMMARY;
		      }
		      break;
773 774 775
		}
		) break;

776 777 778 779
	      case 'R':
		  PROFILING_BUILD_ONLY(
		      RtsFlags.ProfFlags.maxRetainerSetSize = atof(rts_argv[arg]+2);
  	          ) break;
ravi@bluespec.com's avatar
ravi@bluespec.com committed
780 781 782 783 784 785 786
	      case 'L':
		  PROFILING_BUILD_ONLY(
		      RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
                      if(RtsFlags.ProfFlags.ccsLength <= 0) {
			bad_option(rts_argv[arg]);
                      }
		  ) break;
787
	      case 'h': /* serial heap profile */
788
#if !defined(PROFILING)
789 790 791 792 793 794
		switch (rts_argv[arg][2]) {
		  case '\0':
		  case 'T':
		    RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
		    break;
		  default:
795
		    errorBelch("invalid heap profile option: %s",rts_argv[arg]);
796 797 798 799 800
		    error = rtsTrue;
		}
#else
		PROFILING_BUILD_ONLY(
		switch (rts_argv[arg][2]) {
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
		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], '}');
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834

			    // 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;
835 836 837
			    case 'C':
				RtsFlags.ProfFlags.ccsSelector = left;
				break;
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
			    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;
858 859 860 861
			    }
			}
			break;
		    }
862

863
		    if (RtsFlags.ProfFlags.doHeapProfile != 0) {
864
			errorBelch("multiple heap profile options");
865 866 867 868 869 870 871 872 873 874 875 876
			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':
877 878
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
			  break;
879 880
		    case 'D':
		    case 'd':
881 882
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
			  break;
883 884
		    case 'Y':
		    case 'y':
885 886
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
			  break;
887 888
		    case 'R':
		    case 'r':
889 890
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
			  break;
891 892
		    case 'B':
		    case 'b':
893 894
			  RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
			  break;
895 896
		    }
		    break;
897
		      
898
		default:
899
		    errorBelch("invalid heap profile option: %s",rts_argv[arg]);
900 901 902
		    error = rtsTrue;
		}
		) 
903
#endif /* PROFILING */
andy's avatar
andy committed
904 905 906 907 908 909 910 911 912 913
    	    	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));
914
		    RtsFlags.ProfFlags.profileInterval = cst;
andy's avatar
andy committed
915 916
		}
		break;
917 918 919 920 921 922 923 924 925 926 927 928 929 930

	      /* =========== 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;

931 932 933 934 935 936 937 938 939 940 941 942 943
              case 'V': /* master tick interval */
                if (rts_argv[arg][2] == '\0') {
                    // turns off ticks completely
                    RtsFlags.MiscFlags.tickInterval = 0;
                } else {
                    I_ cst; /* tmp */

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

944
#if defined(THREADED_RTS) && !defined(NOSMP)
945
	      case 'N':
946
		THREADED_BUILD_ONLY(
947 948 949 950
		if (rts_argv[arg][2] == '\0') {
#if defined(PROFILING)
		    RtsFlags.ParFlags.nNodes = 1;
#else
951
                    RtsFlags.ParFlags.nNodes = getNumberOfProcessors();
952 953
#endif
		} else {
954
		    RtsFlags.ParFlags.nNodes
955
		      = strtol(rts_argv[arg]+2, (char **) NULL, 10);
956
		    if (RtsFlags.ParFlags.nNodes <= 0) {
957
		      errorBelch("bad value for -N");
958
		      error = rtsTrue;
959
		    }
Simon Marlow's avatar
Simon Marlow committed
960 961 962 963 964 965
#if defined(PROFILING)
                    if (RtsFlags.ParFlags.nNodes > 1) {
                        errorBelch("bad option %s: only -N1 is supported with profiling", rts_argv[arg]);
		      error = rtsTrue;
                    }
#endif
966 967 968 969 970
		}
		) break;

	      case 'g':
		THREADED_BUILD_ONLY(
971 972 973 974 975 976 977 978 979 980 981
		    switch (rts_argv[arg][2]) {
                    case '1':
                        // backwards compat only
                        RtsFlags.ParFlags.parGcEnabled = rtsFalse;
                        break;
		    default:
			errorBelch("unknown RTS option: %s",rts_argv[arg]);
			error = rtsTrue;
			break;
                    }
                    ) break;
982

Simon Marlow's avatar
Simon Marlow committed
983
	      case 'q':
984 985 986 987 988
		    switch (rts_argv[arg][2]) {
		    case '\0':
			errorBelch("incomplete RTS option: %s",rts_argv[arg]);
			error = rtsTrue;
			break;
989 990 991 992 993 994 995 996 997 998 999 1000
                    case '1':
                        RtsFlags.ParFlags.parGcEnabled = rtsFalse;
                        break;
                    case 'g':
                        if (rts_argv[arg][3] != '\0') {
                            RtsFlags.ParFlags.parGcGen
                                = strtol(rts_argv[arg]+3, (char **) NULL, 10);
                        } else {
                            errorBelch("bad value for -qg");
                            error = rtsTrue;
                        }
                        break;
1001 1002 1003
		    case 'b':
			RtsFlags.ParFlags.parGcLoadBalancing = rtsFalse;
			break;
1004 1005 1006
		    case 'a':
			RtsFlags.ParFlags.setAffinity = rtsTrue;
			break;
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
		    case 'm':
			RtsFlags.ParFlags.migrate = rtsFalse;
			break;
		    case 'w':
			RtsFlags.ParFlags.wakeupMigrate = rtsTrue;
			break;
		    default:
			errorBelch("unknown RTS option: %s",rts_argv[arg]);
			error = rtsTrue;
			break;
		    }
		    break;
1019
#endif
1020 1021
	      /* =========== PARALLEL =========================== */
	      case 'e':
Simon Marlow's avatar
Simon Marlow committed
1022
		THREADED_BUILD_ONLY(
1023
		if (rts_argv[arg][2] != '\0') {
1024 1025 1026
		    RtsFlags.ParFlags.maxLocalSparks
		      = strtol(rts_argv[arg]+2, (char **) NULL, 10);
		    if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
1027
		      errorBelch("bad value for -e");
1028
		      error = rtsTrue;
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
		    }
		}
		) break;

	      /* =========== TICKY ============================== */

	      case 'r': /* Basic profiling stats */
		TICKY_BUILD_ONLY(

		RtsFlags.TickyFlags.showTickyStats = rtsTrue;

1040 1041 1042 1043 1044 1045 1046
		{ 
		    int r;
		    r = open_stats_file(arg, *argc, argv,
					*rts_argc, rts_argv, TICKY_FILENAME_FMT,
					&RtsFlags.TickyFlags.tickyFile);
		    if (r == -1) { error = rtsTrue; }
		}
1047 1048
	        ) break;

Simon Marlow's avatar
Simon Marlow committed
1049 1050 1051 1052 1053 1054 1055 1056 1057
	      /* =========== TRACING ---------=================== */

	      case 'v':
                switch(rts_argv[arg][2]) {
		case '\0':
		    errorBelch("incomplete RTS option: %s",rts_argv[arg]);
		    error = rtsTrue;
		    break;
		case 't':
Simon Marlow's avatar
Simon Marlow committed
1058
		    RtsFlags.DebugFlags.timestamp = rtsTrue;
Simon Marlow's avatar
Simon Marlow committed
1059 1060
		    break;
		case 's':
1061
		case 'g':
Simon Marlow's avatar
Simon Marlow committed
1062
                    // ignored for backwards-compat
1063
		    break;
Simon Marlow's avatar
Simon Marlow committed
1064 1065 1066 1067 1068 1069 1070
		default:
		    errorBelch("unknown RTS option: %s",rts_argv[arg]);
		    error = rtsTrue;
		    break;
		}
                break;

1071 1072 1073 1074 1075
	      /* =========== EXTENDED OPTIONS =================== */

              case 'x': /* Extend the argument space */
                switch(rts_argv[arg][2]) {
                  case '\0':
1076
		    errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1077 1078 1079
		    error = rtsTrue;
		    break;

1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
                case 'b': /* heapBase in hex; undocumented */
                    if (rts_argv[arg][3] != '\0') {
                        RtsFlags.GcFlags.heapBase
                            = strtol(rts_argv[arg]+3, (char **) NULL, 16);
                    } else {
                        errorBelch("-xb: requires argument");
                        error = rtsTrue;
                    }
                    break;

1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
#if defined(x86_64_HOST_ARCH)
                case 'm': /* linkerMemBase */
                    if (rts_argv[arg][3] != '\0') {
                        RtsFlags.MiscFlags.linkerMemBase
                            = strtol(rts_argv[arg]+3, (char **) NULL, 16);
                        if (RtsFlags.MiscFlags.linkerMemBase > 0x80000000) {
                            errorBelch("-xm: value must be <80000000");
                            error = rtsTrue;
                        }
                    } else {
                        RtsFlags.MiscFlags.linkerMemBase = 0;
                    }
                    break;
#endif

                case 'c': /* Debugging tool: show current cost centre on an exception */