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