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