RtsFlags: Refactor some of the deeper switches
[ghc.git] / rts / RtsFlags.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The AQUA Project, Glasgow University, 1994-1997
4 * (c) The GHC Team, 1998-2006
5 *
6 * Functions for parsing the argument list.
7 *
8 * ---------------------------------------------------------------------------*/
9
10 #include "PosixSource.h"
11 #include "Rts.h"
12
13 #include "RtsUtils.h"
14 #include "Profiling.h"
15 #include "RtsFlags.h"
16 #include "sm/OSMem.h"
17 #include "hooks/Hooks.h"
18
19 #ifdef HAVE_CTYPE_H
20 #include <ctype.h>
21 #endif
22
23 #include <string.h>
24
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32
33 // Flag Structure
34 RTS_FLAGS RtsFlags;
35
36 /*
37 * Split argument lists
38 */
39 int prog_argc = 0; /* an "int" so as to match normal "argc" */
40 char **prog_argv = NULL;
41 int full_prog_argc = 0; /* an "int" so as to match normal "argc" */
42 char **full_prog_argv = NULL;
43 char *prog_name = NULL; /* 'basename' of prog_argv[0] */
44 int rts_argc = 0; /* ditto */
45 char **rts_argv = NULL;
46 int rts_argv_size = 0;
47 #if defined(mingw32_HOST_OS)
48 // On Windows, we want to use GetCommandLineW rather than argc/argv,
49 // but we need to mutate the command line arguments for withProgName and
50 // friends. The System.Environment module achieves that using this bit of
51 // shared state:
52 int win32_prog_argc = 0;
53 wchar_t **win32_prog_argv = NULL;
54 #endif
55
56 // The global rtsConfig, set from the RtsConfig supplied by the call
57 // to hs_init_ghc().
58 RtsConfig rtsConfig;
59
60 const RtsConfig defaultRtsConfig = {
61 .rts_opts_enabled = RtsOptsSafeOnly,
62 .rts_opts_suggestions = rtsTrue,
63 .rts_opts = NULL,
64 .rts_hs_main = rtsFalse,
65 .keep_cafs = rtsFalse,
66 .defaultsHook = FlagDefaultsHook,
67 .onExitHook = OnExitHook,
68 .stackOverflowHook = StackOverflowHook,
69 .outOfHeapHook = OutOfHeapHook,
70 .mallocFailHook = MallocFailHook,
71 .gcDoneHook = NULL
72 };
73
74 /*
75 * constants, used later
76 */
77 #define RTS 1
78 #define PGM 0
79
80 /* -----------------------------------------------------------------------------
81 Static function decls
82 -------------------------------------------------------------------------- */
83
84 static void procRtsOpts (int rts_argc0, RtsOptsEnabledEnum enabled);
85
86 static void normaliseRtsOpts (void);
87
88 static void initStatsFile (FILE *f);
89
90 static int openStatsFile (
91 char *filename, const char *FILENAME_FMT, FILE **file_ret);
92
93 static StgWord64 decodeSize (
94 const char *flag, nat offset, StgWord64 min, StgWord64 max);
95
96 static void bad_option (const char *s);
97
98 #ifdef DEBUG
99 static void read_debug_flags(const char *arg);
100 #endif
101
102 #ifdef PROFILING
103 static rtsBool read_heap_profiling_flag(const char *arg);
104 #endif
105
106 #ifdef USE_PAPI
107 static void read_papi_flag(const char *arg);
108 #endif
109
110 #ifdef TRACING
111 static void read_trace_flags(const char *arg);
112 #endif
113
114 static void errorUsage (void) GNU_ATTRIBUTE(__noreturn__);
115
116 static char * copyArg (char *arg);
117 static char ** copyArgv (int argc, char *argv[]);
118 static void freeArgv (int argc, char *argv[]);
119
120 static void errorRtsOptsDisabled (const char *s);
121
122 /* -----------------------------------------------------------------------------
123 * Command-line option parsing routines.
124 * ---------------------------------------------------------------------------*/
125
126 void initRtsFlagsDefaults(void)
127 {
128 StgWord64 maxStkSize = 8 * getPhysicalMemorySize() / 10;
129 // if getPhysicalMemorySize fails just move along with an 8MB limit
130 if (maxStkSize == 0)
131 maxStkSize = 8 * 1024 * 1024;
132
133 RtsFlags.GcFlags.statsFile = NULL;
134 RtsFlags.GcFlags.giveStats = NO_GC_STATS;
135
136 RtsFlags.GcFlags.maxStkSize = maxStkSize / sizeof(W_);
137 RtsFlags.GcFlags.initialStkSize = 1024 / sizeof(W_);
138 RtsFlags.GcFlags.stkChunkSize = (32 * 1024) / sizeof(W_);
139 RtsFlags.GcFlags.stkChunkBufferSize = (1 * 1024) / sizeof(W_);
140
141 RtsFlags.GcFlags.minAllocAreaSize = (512 * 1024) / BLOCK_SIZE;
142 RtsFlags.GcFlags.nurseryChunkSize = 0;
143 RtsFlags.GcFlags.minOldGenSize = (1024 * 1024) / BLOCK_SIZE;
144 RtsFlags.GcFlags.maxHeapSize = 0; /* off by default */
145 RtsFlags.GcFlags.heapSizeSuggestion = 0; /* none */
146 RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsFalse;
147 RtsFlags.GcFlags.pcFreeHeap = 3; /* 3% */
148 RtsFlags.GcFlags.oldGenFactor = 2;
149 RtsFlags.GcFlags.generations = 2;
150 RtsFlags.GcFlags.squeezeUpdFrames = rtsTrue;
151 RtsFlags.GcFlags.compact = rtsFalse;
152 RtsFlags.GcFlags.compactThreshold = 30.0;
153 RtsFlags.GcFlags.sweep = rtsFalse;
154 RtsFlags.GcFlags.idleGCDelayTime = USToTime(300000); // 300ms
155 #ifdef THREADED_RTS
156 RtsFlags.GcFlags.doIdleGC = rtsTrue;
157 #else
158 RtsFlags.GcFlags.doIdleGC = rtsFalse;
159 #endif
160
161 #if osf3_HOST_OS
162 /* ToDo: Perhaps by adjusting this value we can make linking without
163 * -static work (i.e., not generate a core-dumping executable)? */
164 # if SIZEOF_VOID_P == 8
165 RtsFlags.GcFlags.heapBase = 0x180000000L;
166 # else
167 # error I have no idea where to begin the heap on a non-64-bit osf3 machine.
168 # endif
169 #else
170 RtsFlags.GcFlags.heapBase = 0; /* means don't care */
171 #endif
172 RtsFlags.GcFlags.allocLimitGrace = (100*1024) / BLOCK_SIZE;
173
174 #ifdef DEBUG
175 RtsFlags.DebugFlags.scheduler = rtsFalse;
176 RtsFlags.DebugFlags.interpreter = rtsFalse;
177 RtsFlags.DebugFlags.weak = rtsFalse;
178 RtsFlags.DebugFlags.gccafs = rtsFalse;
179 RtsFlags.DebugFlags.gc = rtsFalse;
180 RtsFlags.DebugFlags.block_alloc = rtsFalse;
181 RtsFlags.DebugFlags.sanity = rtsFalse;
182 RtsFlags.DebugFlags.stable = rtsFalse;
183 RtsFlags.DebugFlags.stm = rtsFalse;
184 RtsFlags.DebugFlags.prof = rtsFalse;
185 RtsFlags.DebugFlags.apply = rtsFalse;
186 RtsFlags.DebugFlags.linker = rtsFalse;
187 RtsFlags.DebugFlags.squeeze = rtsFalse;
188 RtsFlags.DebugFlags.hpc = rtsFalse;
189 RtsFlags.DebugFlags.sparks = rtsFalse;
190 #endif
191
192 #if defined(PROFILING)
193 RtsFlags.CcFlags.doCostCentres = 0;
194 #endif /* PROFILING */
195
196 RtsFlags.ProfFlags.doHeapProfile = rtsFalse;
197 RtsFlags.ProfFlags. heapProfileInterval = USToTime(100000); // 100ms
198
199 #ifdef PROFILING
200 RtsFlags.ProfFlags.includeTSOs = rtsFalse;
201 RtsFlags.ProfFlags.showCCSOnException = rtsFalse;
202 RtsFlags.ProfFlags.maxRetainerSetSize = 8;
203 RtsFlags.ProfFlags.ccsLength = 25;
204 RtsFlags.ProfFlags.modSelector = NULL;
205 RtsFlags.ProfFlags.descrSelector = NULL;
206 RtsFlags.ProfFlags.typeSelector = NULL;
207 RtsFlags.ProfFlags.ccSelector = NULL;
208 RtsFlags.ProfFlags.ccsSelector = NULL;
209 RtsFlags.ProfFlags.retainerSelector = NULL;
210 RtsFlags.ProfFlags.bioSelector = NULL;
211 #endif
212
213 #ifdef TRACING
214 RtsFlags.TraceFlags.tracing = TRACE_NONE;
215 RtsFlags.TraceFlags.timestamp = rtsFalse;
216 RtsFlags.TraceFlags.scheduler = rtsFalse;
217 RtsFlags.TraceFlags.gc = rtsFalse;
218 RtsFlags.TraceFlags.sparks_sampled= rtsFalse;
219 RtsFlags.TraceFlags.sparks_full = rtsFalse;
220 RtsFlags.TraceFlags.user = rtsFalse;
221 #endif
222
223 #ifdef PROFILING
224 // When profiling we want a lot more ticks
225 RtsFlags.MiscFlags.tickInterval = USToTime(1000); // 1ms
226 #else
227 RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
228 #endif
229 RtsFlags.ConcFlags.ctxtSwitchTime = USToTime(20000); // 20ms
230
231 RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
232 RtsFlags.MiscFlags.machineReadable = rtsFalse;
233 RtsFlags.MiscFlags.linkerMemBase = 0;
234
235 #ifdef THREADED_RTS
236 RtsFlags.ParFlags.nNodes = 1;
237 RtsFlags.ParFlags.migrate = rtsTrue;
238 RtsFlags.ParFlags.parGcEnabled = 1;
239 RtsFlags.ParFlags.parGcGen = 0;
240 RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsTrue;
241 RtsFlags.ParFlags.parGcLoadBalancingGen = 1;
242 RtsFlags.ParFlags.parGcNoSyncWithIdle = 0;
243 RtsFlags.ParFlags.setAffinity = 0;
244 #endif
245
246 #if defined(THREADED_RTS)
247 RtsFlags.ParFlags.maxLocalSparks = 4096;
248 #endif /* THREADED_RTS */
249
250 #ifdef TICKY_TICKY
251 RtsFlags.TickyFlags.showTickyStats = rtsFalse;
252 RtsFlags.TickyFlags.tickyFile = NULL;
253 #endif
254
255 #ifdef USE_PAPI
256 /* By default no special measurements taken */
257 RtsFlags.PapiFlags.eventType = 0;
258 RtsFlags.PapiFlags.numUserEvents = 0;
259 #endif
260 }
261
262 static const char *
263 usage_text[] = {
264 "",
265 "Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
266 "",
267 " +RTS Indicates run time system options follow",
268 " -RTS Indicates program arguments follow",
269 " --RTS Indicates that ALL subsequent arguments will be given to the",
270 " program (including any of these RTS flags)",
271 "",
272 "The following run time system options are available:",
273 "",
274 " -? Prints this message and exits; the program is not executed",
275 " --info Print information about the RTS used by this program",
276 "",
277 " -K<size> Sets the maximum stack size (default: 80% of the heap)",
278 " Egs: -K32k -K512k -K8M",
279 " -ki<size> Sets the initial thread stack size (default 1k) Egs: -ki4k -ki2m",
280 " -kc<size> Sets the stack chunk size (default 32k)",
281 " -kb<size> Sets the stack chunk buffer size (default 1k)",
282 "",
283 " -A<size> Sets the minimum allocation area size (default 512k) Egs: -A1m -A10k",
284 " -n<size> Allocation area chunk size (0 = disabled, default: 0)",
285 " -O<size> Sets the minimum size of the old generation (default 1M)",
286 " -M<size> Sets the maximum heap size (default unlimited) Egs: -M256k -M1G",
287 " -H<size> Sets the minimum heap size (default 0M) Egs: -H24m -H1G",
288 " -m<n> Minimum % of heap which must be available (default 3%)",
289 " -G<n> Number of generations (default: 2)",
290 " -c<n> Use in-place compaction instead of copying in the oldest generation",
291 " when live data is at least <n>% of the maximum heap size set with",
292 " -M (default: 30%)",
293 " -c Use in-place compaction for all oldest generation collections",
294 " (the default is to use copying)",
295 " -w Use mark-region for the oldest generation (experimental)",
296 #if defined(THREADED_RTS)
297 " -I<sec> Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
298 #endif
299 "",
300 " -T Collect GC statistics (useful for in-program statistics access)",
301 " -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
302 " -s[<file>] Summary GC statistics (if <file> omitted, uses stderr)",
303 " -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
304 "",
305 "",
306 " -Z Don't squeeze out update frames on stack overflow",
307 " -B Sound the bell at the start of each garbage collection",
308 #if defined(PROFILING)
309 "",
310 " -p Time/allocation profile (output file <program>.prof)",
311 " -P More detailed Time/Allocation profile",
312 " -Pa Give information about *all* cost centres",
313 "",
314 " -h<break-down> Heap residency profile (hp2ps) (output file <program>.hp)",
315 " break-down: c = cost centre stack (default)",
316 " m = module",
317 " d = closure description",
318 " y = type description",
319 " r = retainer",
320 " b = biography (LAG,DRAG,VOID,USE)",
321 " A subset of closures may be selected thusly:",
322 " -hc<cc>,... specific cost centre(s) (top of stack only)",
323 " -hC<cc>,... specific cost centre(s) (anywhere in stack)",
324 " -hm<mod>... all cost centres from the specified modules(s)",
325 " -hd<des>,... closures with specified closure descriptions",
326 " -hy<typ>... closures with specified type descriptions",
327 " -hr<cc>... closures with specified retainers",
328 " -hb<bio>... closures with specified biographies (lag,drag,void,use)",
329 "",
330 " -R<size> Set the maximum retainer set size (default: 8)",
331 "",
332 " -L<chars> Maximum length of a cost-centre stack in a heap profile",
333 " (default: 25)",
334 "",
335 " -xt Include threads (TSOs) in a heap profile",
336 "",
337 " -xc Show current cost centre stack on raising an exception",
338 #endif /* PROFILING */
339
340 #ifdef TRACING
341 "",
342 " -l[flags] Log events in binary format to the file <program>.eventlog",
343 # ifdef DEBUG
344 " -v[flags] Log events to stderr",
345 # endif
346 " where [flags] can contain:",
347 " s scheduler events",
348 " g GC and heap events",
349 " p par spark events (sampled)",
350 " f par spark events (full detail)",
351 " u user events (emitted from Haskell code)",
352 " a all event classes above",
353 # ifdef DEBUG
354 " t add time stamps (only useful with -v)",
355 # endif
356 " -x disable an event class, for any flag above",
357 " the initial enabled event classes are 'sgpu'",
358 #endif
359
360 #if !defined(PROFILING)
361 "",
362 " -h Heap residency profile (output file <program>.hp)",
363 #endif
364 " -i<sec> Time between heap profile samples (seconds, default: 0.1)",
365 "",
366 #if defined(TICKY_TICKY)
367 " -r<file> Produce ticky-ticky statistics (with -rstderr for stderr)",
368 "",
369 #endif
370 " -C<secs> Context-switch interval in seconds.",
371 " 0 or no argument means switch as often as possible.",
372 " Default: 0.02 sec.",
373 " -V<secs> Master tick interval in seconds (0 == disable timer).",
374 " This sets the resolution for -C and the heap profile timer -i,",
375 " and is the frequence of time profile samples.",
376 #ifdef PROFILING
377 " Default: 0.001 sec.",
378 #else
379 " Default: 0.01 sec.",
380 #endif
381 "",
382 #if defined(DEBUG)
383 " -Ds DEBUG: scheduler",
384 " -Di DEBUG: interpreter",
385 " -Dw DEBUG: weak",
386 " -DG DEBUG: gccafs",
387 " -Dg DEBUG: gc",
388 " -Db DEBUG: block",
389 " -DS DEBUG: sanity",
390 " -Dt DEBUG: stable",
391 " -Dp DEBUG: prof",
392 " -Da DEBUG: apply",
393 " -Dl DEBUG: linker",
394 " -Dm DEBUG: stm",
395 " -Dz DEBUG: stack squeezing",
396 " -Dc DEBUG: program coverage",
397 " -Dr DEBUG: sparks",
398 "",
399 " NOTE: DEBUG events are sent to stderr by default; add -l to create a",
400 " binary event log file instead.",
401 "",
402 #endif /* DEBUG */
403 #if defined(THREADED_RTS) && !defined(NOSMP)
404 " -N[<n>] Use <n> processors (default: 1, -N alone determines",
405 " the number of processors to use automatically)",
406 " -qg[<n>] Use parallel GC only for generations >= <n>",
407 " (default: 0, -qg alone turns off parallel GC)",
408 " -qb[<n>] Use load-balancing in the parallel GC only for generations >= <n>",
409 " (default: 1, -qb alone turns off load-balancing)",
410 " -qa Use the OS to set thread affinity (experimental)",
411 " -qm Don't automatically migrate threads between CPUs",
412 " -qi<n> If a processor has been idle for the last <n> GCs, do not",
413 " wake it up for a non-load-balancing parallel GC.",
414 " (0 disables, default: 0)",
415 #endif
416 " --install-signal-handlers=<yes|no>",
417 " Install signal handlers (default: yes)",
418 #if defined(THREADED_RTS)
419 " -e<n> Maximum number of outstanding local sparks (default: 4096)",
420 #endif
421 #if defined(x86_64_HOST_ARCH)
422 " -xm Base address to mmap memory in the GHCi linker",
423 " (hex; must be <80000000)",
424 #endif
425 #if defined(USE_PAPI)
426 " -aX CPU performance counter measurements using PAPI",
427 " (use with the -s<file> option). X is one of:",
428 "",
429 /* " y - cycles", */
430 " 1 - level 1 cache misses",
431 " 2 - level 2 cache misses",
432 " b - branch mispredictions",
433 " s - stalled cycles",
434 " e - cache miss and branch misprediction events",
435 " +PAPI_EVENT - collect papi preset event PAPI_EVENT",
436 " #NATIVE_EVENT - collect native event NATIVE_EVENT (in hex)",
437 #endif
438 " -xq The allocation limit given to a thread after it receives",
439 " an AllocationLimitExceeded exception. (default: 100k)",
440 "",
441 "RTS options may also be specified using the GHCRTS environment variable.",
442 "",
443 "Other RTS options may be available for programs compiled a different way.",
444 "The GHC User's Guide has full details.",
445 "",
446 0
447 };
448
449 STATIC_INLINE rtsBool strequal(const char *a, const char * b)
450 {
451 return(strcmp(a, b) == 0);
452 }
453
454 // We can't predict up front how much space we'll need for rts_argv,
455 // because it involves parsing ghc_rts_opts and GHCRTS, so we
456 // expand it on demand.
457 static void appendRtsArg (char *arg)
458 {
459 if (rts_argc == rts_argv_size) {
460 rts_argv_size *= 2;
461 rts_argv = stgReallocBytes(rts_argv, rts_argv_size * sizeof (char *),
462 "RtsFlags.c:appendRtsArg");
463 }
464 rts_argv[rts_argc++] = arg;
465 }
466
467 static void splitRtsFlags(const char *s)
468 {
469 const char *c1, *c2;
470 char *t;
471
472 c1 = s;
473 do {
474 while (isspace(*c1)) { c1++; };
475 c2 = c1;
476 while (!isspace(*c2) && *c2 != '\0') { c2++; };
477
478 if (c1 == c2) { break; }
479
480 t = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
481 strncpy(t, c1, c2-c1);
482 t[c2-c1] = '\0';
483 appendRtsArg(t);
484
485 c1 = c2;
486 } while (*c1 != '\0');
487 }
488
489 static void errorRtsOptsDisabled(const char *s)
490 {
491 char *advice;
492 if (rtsConfig.rts_hs_main) {
493 advice = "Link with -rtsopts to enable them.";
494 } else {
495 advice = "Use hs_init_with_rtsopts() to enable them.";
496 }
497 errorBelch(s, advice);
498 }
499
500 /* -----------------------------------------------------------------------------
501 Parse the command line arguments, collecting options for the RTS.
502
503 On return:
504 - argv[] is *modified*, any RTS options have been stripped out
505 - *argc contains the new count of arguments in argv[]
506
507 - rts_argv[] (global) contains a copy of the collected RTS args
508 - rts_argc (global) contains the count of args in rts_argv
509
510 - prog_argv[] (global) contains a copy of the non-RTS args (== argv)
511 - prog_argc (global) contains the count of args in prog_argv
512
513 - prog_name (global) contains the basename of prog_argv[0]
514
515 - rtsConfig (global) contains the supplied RtsConfig
516
517 -------------------------------------------------------------------------- */
518
519 void setupRtsFlags (int *argc, char *argv[], RtsConfig rts_config)
520 {
521 nat mode;
522 nat total_arg;
523 nat arg, rts_argc0;
524
525 rtsConfig = rts_config;
526
527 setProgName (argv);
528 total_arg = *argc;
529 arg = 1;
530
531 if (*argc > 1) { *argc = 1; };
532 rts_argc = 0;
533
534 rts_argv_size = total_arg + 1;
535 rts_argv = stgMallocBytes(rts_argv_size * sizeof (char *), "setupRtsFlags");
536
537 rts_argc0 = rts_argc;
538
539 // process arguments from the -with-rtsopts compile-time flag first
540 // (arguments from the GHCRTS environment variable and the command
541 // line override these).
542 {
543 if (rtsConfig.rts_opts != NULL) {
544 splitRtsFlags(rtsConfig.rts_opts);
545 // opts from rts_opts are always enabled:
546 procRtsOpts(rts_argc0, RtsOptsAll);
547 rts_argc0 = rts_argc;
548 }
549 }
550
551 // process arguments from the GHCRTS environment variable next
552 // (arguments from the command line override these).
553 {
554 char *ghc_rts = getenv("GHCRTS");
555
556 if (ghc_rts != NULL) {
557 if (rtsConfig.rts_opts_enabled == RtsOptsNone) {
558 errorRtsOptsDisabled(
559 "Warning: Ignoring GHCRTS variable as RTS options are disabled.\n %s");
560 // We don't actually exit, just warn
561 } else {
562 splitRtsFlags(ghc_rts);
563 procRtsOpts(rts_argc0, rtsConfig.rts_opts_enabled);
564 rts_argc0 = rts_argc;
565 }
566 }
567 }
568
569 // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
570 // argv[0] must be PGM argument -- leave in argv
571
572 for (mode = PGM; arg < total_arg; arg++) {
573 // The '--RTS' argument disables all future +RTS ... -RTS processing.
574 if (strequal("--RTS", argv[arg])) {
575 arg++;
576 break;
577 }
578 // The '--' argument is passed through to the program, but
579 // disables all further +RTS ... -RTS processing.
580 else if (strequal("--", argv[arg])) {
581 break;
582 }
583 else if (strequal("+RTS", argv[arg])) {
584 mode = RTS;
585 }
586 else if (strequal("-RTS", argv[arg])) {
587 mode = PGM;
588 }
589 else if (mode == RTS) {
590 appendRtsArg(copyArg(argv[arg]));
591 }
592 else {
593 argv[(*argc)++] = argv[arg];
594 }
595 }
596 // process remaining program arguments
597 for (; arg < total_arg; arg++) {
598 argv[(*argc)++] = argv[arg];
599 }
600 argv[*argc] = (char *) 0;
601
602 procRtsOpts(rts_argc0, rtsConfig.rts_opts_enabled);
603
604 appendRtsArg((char *)0);
605 rts_argc--; // appendRtsArg will have bumped it for the NULL (#7227)
606
607 normaliseRtsOpts();
608
609 setProgArgv(*argc, argv);
610
611 if (RtsFlags.GcFlags.statsFile != NULL) {
612 initStatsFile (RtsFlags.GcFlags.statsFile);
613 }
614 if (RtsFlags.TickyFlags.tickyFile != NULL) {
615 initStatsFile (RtsFlags.GcFlags.statsFile);
616 }
617 }
618
619 /* -----------------------------------------------------------------------------
620 * procRtsOpts: Process rts_argv between rts_argc0 and rts_argc.
621 * -------------------------------------------------------------------------- */
622
623 #if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_TYPES_H) && !defined(mingw32_HOST_OS)
624 static void checkSuid(RtsOptsEnabledEnum enabled)
625 {
626 if (enabled == RtsOptsSafeOnly) {
627 /* This doesn't cover linux/posix capabilities like CAP_DAC_OVERRIDE,
628 we'd have to link with -lcap for that. */
629 if ((getuid() != geteuid()) || (getgid() != getegid())) {
630 errorRtsOptsDisabled(
631 "RTS options are disabled for setuid binaries. %s");
632 stg_exit(EXIT_FAILURE);
633 }
634 }
635 }
636 #else
637 static void checkSuid (RtsOptsEnabledEnum enabled STG_UNUSED)
638 {
639 }
640 #endif
641
642 static void checkUnsafe(RtsOptsEnabledEnum enabled)
643 {
644 if (enabled == RtsOptsSafeOnly) {
645 errorRtsOptsDisabled("Most RTS options are disabled. %s");
646 stg_exit(EXIT_FAILURE);
647 }
648 }
649
650 static void procRtsOpts (int rts_argc0,
651 RtsOptsEnabledEnum rtsOptsEnabled)
652 {
653 rtsBool error = rtsFalse;
654 int arg;
655 int unchecked_arg_start;
656
657 if (!(rts_argc0 < rts_argc)) return;
658
659 if (rtsOptsEnabled == RtsOptsNone) {
660 errorRtsOptsDisabled("RTS options are disabled. %s");
661 stg_exit(EXIT_FAILURE);
662 }
663
664 checkSuid(rtsOptsEnabled);
665
666 // Process RTS (rts_argv) part: mainly to determine statsfile
667 for (arg = rts_argc0; arg < rts_argc; arg++) {
668
669 /* We handle RtsOptsSafeOnly mode by declaring each option as
670 either OPTION_SAFE or OPTION_UNSAFE. To make sure we cover
671 every branch we use an option_checked flag which is reset
672 at the start each iteration and checked at the end. */
673 rtsBool option_checked = rtsFalse;
674
675 #define OPTION_SAFE option_checked = rtsTrue;
676 #define OPTION_UNSAFE checkUnsafe(rtsOptsEnabled); option_checked = rtsTrue;
677
678 if (rts_argv[arg][0] != '-') {
679 fflush(stdout);
680 errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
681 error = rtsTrue;
682
683 } else {
684 /* 0 is dash, 1 is first letter */
685 /* see Trac #9839 */
686 unchecked_arg_start = 1;
687 switch(rts_argv[arg][1]) {
688
689 /* process: general args, then PROFILING-only ones, then
690 CONCURRENT-only, TICKY-only (same order as defined in
691 RtsFlags.lh); within those groups, mostly in
692 case-insensitive alphabetical order. Final group is
693 x*, which allows for more options.
694 */
695
696 #ifdef TICKY_TICKY
697 # define TICKY_BUILD_ONLY(x) x
698 #else
699 # define TICKY_BUILD_ONLY(x) \
700 errorBelch("the flag %s requires the program to be built with -ticky", \
701 rts_argv[arg]); \
702 error = rtsTrue;
703 #endif
704
705 #ifdef PROFILING
706 # define PROFILING_BUILD_ONLY(x) x
707 #else
708 # define PROFILING_BUILD_ONLY(x) \
709 errorBelch("the flag %s requires the program to be built with -prof", \
710 rts_argv[arg]); \
711 error = rtsTrue;
712 #endif
713
714 #ifdef TRACING
715 # define TRACING_BUILD_ONLY(x) x
716 #else
717 # define TRACING_BUILD_ONLY(x) \
718 errorBelch("the flag %s requires the program to be built with -eventlog or -debug", \
719 rts_argv[arg]); \
720 error = rtsTrue;
721 #endif
722
723 #ifdef THREADED_RTS
724 # define THREADED_BUILD_ONLY(x) x
725 #else
726 # define THREADED_BUILD_ONLY(x) \
727 errorBelch("the flag %s requires the program to be built with -threaded", \
728 rts_argv[arg]); \
729 error = rtsTrue;
730 #endif
731
732 #ifdef DEBUG
733 # define DEBUG_BUILD_ONLY(x) x
734 #else
735 # define DEBUG_BUILD_ONLY(x) \
736 errorBelch("the flag %s requires the program to be built with -debug", \
737 rts_argv[arg]); \
738 error = rtsTrue;
739 #endif
740
741 /* =========== GENERAL ========================== */
742 case '?':
743 OPTION_SAFE;
744 error = rtsTrue;
745 break;
746
747 /* This isn't going to allow us to keep related options
748 together as we add more --* flags. We really need a
749 proper options parser. */
750 case '-':
751 if (strequal("install-signal-handlers=yes",
752 &rts_argv[arg][2])) {
753 OPTION_UNSAFE;
754 RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
755 }
756 else if (strequal("install-signal-handlers=no",
757 &rts_argv[arg][2])) {
758 OPTION_UNSAFE;
759 RtsFlags.MiscFlags.install_signal_handlers = rtsFalse;
760 }
761 else if (strequal("machine-readable",
762 &rts_argv[arg][2])) {
763 OPTION_UNSAFE;
764 RtsFlags.MiscFlags.machineReadable = rtsTrue;
765 }
766 else if (strequal("info",
767 &rts_argv[arg][2])) {
768 OPTION_SAFE;
769 printRtsInfo();
770 stg_exit(0);
771 }
772 else {
773 OPTION_SAFE;
774 errorBelch("unknown RTS option: %s",rts_argv[arg]);
775 error = rtsTrue;
776 }
777 break;
778 case 'A':
779 OPTION_UNSAFE;
780 // minimum two blocks in the nursery, so that we have one to
781 // grab for allocate().
782 RtsFlags.GcFlags.minAllocAreaSize
783 = decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE, HS_INT_MAX)
784 / BLOCK_SIZE;
785 break;
786 case 'n':
787 OPTION_UNSAFE;
788 RtsFlags.GcFlags.nurseryChunkSize
789 = decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE, HS_INT_MAX)
790 / BLOCK_SIZE;
791 break;
792
793 #ifdef USE_PAPI
794 case 'a':
795 OPTION_UNSAFE;
796 read_papi_flag(&rts_argv[arg])
797 break;
798 #endif
799
800 case 'B':
801 OPTION_UNSAFE;
802 RtsFlags.GcFlags.ringBell = rtsTrue;
803 unchecked_arg_start++;
804 goto check_rest;
805
806 case 'c':
807 OPTION_UNSAFE;
808 if (rts_argv[arg][2] != '\0') {
809 RtsFlags.GcFlags.compactThreshold =
810 atof(rts_argv[arg]+2);
811 } else {
812 RtsFlags.GcFlags.compact = rtsTrue;
813 }
814 break;
815
816 case 'w':
817 OPTION_UNSAFE;
818 RtsFlags.GcFlags.sweep = rtsTrue;
819 unchecked_arg_start++;
820 goto check_rest;
821
822 case 'F':
823 OPTION_UNSAFE;
824 RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
825
826 if (RtsFlags.GcFlags.oldGenFactor < 0)
827 bad_option( rts_argv[arg] );
828 break;
829
830 case 'D':
831 OPTION_SAFE;
832 DEBUG_BUILD_ONLY(read_debug_flags(rts_argv[arg]);)
833 break;
834
835 case 'K':
836 OPTION_UNSAFE;
837 RtsFlags.GcFlags.maxStkSize =
838 decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX)
839 / sizeof(W_);
840 break;
841
842 case 'k':
843 OPTION_UNSAFE;
844 switch(rts_argv[arg][2]) {
845 case 'c':
846 RtsFlags.GcFlags.stkChunkSize =
847 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
848 / sizeof(W_);
849 break;
850 case 'b':
851 RtsFlags.GcFlags.stkChunkBufferSize =
852 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
853 / sizeof(W_);
854 break;
855 case 'i':
856 RtsFlags.GcFlags.initialStkSize =
857 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
858 / sizeof(W_);
859 break;
860 default:
861 RtsFlags.GcFlags.initialStkSize =
862 decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX)
863 / sizeof(W_);
864 break;
865 }
866 break;
867
868 case 'M':
869 OPTION_UNSAFE;
870 RtsFlags.GcFlags.maxHeapSize =
871 decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX)
872 / BLOCK_SIZE;
873 /* user give size in *bytes* but "maxHeapSize" is in
874 * *blocks* */
875 break;
876
877 case 'm':
878 OPTION_UNSAFE;
879 RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
880
881 if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
882 RtsFlags.GcFlags.pcFreeHeap > 100)
883 bad_option( rts_argv[arg] );
884 break;
885
886 case 'G':
887 OPTION_UNSAFE;
888 RtsFlags.GcFlags.generations =
889 decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
890 break;
891
892 case 'H':
893 OPTION_UNSAFE;
894 if (rts_argv[arg][2] == '\0') {
895 RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsTrue;
896 } else {
897 RtsFlags.GcFlags.heapSizeSuggestion =
898 (nat)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX) / BLOCK_SIZE);
899 }
900 break;
901
902 case 'O':
903 OPTION_UNSAFE;
904 RtsFlags.GcFlags.minOldGenSize =
905 (nat)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE,
906 HS_WORD_MAX)
907 / BLOCK_SIZE);
908 break;
909
910 case 'I': /* idle GC delay */
911 OPTION_UNSAFE;
912 if (rts_argv[arg][2] == '\0') {
913 /* use default */
914 } else {
915 Time t = fsecondsToTime(atof(rts_argv[arg]+2));
916 if (t == 0) {
917 RtsFlags.GcFlags.doIdleGC = rtsFalse;
918 } else {
919 RtsFlags.GcFlags.doIdleGC = rtsTrue;
920 RtsFlags.GcFlags.idleGCDelayTime = t;
921 }
922 }
923 break;
924
925 case 'T':
926 OPTION_SAFE;
927 RtsFlags.GcFlags.giveStats = COLLECT_GC_STATS;
928 unchecked_arg_start++;
929 goto check_rest; /* Don't initialize statistics file. */
930
931 case 'S':
932 OPTION_SAFE; /* but see below */
933 RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
934 goto stats;
935
936 case 's':
937 OPTION_SAFE; /* but see below */
938 RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
939 goto stats;
940
941 case 't':
942 OPTION_SAFE; /* but see below */
943 RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
944 goto stats;
945
946 stats:
947 {
948 int r;
949 if (rts_argv[arg][2] != '\0') {
950 OPTION_UNSAFE;
951 }
952 r = openStatsFile(rts_argv[arg]+2, NULL,
953 &RtsFlags.GcFlags.statsFile);
954 if (r == -1) { error = rtsTrue; }
955 }
956 break;
957
958 case 'Z':
959 OPTION_UNSAFE;
960 RtsFlags.GcFlags.squeezeUpdFrames = rtsFalse;
961 unchecked_arg_start++;
962 goto check_rest;
963
964 /* =========== PROFILING ========================== */
965
966 case 'P': /* detailed cost centre profiling (time/alloc) */
967 case 'p': /* cost centre profiling (time/alloc) */
968 OPTION_SAFE;
969 PROFILING_BUILD_ONLY(
970 switch (rts_argv[arg][2]) {
971 case 'a':
972 RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
973 if (rts_argv[arg][3] != '\0') {
974 errorBelch("flag -Pa given an argument"
975 " when none was expected: %s"
976 ,rts_argv[arg]);
977 error = rtsTrue;
978 }
979 break;
980 case '\0':
981 if (rts_argv[arg][1] == 'P') {
982 RtsFlags.CcFlags.doCostCentres =
983 COST_CENTRES_VERBOSE;
984 } else {
985 RtsFlags.CcFlags.doCostCentres =
986 COST_CENTRES_SUMMARY;
987 }
988 break;
989 default:
990 unchecked_arg_start++;
991 goto check_rest;
992 }
993 ) break;
994
995 case 'R':
996 OPTION_SAFE;
997 PROFILING_BUILD_ONLY(
998 RtsFlags.ProfFlags.maxRetainerSetSize =
999 atof(rts_argv[arg]+2);
1000 ) break;
1001 case 'L':
1002 OPTION_SAFE;
1003 PROFILING_BUILD_ONLY(
1004 RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
1005 if(RtsFlags.ProfFlags.ccsLength <= 0) {
1006 bad_option(rts_argv[arg]);
1007 }
1008 ) break;
1009 case 'h': /* serial heap profile */
1010 #if !defined(PROFILING)
1011 OPTION_UNSAFE;
1012 switch (rts_argv[arg][2]) {
1013 case '\0':
1014 case 'T':
1015 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
1016 break;
1017 default:
1018 errorBelch("invalid heap profile option: %s",rts_argv[arg]);
1019 error = rtsTrue;
1020 }
1021 #else
1022 OPTION_SAFE;
1023 PROFILING_BUILD_ONLY(
1024 error = read_heap_profiling_flag(rts_argv[arg]);
1025 );
1026 #endif /* PROFILING */
1027 break;
1028
1029 case 'i': /* heap sample interval */
1030 OPTION_UNSAFE;
1031 if (rts_argv[arg][2] == '\0') {
1032 /* use default */
1033 } else {
1034 RtsFlags.ProfFlags.heapProfileInterval =
1035 fsecondsToTime(atof(rts_argv[arg]+2));
1036 }
1037 break;
1038
1039 /* =========== CONCURRENT ========================= */
1040 case 'C': /* context switch interval */
1041 OPTION_UNSAFE;
1042 if (rts_argv[arg][2] == '\0')
1043 RtsFlags.ConcFlags.ctxtSwitchTime = 0;
1044 else {
1045 RtsFlags.ConcFlags.ctxtSwitchTime =
1046 fsecondsToTime(atof(rts_argv[arg]+2));
1047 }
1048 break;
1049
1050 case 'V': /* master tick interval */
1051 OPTION_UNSAFE;
1052 if (rts_argv[arg][2] == '\0') {
1053 // turns off ticks completely
1054 RtsFlags.MiscFlags.tickInterval = 0;
1055 } else {
1056 RtsFlags.MiscFlags.tickInterval =
1057 fsecondsToTime(atof(rts_argv[arg]+2));
1058 }
1059 break;
1060
1061 #if !defined(NOSMP)
1062 case 'N':
1063 OPTION_SAFE;
1064 THREADED_BUILD_ONLY(
1065 if (rts_argv[arg][2] == '\0') {
1066 #if defined(PROFILING)
1067 RtsFlags.ParFlags.nNodes = 1;
1068 #else
1069 RtsFlags.ParFlags.nNodes = getNumberOfProcessors();
1070 #endif
1071 } else {
1072 int nNodes;
1073 OPTION_SAFE; /* but see extra checks below... */
1074 nNodes = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1075 if (nNodes <= 0) {
1076 errorBelch("bad value for -N");
1077 error = rtsTrue;
1078 }
1079 if (rtsOptsEnabled == RtsOptsSafeOnly &&
1080 nNodes > (int)getNumberOfProcessors()) {
1081 errorRtsOptsDisabled("Using large values for -N is not allowed by default. %s");
1082 stg_exit(EXIT_FAILURE);
1083 }
1084 RtsFlags.ParFlags.nNodes = (nat)nNodes;
1085 }
1086 ) break;
1087
1088 case 'g':
1089 OPTION_UNSAFE;
1090 THREADED_BUILD_ONLY(
1091 switch (rts_argv[arg][2]) {
1092 case '1':
1093 // backwards compat only
1094 RtsFlags.ParFlags.parGcEnabled = rtsFalse;
1095 break;
1096 default:
1097 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1098 error = rtsTrue;
1099 break;
1100 }
1101 ) break;
1102
1103 case 'q':
1104 OPTION_UNSAFE;
1105 THREADED_BUILD_ONLY(
1106 switch (rts_argv[arg][2]) {
1107 case '\0':
1108 errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1109 error = rtsTrue;
1110 break;
1111 case 'g':
1112 if (rts_argv[arg][3] == '\0') {
1113 RtsFlags.ParFlags.parGcEnabled = rtsFalse;
1114 } else {
1115 RtsFlags.ParFlags.parGcEnabled = rtsTrue;
1116 RtsFlags.ParFlags.parGcGen
1117 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1118 }
1119 break;
1120 case 'b':
1121 if (rts_argv[arg][3] == '\0') {
1122 RtsFlags.ParFlags.parGcLoadBalancingEnabled =
1123 rtsFalse;
1124 }
1125 else {
1126 RtsFlags.ParFlags.parGcLoadBalancingEnabled =
1127 rtsTrue;
1128 RtsFlags.ParFlags.parGcLoadBalancingGen
1129 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1130 }
1131 break;
1132 case 'i':
1133 RtsFlags.ParFlags.parGcNoSyncWithIdle
1134 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1135 break;
1136 case 'a':
1137 RtsFlags.ParFlags.setAffinity = rtsTrue;
1138 break;
1139 case 'm':
1140 RtsFlags.ParFlags.migrate = rtsFalse;
1141 break;
1142 case 'w':
1143 // -qw was removed; accepted for backwards compat
1144 break;
1145 default:
1146 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1147 error = rtsTrue;
1148 break;
1149 }
1150 ) break;
1151 #endif
1152 /* =========== PARALLEL =========================== */
1153 case 'e':
1154 OPTION_UNSAFE;
1155 THREADED_BUILD_ONLY(
1156 if (rts_argv[arg][2] != '\0') {
1157 RtsFlags.ParFlags.maxLocalSparks
1158 = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1159 if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
1160 errorBelch("bad value for -e");
1161 error = rtsTrue;
1162 }
1163 }
1164 ) break;
1165
1166 /* =========== TICKY ============================== */
1167
1168 case 'r': /* Basic profiling stats */
1169 OPTION_SAFE;
1170 TICKY_BUILD_ONLY(
1171
1172 RtsFlags.TickyFlags.showTickyStats = rtsTrue;
1173
1174 {
1175 int r;
1176 if (rts_argv[arg][2] != '\0') {
1177 OPTION_UNSAFE;
1178 }
1179 r = openStatsFile(rts_argv[arg]+2,
1180 TICKY_FILENAME_FMT,
1181 &RtsFlags.TickyFlags.tickyFile);
1182 if (r == -1) { error = rtsTrue; }
1183 }
1184 ) break;
1185
1186 /* =========== TRACING ---------=================== */
1187
1188 case 'l':
1189 OPTION_SAFE;
1190 TRACING_BUILD_ONLY(
1191 RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
1192 read_trace_flags(&rts_argv[arg][2]);
1193 );
1194 break;
1195
1196 case 'v':
1197 OPTION_SAFE;
1198 DEBUG_BUILD_ONLY(
1199 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
1200 read_trace_flags(&rts_argv[arg][2]);
1201 );
1202 break;
1203
1204 /* =========== EXTENDED OPTIONS =================== */
1205
1206 case 'x': /* Extend the argument space */
1207 unchecked_arg_start++;
1208 switch(rts_argv[arg][2]) {
1209 case '\0':
1210 OPTION_SAFE;
1211 errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1212 error = rtsTrue;
1213 break;
1214
1215 case 'b': /* heapBase in hex; undocumented */
1216 OPTION_UNSAFE;
1217 if (rts_argv[arg][3] != '\0') {
1218 RtsFlags.GcFlags.heapBase
1219 = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1220 } else {
1221 errorBelch("-xb: requires argument");
1222 error = rtsTrue;
1223 }
1224 break;
1225
1226 #if defined(x86_64_HOST_ARCH)
1227 case 'm': /* linkerMemBase */
1228 OPTION_UNSAFE;
1229 if (rts_argv[arg][3] != '\0') {
1230 RtsFlags.MiscFlags.linkerMemBase
1231 = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1232 if (RtsFlags.MiscFlags.linkerMemBase > 0x80000000) {
1233 errorBelch("-xm: value must be <80000000");
1234 error = rtsTrue;
1235 }
1236 } else {
1237 RtsFlags.MiscFlags.linkerMemBase = 0;
1238 }
1239 break;
1240 #endif
1241
1242 case 'c': /* Debugging tool: show current cost centre on
1243 an exception */
1244 OPTION_SAFE;
1245 PROFILING_BUILD_ONLY(
1246 RtsFlags.ProfFlags.showCCSOnException = rtsTrue;
1247 );
1248 unchecked_arg_start++;
1249 goto check_rest;
1250
1251 case 't': /* Include memory used by TSOs in a heap profile */
1252 OPTION_SAFE;
1253 PROFILING_BUILD_ONLY(
1254 RtsFlags.ProfFlags.includeTSOs = rtsTrue;
1255 );
1256 unchecked_arg_start++;
1257 goto check_rest;
1258
1259 /*
1260 * The option prefix '-xx' is reserved for future
1261 * extension. KSW 1999-11.
1262 */
1263
1264 case 'q':
1265 OPTION_UNSAFE;
1266 RtsFlags.GcFlags.allocLimitGrace
1267 = decodeSize(rts_argv[arg], 3, BLOCK_SIZE, HS_INT_MAX)
1268 / BLOCK_SIZE;
1269 break;
1270
1271 default:
1272 OPTION_SAFE;
1273 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1274 error = rtsTrue;
1275 break;
1276 }
1277 break; /* defensive programming */
1278
1279 /* check the rest to be sure there is nothing afterwards.*/
1280 /* see Trac #9839 */
1281 check_rest:
1282 {
1283 /* start checking from the first unchecked position,
1284 * not from index 2*/
1285 /* see Trac #9839 */
1286 if (rts_argv[arg][unchecked_arg_start] != '\0') {
1287 errorBelch("flag -%c given an argument"
1288 " when none was expected: %s",
1289 rts_argv[arg][1],rts_argv[arg]);
1290 error = rtsTrue;
1291 }
1292 break;
1293 }
1294
1295 /* =========== OH DEAR ============================ */
1296 default:
1297 OPTION_SAFE;
1298 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1299 error = rtsTrue;
1300 break;
1301 }
1302
1303 if (!option_checked) {
1304 /* Naughty! Someone didn't use OPTION_UNSAFE / OPTION_SAFE for
1305 an option above */
1306 errorBelch("Internal error in the RTS options parser");
1307 stg_exit(EXIT_FAILURE);
1308 }
1309 }
1310 }
1311
1312 if (error) errorUsage();
1313 }
1314
1315 /* -----------------------------------------------------------------------------
1316 * normaliseRtsOpts: Set some derived values, and make sure things are
1317 * within sensible ranges.
1318 * -------------------------------------------------------------------------- */
1319
1320 static void normaliseRtsOpts (void)
1321 {
1322 if (RtsFlags.MiscFlags.tickInterval < 0) {
1323 RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
1324 }
1325
1326 // If the master timer is disabled, turn off the other timers.
1327 if (RtsFlags.MiscFlags.tickInterval == 0) {
1328 RtsFlags.ConcFlags.ctxtSwitchTime = 0;
1329 RtsFlags.GcFlags.idleGCDelayTime = 0;
1330 RtsFlags.ProfFlags.heapProfileInterval = 0;
1331 }
1332
1333 // Determine what tick interval we should use for the RTS timer
1334 // by taking the shortest of the various intervals that we need to
1335 // monitor.
1336 if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1337 RtsFlags.MiscFlags.tickInterval =
1338 stg_min(RtsFlags.ConcFlags.ctxtSwitchTime,
1339 RtsFlags.MiscFlags.tickInterval);
1340 }
1341
1342 if (RtsFlags.GcFlags.idleGCDelayTime > 0) {
1343 RtsFlags.MiscFlags.tickInterval =
1344 stg_min(RtsFlags.GcFlags.idleGCDelayTime,
1345 RtsFlags.MiscFlags.tickInterval);
1346 }
1347
1348 if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
1349 RtsFlags.MiscFlags.tickInterval =
1350 stg_min(RtsFlags.ProfFlags.heapProfileInterval,
1351 RtsFlags.MiscFlags.tickInterval);
1352 }
1353
1354 if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1355 RtsFlags.ConcFlags.ctxtSwitchTicks =
1356 RtsFlags.ConcFlags.ctxtSwitchTime /
1357 RtsFlags.MiscFlags.tickInterval;
1358 } else {
1359 RtsFlags.ConcFlags.ctxtSwitchTicks = 0;
1360 }
1361
1362 if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
1363 RtsFlags.ProfFlags.heapProfileIntervalTicks =
1364 RtsFlags.ProfFlags.heapProfileInterval /
1365 RtsFlags.MiscFlags.tickInterval;
1366 } else {
1367 RtsFlags.ProfFlags.heapProfileIntervalTicks = 0;
1368 }
1369
1370 if (RtsFlags.GcFlags.stkChunkBufferSize >
1371 RtsFlags.GcFlags.stkChunkSize / 2) {
1372 errorBelch("stack chunk buffer size (-kb) must be less than 50%%\n"
1373 "of the stack chunk size (-kc)");
1374 errorUsage();
1375 }
1376 }
1377
1378 static void errorUsage (void)
1379 {
1380 const char **p;
1381
1382 fflush(stdout);
1383 for (p = usage_text; *p; p++)
1384 errorBelch("%s", *p);
1385 stg_exit(EXIT_FAILURE);
1386 }
1387
1388 static void
1389 stats_fprintf(FILE *f, char *s, ...)
1390 {
1391 va_list ap;
1392 va_start(ap,s);
1393 if (f == NULL) {
1394 vdebugBelch(s, ap);
1395 } else {
1396 vfprintf(f, s, ap);
1397 }
1398 va_end(ap);
1399 }
1400
1401 /* -----------------------------------------------------------------------------
1402 * openStatsFile: open a file in which to put some runtime stats
1403 * -------------------------------------------------------------------------- */
1404
1405 static int // return -1 on error
1406 openStatsFile (char *filename, // filename, or NULL
1407 const char *filename_fmt, // if filename == NULL, use
1408 // this fmt with sprintf to
1409 // generate the filename. %s
1410 // expands to the program name.
1411 FILE **file_ret) // return the FILE*
1412 {
1413 FILE *f = NULL;
1414
1415 if (strequal(filename, "stderr")
1416 || (filename_fmt == NULL && *filename == '\0')) {
1417 f = NULL; /* NULL means use debugBelch */
1418 } else {
1419 if (*filename != '\0') { /* stats file specified */
1420 f = fopen(filename,"w");
1421 } else {
1422 /* default <program>.<ext> */
1423 char stats_filename[STATS_FILENAME_MAXLEN];
1424 sprintf(stats_filename, filename_fmt, prog_name);
1425 f = fopen(stats_filename,"w");
1426 }
1427 if (f == NULL) {
1428 errorBelch("Can't open stats file %s\n", filename);
1429 return -1;
1430 }
1431 }
1432 *file_ret = f;
1433
1434 return 0;
1435 }
1436
1437 /* -----------------------------------------------------------------------------
1438 * initStatsFile: write a line to the file containing the program name
1439 * and the arguments it was invoked with.
1440 -------------------------------------------------------------------------- */
1441
1442 static void initStatsFile (FILE *f)
1443 {
1444 /* Write prog_argv and rts_argv into start of stats file */
1445 int count;
1446 for (count = 0; count < prog_argc; count++) {
1447 stats_fprintf(f, "%s ", prog_argv[count]);
1448 }
1449 stats_fprintf(f, "+RTS ");
1450 for (count = 0; count < rts_argc; count++)
1451 stats_fprintf(f, "%s ", rts_argv[count]);
1452 stats_fprintf(f, "\n");
1453 }
1454
1455 /* -----------------------------------------------------------------------------
1456 * decodeSize: parse a string containing a size, like 300K or 1.2M
1457 -------------------------------------------------------------------------- */
1458
1459 static StgWord64
1460 decodeSize(const char *flag, nat offset, StgWord64 min, StgWord64 max)
1461 {
1462 char c;
1463 const char *s;
1464 StgDouble m;
1465 StgWord64 val;
1466
1467 s = flag + offset;
1468
1469 if (!*s)
1470 {
1471 m = 0;
1472 }
1473 else
1474 {
1475 m = atof(s);
1476 c = s[strlen(s)-1];
1477
1478 if (c == 'g' || c == 'G')
1479 m *= 1024*1024*1024;
1480 else if (c == 'm' || c == 'M')
1481 m *= 1024*1024;
1482 else if (c == 'k' || c == 'K')
1483 m *= 1024;
1484 else if (c == 'w' || c == 'W')
1485 m *= sizeof(W_);
1486 }
1487
1488 val = (StgWord64)m;
1489
1490 if (m < 0 || val < min || val > max) {
1491 // printf doesn't like 64-bit format specs on Windows
1492 // apparently, so fall back to unsigned long.
1493 errorBelch("error in RTS option %s: size outside allowed range (%" FMT_Word " - %" FMT_Word ")", flag, (W_)min, (W_)max);
1494 stg_exit(EXIT_FAILURE);
1495 }
1496
1497 return val;
1498 }
1499
1500 #ifdef DEBUG
1501 static void read_debug_flags(const char* arg)
1502 {
1503 // Already parsed "-D"
1504 const char *c;
1505 for (c = arg + 2; *c != '\0'; c++) {
1506 switch (*c) {
1507 case 's':
1508 RtsFlags.DebugFlags.scheduler = rtsTrue;
1509 break;
1510 case 'i':
1511 RtsFlags.DebugFlags.interpreter = rtsTrue;
1512 break;
1513 case 'w':
1514 RtsFlags.DebugFlags.weak = rtsTrue;
1515 break;
1516 case 'G':
1517 RtsFlags.DebugFlags.gccafs = rtsTrue;
1518 break;
1519 case 'g':
1520 RtsFlags.DebugFlags.gc = rtsTrue;
1521 break;
1522 case 'b':
1523 RtsFlags.DebugFlags.block_alloc = rtsTrue;
1524 break;
1525 case 'S':
1526 RtsFlags.DebugFlags.sanity = rtsTrue;
1527 break;
1528 case 't':
1529 RtsFlags.DebugFlags.stable = rtsTrue;
1530 break;
1531 case 'p':
1532 RtsFlags.DebugFlags.prof = rtsTrue;
1533 break;
1534 case 'l':
1535 RtsFlags.DebugFlags.linker = rtsTrue;
1536 break;
1537 case 'a':
1538 RtsFlags.DebugFlags.apply = rtsTrue;
1539 break;
1540 case 'm':
1541 RtsFlags.DebugFlags.stm = rtsTrue;
1542 break;
1543 case 'z':
1544 RtsFlags.DebugFlags.squeeze = rtsTrue;
1545 break;
1546 case 'c':
1547 RtsFlags.DebugFlags.hpc = rtsTrue;
1548 break;
1549 case 'r':
1550 RtsFlags.DebugFlags.sparks = rtsTrue;
1551 break;
1552 default:
1553 bad_option( arg );
1554 }
1555 }
1556 // -Dx also turns on -v. Use -l to direct trace
1557 // events to the .eventlog file instead.
1558 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
1559 }
1560 #endif
1561
1562 #ifdef USE_PAPI
1563 static void read_papi_flags(const char *arg)
1564 {
1565 // Already parsed "-a"
1566 switch(arg[2]) {
1567 case '1':
1568 RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L1;
1569 break;
1570 case '2':
1571 RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L2;
1572 break;
1573 case 'b':
1574 RtsFlags.PapiFlags.eventType = PAPI_FLAG_BRANCH;
1575 break;
1576 case 's':
1577 RtsFlags.PapiFlags.eventType = PAPI_FLAG_STALLS;
1578 break;
1579 case 'e':
1580 RtsFlags.PapiFlags.eventType = PAPI_FLAG_CB_EVENTS;
1581 break;
1582 case '+':
1583 case '#':
1584 if (RtsFlags.PapiFlags.numUserEvents >= MAX_PAPI_USER_EVENTS) {
1585 errorBelch("maximum number of PAPI events reached");
1586 stg_exit(EXIT_FAILURE);
1587 }
1588 nat eventNum = RtsFlags.PapiFlags.numUserEvents++;
1589 char kind = arg[2];
1590 nat eventKind =
1591 kind == '+' ? PAPI_PRESET_EVENT_KIND : PAPI_NATIVE_EVENT_KIND;
1592
1593 RtsFlags.PapiFlags.userEvents[eventNum] = arg + 3;
1594 RtsFlags.PapiFlags.eventType = PAPI_USER_EVENTS;
1595 RtsFlags.PapiFlags.userEventsKind[eventNum] = eventKind;
1596 break;
1597 default:
1598 bad_option( arg );
1599 }
1600 }
1601 #endif
1602
1603 #ifdef PROFILING
1604 // Parse a "-h" flag, returning whether the parse resulted in an error.
1605 static rtsBool read_heap_profiling_flag(const char *arg)
1606 {
1607 // Already parsed "-h"
1608 rtsBool error = rtsFalse;
1609 switch (arg[2]) {
1610 case '\0':
1611 case 'C':
1612 case 'c':
1613 case 'M':
1614 case 'm':
1615 case 'D':
1616 case 'd':
1617 case 'Y':
1618 case 'y':
1619 case 'R':
1620 case 'r':
1621 case 'B':
1622 case 'b':
1623 if (arg[2] != '\0' && arg[3] != '\0') {
1624 {
1625 char *left = strchr(arg, '{');
1626 char *right = strrchr(arg, '}');
1627
1628 // curly braces are optional, for
1629 // backwards compat.
1630 if (left)
1631 left = left+1;
1632 else
1633 left = arg + 3;
1634
1635 if (!right)
1636 right = arg + strlen(arg);
1637
1638 *right = '\0';
1639
1640 switch (arg[2]) {
1641 case 'c': // cost centre label select
1642 RtsFlags.ProfFlags.ccSelector = left;
1643 break;
1644 case 'C':
1645 RtsFlags.ProfFlags.ccsSelector = left;
1646 break;
1647 case 'M':
1648 case 'm': // cost centre module select
1649 RtsFlags.ProfFlags.modSelector = left;
1650 break;
1651 case 'D':
1652 case 'd': // closure descr select
1653 RtsFlags.ProfFlags.descrSelector = left;
1654 break;
1655 case 'Y':
1656 case 'y': // closure type select
1657 RtsFlags.ProfFlags.typeSelector = left;
1658 break;
1659 case 'R':
1660 case 'r': // retainer select
1661 RtsFlags.ProfFlags.retainerSelector = left;
1662 break;
1663 case 'B':
1664 case 'b': // biography select
1665 RtsFlags.ProfFlags.bioSelector = left;
1666 break;
1667 }
1668 }
1669 break;
1670 }
1671
1672 if (RtsFlags.ProfFlags.doHeapProfile != 0) {
1673 errorBelch("multiple heap profile options");
1674 error = rtsTrue;
1675 break;
1676 }
1677
1678 switch (arg[2]) {
1679 case '\0':
1680 case 'C':
1681 case 'c':
1682 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
1683 break;
1684 case 'M':
1685 case 'm':
1686 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
1687 break;
1688 case 'D':
1689 case 'd':
1690 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
1691 break;
1692 case 'Y':
1693 case 'y':
1694 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
1695 break;
1696 case 'R':
1697 case 'r':
1698 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
1699 break;
1700 case 'B':
1701 case 'b':
1702 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
1703 break;
1704 }
1705 break;
1706
1707 default:
1708 errorBelch("invalid heap profile option: %s", arg);
1709 error = rtsTrue;
1710 }
1711
1712 return error;
1713 }
1714 #endif
1715
1716 #if defined(TRACING)
1717 static void read_trace_flags(const char *arg)
1718 {
1719 const char *c;
1720 rtsBool enabled = rtsTrue;
1721 /* Syntax for tracing flags currently looks like:
1722 *
1723 * -l To turn on eventlog tracing with default trace classes
1724 * -lx Turn on class 'x' (for some class listed below)
1725 * -l-x Turn off class 'x'
1726 * -la Turn on all classes
1727 * -l-a Turn off all classes
1728 *
1729 * This lets users say things like:
1730 * -la-p "all but sparks"
1731 * -l-ap "only sparks"
1732 */
1733
1734 /* Start by turning on the default tracing flags.
1735 *
1736 * Currently this is all the trace classes, except full-detail sparks.
1737 * Similarly, in future we might default to slightly less verbose
1738 * scheduler or GC tracing.
1739 */
1740 RtsFlags.TraceFlags.scheduler = rtsTrue;
1741 RtsFlags.TraceFlags.gc = rtsTrue;
1742 RtsFlags.TraceFlags.sparks_sampled = rtsTrue;
1743 RtsFlags.TraceFlags.user = rtsTrue;
1744
1745 for (c = arg; *c != '\0'; c++) {
1746 switch(*c) {
1747 case '\0':
1748 break;
1749 case '-':
1750 enabled = rtsFalse;
1751 break;
1752 case 'a':
1753 RtsFlags.TraceFlags.scheduler = enabled;
1754 RtsFlags.TraceFlags.gc = enabled;
1755 RtsFlags.TraceFlags.sparks_sampled = enabled;
1756 RtsFlags.TraceFlags.sparks_full = enabled;
1757 RtsFlags.TraceFlags.user = enabled;
1758 enabled = rtsTrue;
1759 break;
1760
1761 case 's':
1762 RtsFlags.TraceFlags.scheduler = enabled;
1763 enabled = rtsTrue;
1764 break;
1765 case 'p':
1766 RtsFlags.TraceFlags.sparks_sampled = enabled;
1767 enabled = rtsTrue;
1768 break;
1769 case 'f':
1770 RtsFlags.TraceFlags.sparks_full = enabled;
1771 enabled = rtsTrue;
1772 break;
1773 case 't':
1774 RtsFlags.TraceFlags.timestamp = enabled;
1775 enabled = rtsTrue;
1776 break;
1777 case 'g':
1778 RtsFlags.TraceFlags.gc = enabled;
1779 enabled = rtsTrue;
1780 break;
1781 case 'u':
1782 RtsFlags.TraceFlags.user = enabled;
1783 enabled = rtsTrue;
1784 break;
1785 default:
1786 errorBelch("unknown trace option: %c",*c);
1787 break;
1788 }
1789 }
1790 }
1791 #endif
1792
1793 static void GNU_ATTRIBUTE(__noreturn__)
1794 bad_option(const char *s)
1795 {
1796 errorBelch("bad RTS option: %s", s);
1797 stg_exit(EXIT_FAILURE);
1798 }
1799
1800 /* ----------------------------------------------------------------------------
1801 Copying and freeing argc/argv
1802 ------------------------------------------------------------------------- */
1803
1804 static char * copyArg(char *arg)
1805 {
1806 char *new_arg = stgMallocBytes(strlen(arg) + 1, "copyArg");
1807 strcpy(new_arg, arg);
1808 return new_arg;
1809 }
1810
1811 static char ** copyArgv(int argc, char *argv[])
1812 {
1813 int i;
1814 char **new_argv;
1815
1816 new_argv = stgCallocBytes(argc + 1, sizeof (char *), "copyArgv 1");
1817 for (i = 0; i < argc; i++) {
1818 new_argv[i] = copyArg(argv[i]);
1819 }
1820 new_argv[argc] = NULL;
1821 return new_argv;
1822 }
1823
1824 static void freeArgv(int argc, char *argv[])
1825 {
1826 int i;
1827 if (argv != NULL) {
1828 for (i = 0; i < argc; i++) {
1829 stgFree(argv[i]);
1830 }
1831 stgFree(argv);
1832 }
1833 }
1834
1835 /* -----------------------------------------------------------------------------
1836 Getting/Setting the program's arguments.
1837
1838 These are used by System.Environment, and parts of the RTS.
1839 -------------------------------------------------------------------------- */
1840
1841 void
1842 setProgName(char *argv[])
1843 {
1844 char *last_slash;
1845
1846 if (argv[0] == NULL) { // #7037
1847 prog_name = "";
1848 return;
1849 }
1850
1851 /* Remove directory from argv[0] -- default files in current directory */
1852 #if !defined(mingw32_HOST_OS)
1853 if ( (last_slash = (char *) strrchr(argv[0], '/')) != NULL ) {
1854 prog_name = last_slash+1;
1855 } else {
1856 prog_name = argv[0];
1857 }
1858 #else
1859 last_slash = argv[0] + (strlen(argv[0]) - 1);
1860 while ( last_slash > argv[0] ) {
1861 if ( *last_slash == '/' || *last_slash == '\\' ) {
1862 prog_name = last_slash+1;
1863 return;
1864 }
1865 last_slash--;
1866 }
1867 prog_name = argv[0];
1868 #endif
1869 }
1870
1871 void
1872 getProgArgv(int *argc, char **argv[])
1873 {
1874 if (argc) { *argc = prog_argc; }
1875 if (argv) { *argv = prog_argv; }
1876 }
1877
1878 void
1879 setProgArgv(int argc, char *argv[])
1880 {
1881 prog_argc = argc;
1882 prog_argv = copyArgv(argc,argv);
1883 setProgName(prog_argv);
1884 }
1885
1886 static void
1887 freeProgArgv(void)
1888 {
1889 freeArgv(prog_argc,prog_argv);
1890 prog_argc = 0;
1891 prog_argv = NULL;
1892 }
1893
1894 /* ----------------------------------------------------------------------------
1895 The full argv - a copy of the original program's argc/argv
1896 ------------------------------------------------------------------------- */
1897
1898 void
1899 setFullProgArgv(int argc, char *argv[])
1900 {
1901 full_prog_argc = argc;
1902 full_prog_argv = copyArgv(argc,argv);
1903 }
1904
1905 /* These functions record and recall the full arguments, including the
1906 +RTS ... -RTS options. The reason for adding them was so that the
1907 ghc-inplace program can pass /all/ the arguments on to the real ghc. */
1908 void
1909 getFullProgArgv(int *argc, char **argv[])
1910 {
1911 if (argc) { *argc = full_prog_argc; }
1912 if (argv) { *argv = full_prog_argv; }
1913 }
1914
1915 void
1916 freeFullProgArgv (void)
1917 {
1918 freeArgv(full_prog_argc, full_prog_argv);
1919 full_prog_argc = 0;
1920 full_prog_argv = NULL;
1921 }
1922
1923 /* ----------------------------------------------------------------------------
1924 The Win32 argv
1925 ------------------------------------------------------------------------- */
1926
1927 #if defined(mingw32_HOST_OS)
1928 void freeWin32ProgArgv (void);
1929
1930 void
1931 freeWin32ProgArgv (void)
1932 {
1933 int i;
1934
1935 if (win32_prog_argv != NULL) {
1936 for (i = 0; i < win32_prog_argc; i++) {
1937 stgFree(win32_prog_argv[i]);
1938 }
1939 stgFree(win32_prog_argv);
1940 }
1941
1942 win32_prog_argc = 0;
1943 win32_prog_argv = NULL;
1944 }
1945
1946 void
1947 getWin32ProgArgv(int *argc, wchar_t **argv[])
1948 {
1949 *argc = win32_prog_argc;
1950 *argv = win32_prog_argv;
1951 }
1952
1953 void
1954 setWin32ProgArgv(int argc, wchar_t *argv[])
1955 {
1956 int i;
1957
1958 freeWin32ProgArgv();
1959
1960 win32_prog_argc = argc;
1961 if (argv == NULL) {
1962 win32_prog_argv = NULL;
1963 return;
1964 }
1965
1966 win32_prog_argv = stgCallocBytes(argc + 1, sizeof (wchar_t *),
1967 "setWin32ProgArgv 1");
1968 for (i = 0; i < argc; i++) {
1969 win32_prog_argv[i] = stgMallocBytes((wcslen(argv[i]) + 1) * sizeof(wchar_t),
1970 "setWin32ProgArgv 2");
1971 wcscpy(win32_prog_argv[i], argv[i]);
1972 }
1973 win32_prog_argv[argc] = NULL;
1974 }
1975 #endif
1976
1977 /* ----------------------------------------------------------------------------
1978 The RTS argv
1979 ------------------------------------------------------------------------- */
1980
1981 static void
1982 freeRtsArgv(void)
1983 {
1984 freeArgv(rts_argc,rts_argv);
1985 rts_argc = 0;
1986 rts_argv = NULL;
1987 rts_argv_size = 0;
1988 }
1989
1990 /* ----------------------------------------------------------------------------
1991 All argvs
1992 ------------------------------------------------------------------------- */
1993
1994 void freeRtsArgs(void)
1995 {
1996 #if defined(mingw32_HOST_OS)
1997 freeWin32ProgArgv();
1998 #endif
1999 freeFullProgArgv();
2000 freeProgArgv();
2001 freeRtsArgv();
2002 }