RtsFlags.c 46 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
#include "RtsFlags.h"
17

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

22 23
#include <string.h>

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

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

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

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

48 49 50 51 52 53 54 55 56 57 58 59 60
static void procRtsOpts      (int rts_argc0, RtsOptsEnabledEnum enabled);

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);
61

62 63 64
#ifdef TRACING
static void read_trace_flags(char *arg);
#endif
65

66 67
static void errorUsage      (void) GNU_ATTRIBUTE(__noreturn__);

68 69 70 71 72 73 74 75 76
/* -----------------------------------------------------------------------------
 * Command-line option parsing routines.
 * ---------------------------------------------------------------------------*/

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

77
    RtsFlags.GcFlags.maxStkSize		= (8 * 1024 * 1024) / sizeof(W_);
78
    RtsFlags.GcFlags.initialStkSize	= 1024 / sizeof(W_);
79 80
    RtsFlags.GcFlags.stkChunkSize       = (32 * 1024) / sizeof(W_);
    RtsFlags.GcFlags.stkChunkBufferSize = (1 * 1024) / sizeof(W_);
81

82
    RtsFlags.GcFlags.minAllocAreaSize   = (512 * 1024)        / BLOCK_SIZE;
83
    RtsFlags.GcFlags.minOldGenSize      = (1024 * 1024)       / BLOCK_SIZE;
84
    RtsFlags.GcFlags.maxHeapSize	= 0;    /* off by default */
85
    RtsFlags.GcFlags.heapSizeSuggestion	= 0;    /* none */
86
    RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsFalse;
87
    RtsFlags.GcFlags.pcFreeHeap		= 3;	/* 3% */
88
    RtsFlags.GcFlags.oldGenFactor       = 2;
89
    RtsFlags.GcFlags.generations        = 2;
90
    RtsFlags.GcFlags.squeezeUpdFrames	= rtsTrue;
91
    RtsFlags.GcFlags.compact            = rtsFalse;
92
    RtsFlags.GcFlags.compactThreshold   = 30.0;
93
    RtsFlags.GcFlags.sweep              = rtsFalse;
94 95 96
#ifdef RTS_GTK_FRONTPANEL
    RtsFlags.GcFlags.frontpanel         = rtsFalse;
#endif
97
    RtsFlags.GcFlags.idleGCDelayTime    = 300; /* millisecs */
98

99 100 101 102 103 104 105 106 107 108 109 110
#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

111 112
#ifdef DEBUG
    RtsFlags.DebugFlags.scheduler	= rtsFalse;
113
    RtsFlags.DebugFlags.interpreter	= rtsFalse;
114 115 116 117 118 119
    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;
120
    RtsFlags.DebugFlags.stm             = rtsFalse;
121
    RtsFlags.DebugFlags.prof		= rtsFalse;
122
    RtsFlags.DebugFlags.apply		= rtsFalse;
123
    RtsFlags.DebugFlags.linker		= rtsFalse;
124
    RtsFlags.DebugFlags.squeeze		= rtsFalse;
125
    RtsFlags.DebugFlags.hpc		= rtsFalse;
126
    RtsFlags.DebugFlags.sparks		= rtsFalse;
127 128
#endif

Simon Marlow's avatar
Simon Marlow committed
129
#if defined(PROFILING)
130
    RtsFlags.CcFlags.doCostCentres	= 0;
Simon Marlow's avatar
Simon Marlow committed
131
#endif /* PROFILING */
132

133
    RtsFlags.ProfFlags.doHeapProfile      = rtsFalse;
134
    RtsFlags.ProfFlags.profileInterval    = 100;
135 136

#ifdef PROFILING
137
    RtsFlags.ProfFlags.includeTSOs        = rtsFalse;
138
    RtsFlags.ProfFlags.showCCSOnException = rtsFalse;
139
    RtsFlags.ProfFlags.maxRetainerSetSize = 8;
ravi@bluespec.com's avatar
ravi@bluespec.com committed
140
    RtsFlags.ProfFlags.ccsLength          = 25;
141 142 143 144
    RtsFlags.ProfFlags.modSelector        = NULL;
    RtsFlags.ProfFlags.descrSelector      = NULL;
    RtsFlags.ProfFlags.typeSelector       = NULL;
    RtsFlags.ProfFlags.ccSelector         = NULL;
145
    RtsFlags.ProfFlags.ccsSelector        = NULL;
146 147
    RtsFlags.ProfFlags.retainerSelector   = NULL;
    RtsFlags.ProfFlags.bioSelector        = NULL;
148 149
#endif

150
#ifdef TRACING
151
    RtsFlags.TraceFlags.tracing       = TRACE_NONE;
152 153
    RtsFlags.TraceFlags.timestamp     = rtsFalse;
    RtsFlags.TraceFlags.scheduler     = rtsFalse;
Simon Marlow's avatar
Simon Marlow committed
154 155
#endif

156 157
    RtsFlags.MiscFlags.tickInterval	= 20;  /* In milliseconds */
    RtsFlags.ConcFlags.ctxtSwitchTime	= 20;  /* In milliseconds */
158

159
    RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
Ian Lynagh's avatar
Ian Lynagh committed
160
    RtsFlags.MiscFlags.machineReadable = rtsFalse;
161
    RtsFlags.MiscFlags.linkerMemBase    = 0;
162

163
#ifdef THREADED_RTS
164
    RtsFlags.ParFlags.nNodes	        = 1;
165
    RtsFlags.ParFlags.migrate           = rtsTrue;
166
    RtsFlags.ParFlags.parGcEnabled      = 1;
167 168 169
    RtsFlags.ParFlags.parGcGen          = 0;
    RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsTrue;
    RtsFlags.ParFlags.parGcLoadBalancingGen = 1;
170
    RtsFlags.ParFlags.setAffinity       = 0;
171
#endif
172

Simon Marlow's avatar
Simon Marlow committed
173
#if defined(THREADED_RTS)
174
    RtsFlags.ParFlags.maxLocalSparks	= 4096;
Simon Marlow's avatar
Simon Marlow committed
175
#endif /* THREADED_RTS */
176 177

#ifdef TICKY_TICKY
178 179
    RtsFlags.TickyFlags.showTickyStats	 = rtsFalse;
    RtsFlags.TickyFlags.tickyFile	 = NULL;
180
#endif
Simon Marlow's avatar
Simon Marlow committed
181

182
#ifdef USE_PAPI
183 184
    /* By default no special measurements taken */
    RtsFlags.PapiFlags.eventType        = 0;
185
    RtsFlags.PapiFlags.numUserEvents    = 0;
186
#endif
187 188 189 190 191 192 193 194 195 196 197 198 199 200
}

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:",
"",
201
"  -?       Prints this message and exits; the program is not executed",
202
"  --info   Print information about the RTS used by this program",
203
"",
204
"  -K<size> Sets the maximum stack size (default 8M)  Egs: -K32k   -K512k",
205 206 207
"  -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)",
208
"",
209
"  -A<size> Sets the minimum allocation area size (default 512k) Egs: -A1m -A10k",
210
"  -M<size> Sets the maximum heap size (default unlimited)  Egs: -M256k -M1G",
211
"  -H<size> Sets the minimum heap size (default 0M)   Egs: -H24m  -H1G",
212
"  -m<n>    Minimum % of heap which must be available (default 3%)",
213
"  -G<n>    Number of generations (default: 2)",
214 215 216 217 218
"  -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)",
219
"  -w       Use mark-region for the oldest generation (experimental)",
220
#if defined(THREADED_RTS)
221 222
"  -I<sec>  Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
#endif
223
"",
224 225 226
"  -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)",
227 228 229
#ifdef RTS_GTK_FRONTPANEL
"  -f       Display front panel (requires X11 & GTK+)",
#endif
230 231 232 233
"",
"",
"  -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
234
#if defined(PROFILING)
235
"",
236
"  -px      Time/allocation profile (XML)  (output file <program>.prof)",
andy's avatar
andy committed
237 238 239
"  -p       Time/allocation profile        (output file <program>.prof)",
"  -P       More detailed Time/Allocation profile",
"  -Pa      Give information about *all* cost centres",
240

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

271
#ifdef TRACING
Simon Marlow's avatar
Simon Marlow committed
272
"",
273 274 275 276 277 278 279 280 281
"  -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
282 283
#endif

284
#if !defined(PROFILING)
285
"",
286
"  -hT      Heap residency profile (output file <program>.hp)",
287
#endif
288
"  -i<sec>  Time between heap samples (seconds, default: 0.1)",
289 290
"",
#if defined(TICKY_TICKY)
291
"  -r<file>  Produce ticky-ticky statistics (with -rstderr for stderr)",
292 293
"",
#endif
294 295 296
"  -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.",
297
"  -V<secs>  Master tick interval in seconds (0 == disable timer).",
298 299
"            This sets the resolution for -C and the profile timer -i.",
"            Default: 0.02 sec.",
300 301 302
"",
#if defined(DEBUG)
"  -Ds  DEBUG: scheduler",
303
"  -Di  DEBUG: interpreter",
304 305 306 307 308 309 310
"  -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
311
"  -De  DEBUG: event logging",
312
"  -Da  DEBUG: apply",
313
"  -Dl  DEBUG: linker",
314
"  -Dm  DEBUG: stm",
Simon Marlow's avatar
Simon Marlow committed
315
"  -Dz  DEBUG: stack squeezing",
316
"  -Dc  DEBUG: program coverage",
317 318
"  -Dr  DEBUG: sparks",
"",
319
"     NOTE: DEBUG events are sent to stderr by default; add -l to create a",
320
"     binary event log file instead.",
321
"",
322
#endif /* DEBUG */
323
#if defined(THREADED_RTS) && !defined(NOSMP)
324 325
"  -N<n>     Use <n> processors (default: 1)",
"  -N        Determine the number of processors to use automatically",
326 327 328 329 330
"  -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)",
331
"  -qm       Don't automatically migrate threads between CPUs",
332
#endif
333 334
"  --install-signal-handlers=<yes|no>",
"            Install signal handlers (default: yes)",
Simon Marlow's avatar
Simon Marlow committed
335
#if defined(THREADED_RTS)
336 337
"  -e<n>     Maximum number of outstanding local sparks (default: 4096)",
#endif
338 339 340 341
#if defined(x86_64_HOST_ARCH)
"  -xm       Base address to mmap memory in the GHCi linker",
"            (hex; must be <80000000)",
#endif
342
#if defined(USE_PAPI)
343 344
"  -aX       CPU performance counter measurements using PAPI",
"            (use with the -s<file> option).  X is one of:",
345 346 347 348 349 350
"",
/* "            y - cycles", */
"            1 - level 1 cache misses",
"            2 - level 2 cache misses",
"            b - branch mispredictions",
"            s - stalled cycles",
351
"            e - cache miss and branch misprediction events",
352 353
"            +PAPI_EVENT   - collect papi preset event PAPI_EVENT",
"            #NATIVE_EVENT - collect native event NATIVE_EVENT (in hex)",
354
#endif
355
"",
356 357
"RTS options may also be specified using the GHCRTS environment variable.",
"",
358 359 360 361 362 363
"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
364
STATIC_INLINE rtsBool
365 366 367 368 369
strequal(const char *a, const char * b)
{
    return(strcmp(a, b) == 0);
}

370
static void splitRtsFlags(char *s)
371 372 373 374 375 376 377 378 379 380 381
{
    char *c1, *c2;

    c1 = s;
    do {
	while (isspace(*c1)) { c1++; };
	c2 = c1;
	while (!isspace(*c2) && *c2 != '\0') { c2++; };
	
	if (c1 == c2) { break; }
	
382
        if (rts_argc < MAX_RTS_ARGS-1) {
sof's avatar
sof committed
383
	    s = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
384 385
	    strncpy(s, c1, c2-c1);
	    s[c2-c1] = '\0';
386
            rts_argv[rts_argc++] = s;
387 388 389 390 391 392 393 394
	} else {
	    barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
	}
	
	c1 = c2;
    } while (*c1 != '\0');
}
    
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
/* -----------------------------------------------------------------------------
   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[])
413
{
414 415 416
    nat mode;
    nat total_arg;
    nat arg, rts_argc0;
417

418
    setProgName (argv);
419 420 421 422
    total_arg = *argc;
    arg = 1;

    *argc = 1;
423 424 425
    rts_argc = 0;

    rts_argc0 = rts_argc;
426

427 428 429 430 431
    // 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) {
432 433 434 435 436
            splitRtsFlags(ghc_rts_opts);
            // opts from ghc_rts_opts are always enabled:
            procRtsOpts(rts_argc0, RtsOptsAll);
            rts_argc0 = rts_argc;
        }
437 438
    }

439
    // process arguments from the GHCRTS environment variable next
440
    // (arguments from the command line override these).
441 442 443 444
    {
	char *ghc_rts = getenv("GHCRTS");

	if (ghc_rts != NULL) {
445
            if (rtsOptsEnabled == RtsOptsNone) {
446
                errorBelch("Warning: Ignoring GHCRTS variable as RTS options are disabled.\n         Link with -rtsopts to enable them.");
447
                // We don't actually exit, just warn
448 449 450 451
            } else {
                splitRtsFlags(ghc_rts);
                procRtsOpts(rts_argc0, rtsOptsEnabled);
                rts_argc0 = rts_argc;
452
            }
453
        }
454
    }
455

456 457 458
    // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
    //   argv[0] must be PGM argument -- leave in argv

459 460 461 462 463 464 465 466 467 468 469 470
    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])) {
471 472
            mode = RTS;
        }
473 474 475
	else if (strequal("-RTS", argv[arg])) {
	    mode = PGM;
	}
476 477
        else if (mode == RTS && rts_argc < MAX_RTS_ARGS-1) {
            rts_argv[rts_argc++] = argv[arg];
Ian Lynagh's avatar
Ian Lynagh committed
478
        }
Simon Marlow's avatar
Simon Marlow committed
479
        else if (mode == PGM) {
480 481 482 483 484 485
	    argv[(*argc)++] = argv[arg];
	}
	else {
	  barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
	}
    }
486 487 488
    // process remaining program arguments
    for (; arg < total_arg; arg++) {
	argv[(*argc)++] = argv[arg];
489 490
    }
    argv[*argc] = (char *) 0;
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
    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;
515 516

    // Process RTS (rts_argv) part: mainly to determine statsfile
517 518
    for (arg = rts_argc0; arg < rts_argc; arg++) {
        if (rts_argv[arg][0] != '-') {
519
	    fflush(stdout);
520
	    errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
521 522 523
	    error = rtsTrue;

        } else {
Simon Marlow's avatar
Simon Marlow committed
524

525 526 527 528 529
            if (enabled == RtsOptsNone) {
                errorBelch("RTS options are disabled. Link with -rtsopts to enable them.");
                stg_exit(EXIT_FAILURE);
            }

Simon Marlow's avatar
Simon Marlow committed
530 531 532 533 534 535 536 537 538 539 540
            switch(rts_argv[arg][1]) {
            case '-':
                if (strequal("info", &rts_argv[arg][2])) {
                    printRtsInfo();
                    stg_exit(0);
                }
                break;
            default:
                break;
            }

541
            if (enabled == RtsOptsSafeOnly) {
Simon Marlow's avatar
Simon Marlow committed
542 543 544 545 546
                errorBelch("Most RTS options are disabled. Link with -rtsopts to enable them.");
                stg_exit(EXIT_FAILURE);
            }

            switch(rts_argv[arg][1]) {
547

Simon Marlow's avatar
Simon Marlow committed
548 549 550 551 552
	      /* 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.
553 554 555 556 557 558
	      */

#ifdef TICKY_TICKY
# define TICKY_BUILD_ONLY(x) x
#else
# define TICKY_BUILD_ONLY(x) \
559
errorBelch("the flag %s requires the program to be built with -ticky", rts_argv[arg]); \
560 561 562 563 564 565 566
error = rtsTrue;
#endif

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

571 572
#ifdef TRACING
# define TRACING_BUILD_ONLY(x)   x
Simon Marlow's avatar
Simon Marlow committed
573
#else
574
# define TRACING_BUILD_ONLY(x) \
575
errorBelch("the flag %s requires the program to be built with -eventlog or -debug", rts_argv[arg]); \
Simon Marlow's avatar
Simon Marlow committed
576 577 578
error = rtsTrue;
#endif

579 580 581 582
#ifdef THREADED_RTS
# define THREADED_BUILD_ONLY(x)      x
#else
# define THREADED_BUILD_ONLY(x) \
583 584 585 586 587 588 589 590 591
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]); \
592
error = rtsTrue;
593 594 595 596 597 598 599
#endif

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

600 601 602 603 604 605 606 607 608 609 610 611
              /* 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
612 613 614 615
                  else if (strequal("machine-readable",
                               &rts_argv[arg][2])) {
                      RtsFlags.MiscFlags.machineReadable = rtsTrue;
                  }
616 617
                  else if (strequal("info",
                               &rts_argv[arg][2])) {
618
                      printRtsInfo();
619
                      stg_exit(0);
620
                  }
621 622 623 624 625
                  else {
		      errorBelch("unknown RTS option: %s",rts_argv[arg]);
		      error = rtsTrue;
                  }
		  break;
626
	      case 'A':
627 628 629 630
                  RtsFlags.GcFlags.minAllocAreaSize
                      = decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_INT_MAX)
                           / BLOCK_SIZE;
                  break;
631

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
#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;
647 648 649
		case 'e':
		  RtsFlags.PapiFlags.eventType = PAPI_FLAG_CB_EVENTS;
		  break;
650
                case '+':
651
                case '#':
652 653 654 655
                  if (RtsFlags.PapiFlags.numUserEvents >= MAX_PAPI_USER_EVENTS) {
                      errorBelch("maximum number of PAPI events reached");
                      stg_exit(EXIT_FAILURE);
                  }
656 657 658 659 660
                  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;
661
                  RtsFlags.PapiFlags.eventType = PAPI_USER_EVENTS;
662
                  RtsFlags.PapiFlags.userEventsKind[eventNum] = eventKind;
663
                  break;
664 665 666 667 668 669
		default:
		  bad_option( rts_argv[arg] );
		}
		break;
#endif

670 671 672 673
	      case 'B':
		RtsFlags.GcFlags.ringBell = rtsTrue;
		break;

674
	      case 'c':
675 676 677 678
		  if (rts_argv[arg][2] != '\0') {
		      RtsFlags.GcFlags.compactThreshold =
			  atof(rts_argv[arg]+2);
		  } else {
679
		      RtsFlags.GcFlags.compact = rtsTrue;
680 681
		  }
		  break;
682

683 684 685 686
              case 'w':
		RtsFlags.GcFlags.sweep = rtsTrue;
		break;

687 688 689 690 691 692 693
	      case 'F':
	        RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
	      
		if (RtsFlags.GcFlags.oldGenFactor < 0)
		  bad_option( rts_argv[arg] );
		break;
	      
694
	      case 'D':
695
              DEBUG_BUILD_ONLY(
696 697 698 699 700 701 702 703
	      { 
		  char *c;

		  for (c  = rts_argv[arg] + 2; *c != '\0'; c++) {
		      switch (*c) {
		      case 's':
			  RtsFlags.DebugFlags.scheduler = rtsTrue;
			  break;
704 705
		      case 'i':
			  RtsFlags.DebugFlags.interpreter = rtsTrue;
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
			  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;
731 732 733
		      case 'a':
			  RtsFlags.DebugFlags.apply = rtsTrue;
			  break;
734 735 736
		      case 'm':
			  RtsFlags.DebugFlags.stm = rtsTrue;
			  break;
737 738 739
		      case 'z':
			  RtsFlags.DebugFlags.squeeze = rtsTrue;
			  break;
740 741 742
		      case 'c':
			  RtsFlags.DebugFlags.hpc = rtsTrue;
			  break;
743 744 745
		      case 'r':
			  RtsFlags.DebugFlags.sparks = rtsTrue;
			  break;
746 747 748 749
		      default:
			  bad_option( rts_argv[arg] );
		      }
		  }
750 751
                  // -Dx also turns on -v.  Use -l to direct trace
                  // events to the .eventlog file instead.
752
                  RtsFlags.TraceFlags.tracing = TRACE_STDERR;
753 754
	      })
              break;
755 756

	      case 'K':
757
                  RtsFlags.GcFlags.maxStkSize =
758
                      decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
759
                  break;
760 761

	      case 'k':
762 763 764 765 766 767 768 769 770 771 772 773 774 775
		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:
776
                  RtsFlags.GcFlags.initialStkSize =
777
                      decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX) / sizeof(W_);
778
                  break;
779 780
                }
                break;
781

782
              case 'M':
783 784 785 786
                  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;
787 788

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

791 792 793 794
                  if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
                      RtsFlags.GcFlags.pcFreeHeap > 100)
                      bad_option( rts_argv[arg] );
                  break;
795

796
	      case 'G':
797 798 799
                  RtsFlags.GcFlags.generations =
                      decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
                  break;
800

801
	      case 'H':
802 803 804 805 806 807 808
                  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;
809

810 811 812 813 814 815
#ifdef RTS_GTK_FRONTPANEL
	      case 'f':
		  RtsFlags.GcFlags.frontpanel = rtsTrue;
		  break;
#endif

816 817 818 819 820 821
    	      case 'I':	/* idle GC delay */
		if (rts_argv[arg][2] == '\0') {
		  /* use default */
		} else {
		    I_ cst; /* tmp */

822
		    /* Convert to millisecs */
823
		    cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
824
		    RtsFlags.GcFlags.idleGCDelayTime = cst;
825 826 827
		}
		break;

828
	      case 'S':
829 830
		  RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
		  goto stats;
831

832
	      case 's':
833 834
		  RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
		  goto stats;
835 836

	      case 't':
837 838
		  RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
		  goto stats;
839

840
	    stats:
841 842
		{ 
		    int r;
843 844
                    r = openStatsFile(rts_argv[arg]+2, NULL,
                                      &RtsFlags.GcFlags.statsFile);
845 846
		    if (r == -1) { error = rtsTrue; }
		}
Simon Marlow's avatar
Simon Marlow committed
847
                break;
848 849 850 851 852 853 854 855 856

	      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
857
		PROFILING_BUILD_ONLY(
858
		switch (rts_argv[arg][2]) {
859 860
		  case 'x':
		    RtsFlags.CcFlags.doCostCentres = COST_CENTRES_XML;
861
		    break;
andy's avatar
andy committed
862 863 864
		  case 'a':
		    RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
		    break;
865
		  default:
866 867 868 869 870 871 872 873
		      if (rts_argv[arg][1] == 'P') {
			  RtsFlags.CcFlags.doCostCentres =
			      COST_CENTRES_VERBOSE;
		      } else {
			  RtsFlags.CcFlags.doCostCentres =
			      COST_CENTRES_SUMMARY;
		      }
		      break;
874 875 876
		}
		) break;

877 878 879 880
	      case 'R':
		  PROFILING_BUILD_ONLY(
		      RtsFlags.ProfFlags.maxRetainerSetSize = atof(rts_argv[arg]+2);
  	          ) break;
ravi@bluespec.com's avatar
ravi@bluespec.com committed
881 882 883 884 885 886 887
	      case 'L':
		  PROFILING_BUILD_ONLY(
		      RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
                      if(RtsFlags.ProfFlags.ccsLength <= 0) {
			bad_option(rts_argv[arg]);
                      }
		  ) break;
888
	      case 'h': /* serial heap profile */
889
#if !defined(PROFILING)
890 891 892 893 894 895
		switch (rts_argv[arg][2]) {
		  case '\0':
		  case 'T':
		    RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
		    break;
		  default:
896
		    errorBelch("invalid heap profile option: %s",rts_argv[arg]);
897 898 899 900 901
		    error = rtsTrue;
		}
#else
		PROFILING_BUILD_ONLY(
		switch (rts_argv[arg][2]) {
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918
		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], '}');
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935

			    // 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;
936 937 938
			    case 'C':
				RtsFlags.ProfFlags.ccsSelector = left;
				break;
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
			    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;
959 960 961 962
			    }
			}
			break;
		    }
963

964
		    if (RtsFlags.ProfFlags.doHeapProfile != 0) {
965
			errorBelch("multiple heap profile options");
966 967 968 969 970 971 972 973 974 975 976 977
			error = rtsTrue;
			break;
		    }

		    switch (rts_argv[arg][2]) {
		    case '\0':
		    case 'C':
		    case 'c':
			RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
			break;
		    case 'M':