RtsFlags.c 82.4 KB
Newer Older
1
/* -----------------------------------------------------------------------------
2 3
 *
 * (c) The AQUA Project, Glasgow University, 1994-1997
Simon Marlow's avatar
Simon Marlow committed
4
 * (c) The GHC Team, 1998-2006
5 6 7 8 9
 *
 * Functions for parsing the argument list.
 *
 * ---------------------------------------------------------------------------*/

10
#include "PosixSource.h"
11
#include "Rts.h"
Simon Marlow's avatar
Simon Marlow committed
12

13
#include "RtsUtils.h"
14
#include "Profiling.h"
15
#include "RtsFlags.h"
16
#include "sm/OSMem.h"
17
#include "hooks/Hooks.h"
Simon Marlow's avatar
Simon Marlow committed
18
#include "Capability.h"
19

Ben Gamari's avatar
Ben Gamari committed
20
#if defined(HAVE_CTYPE_H)
21
#include <ctype.h>
22 23
#endif

24 25
#include <string.h>

Ben Gamari's avatar
Ben Gamari committed
26
#if defined(HAVE_UNISTD_H)
27 28 29
#include <unistd.h>
#endif

Ben Gamari's avatar
Ben Gamari committed
30
#if defined(HAVE_SYS_TYPES_H)
31 32 33
#include <sys/types.h>
#endif

34 35
#include <fs_rts.h>

36 37
// Flag Structure
RTS_FLAGS RtsFlags;
38 39 40 41

/*
 * Split argument lists
 */
sof's avatar
sof committed
42
int     prog_argc = 0;    /* an "int" so as to match normal "argc" */
43
char  **prog_argv = NULL;
44 45
int     full_prog_argc = 0;    /* an "int" so as to match normal "argc" */
char  **full_prog_argv = NULL;
sof's avatar
sof committed
46
char   *prog_name = NULL; /* 'basename' of prog_argv[0] */
47
int     rts_argc = 0;  /* ditto */
48
char  **rts_argv = NULL;
49
int     rts_argv_size = 0;
50
#if defined(mingw32_HOST_OS)
51 52 53 54 55
// On Windows hs_main uses GetCommandLineW to get Unicode arguments and
// passes them along UTF8 encoded as argv. We store them here in order to
// free them on exit.
int       win32_full_utf8_argc = 0;
char**    win32_utf8_argv = NULL;
56
#endif
57

58 59 60 61 62 63
// The global rtsConfig, set from the RtsConfig supplied by the call
// to hs_init_ghc().
RtsConfig rtsConfig;

const RtsConfig defaultRtsConfig  = {
    .rts_opts_enabled = RtsOptsSafeOnly,
Ben Gamari's avatar
Ben Gamari committed
64
    .rts_opts_suggestions = true,
65
    .rts_opts = NULL,
Ben Gamari's avatar
Ben Gamari committed
66 67
    .rts_hs_main = false,
    .keep_cafs = false,
68
    .eventlog_writer = &FileEventLogWriter,
69 70 71 72 73
    .defaultsHook = FlagDefaultsHook,
    .onExitHook = OnExitHook,
    .stackOverflowHook = StackOverflowHook,
    .outOfHeapHook = OutOfHeapHook,
    .mallocFailHook = MallocFailHook,
Simon Marlow's avatar
Simon Marlow committed
74 75 76
    .gcDoneHook = NULL,
    .longGCSync = LongGCSync,
    .longGCSyncEnd = LongGCSyncEnd
77 78
};

79
/*
thoughtpolice's avatar
thoughtpolice committed
80
 * constants, used later
81 82 83 84 85 86 87 88
 */
#define RTS 1
#define PGM 0

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

89
static void procRtsOpts (int rts_argc0, RtsOptsEnabledEnum enabled);
90 91 92

static void normaliseRtsOpts (void);

93
static void initStatsFile (FILE *f);
94

95 96
static int  openStatsFile (
    char *filename, const char *FILENAME_FMT, FILE **file_ret);
97

98
static StgWord64 decodeSize (
99
    const char *flag, uint32_t offset, StgWord64 min, StgWord64 max);
100

101
static void bad_option (const char *s);
102

Ben Gamari's avatar
Ben Gamari committed
103
#if defined(DEBUG)
104 105 106
static void read_debug_flags(const char *arg);
#endif

Ben Gamari's avatar
Ben Gamari committed
107
#if defined(PROFILING)
Ben Gamari's avatar
Ben Gamari committed
108
static bool read_heap_profiling_flag(const char *arg);
109 110
#endif

Ben Gamari's avatar
Ben Gamari committed
111
#if defined(TRACING)
112
static void read_trace_flags(const char *arg);
113
#endif
114

115
static void errorUsage (void) GNU_ATTRIBUTE(__noreturn__);
116

117 118 119
#if defined(mingw32_HOST_OS)
static char** win32_full_utf8_argv;
#endif
120
static char *  copyArg (char *arg);
121 122
static char ** copyArgv (int argc, char *argv[]);
static void    freeArgv (int argc, char *argv[]);
123
static void setProgName (char *argv[]);
124

125
static void errorRtsOptsDisabled (const char *s);
126

127 128 129 130 131 132
/* -----------------------------------------------------------------------------
 * Command-line option parsing routines.
 * ---------------------------------------------------------------------------*/

void initRtsFlagsDefaults(void)
{
133 134 135
    StgWord64 maxStkSize = 8 * getPhysicalMemorySize() / 10;
    // if getPhysicalMemorySize fails just move along with an 8MB limit
    if (maxStkSize == 0)
136
        maxStkSize = 8 * 1024 * 1024;
137 138 139
    // GcFlags.maxStkSiz is 32-bit, so we need to cap to prevent overflow (#17019)
    else if (maxStkSize > UINT32_MAX * sizeof(W_))
        maxStkSize = UINT32_MAX * sizeof(W_);
140

Austin Seipp's avatar
Austin Seipp committed
141
    RtsFlags.GcFlags.statsFile          = NULL;
Ben Gamari's avatar
Ben Gamari committed
142
    RtsFlags.GcFlags.giveStats          = NO_GC_STATS;
143

144
    RtsFlags.GcFlags.maxStkSize         = maxStkSize / sizeof(W_);
Austin Seipp's avatar
Austin Seipp committed
145
    RtsFlags.GcFlags.initialStkSize     = 1024 / sizeof(W_);
146 147
    RtsFlags.GcFlags.stkChunkSize       = (32 * 1024) / sizeof(W_);
    RtsFlags.GcFlags.stkChunkBufferSize = (1 * 1024) / sizeof(W_);
148

149
    RtsFlags.GcFlags.minAllocAreaSize   = (1024 * 1024)       / BLOCK_SIZE;
Simon Marlow's avatar
Simon Marlow committed
150
    RtsFlags.GcFlags.largeAllocLim      = 0; /* defaults to minAllocAreasize */
151
    RtsFlags.GcFlags.nurseryChunkSize   = 0;
152
    RtsFlags.GcFlags.minOldGenSize      = (1024 * 1024)       / BLOCK_SIZE;
Austin Seipp's avatar
Austin Seipp committed
153
    RtsFlags.GcFlags.maxHeapSize        = 0;    /* off by default */
dobenour's avatar
dobenour committed
154
    RtsFlags.GcFlags.heapLimitGrace     = (1024 * 1024);
Austin Seipp's avatar
Austin Seipp committed
155
    RtsFlags.GcFlags.heapSizeSuggestion = 0;    /* none */
Ben Gamari's avatar
Ben Gamari committed
156
    RtsFlags.GcFlags.heapSizeSuggestionAuto = false;
Austin Seipp's avatar
Austin Seipp committed
157
    RtsFlags.GcFlags.pcFreeHeap         = 3;    /* 3% */
158
    RtsFlags.GcFlags.oldGenFactor       = 2;
159
    RtsFlags.GcFlags.useNonmoving       = false;
160
    RtsFlags.GcFlags.nonmovingSelectorOpt = false;
161
    RtsFlags.GcFlags.generations        = 2;
Ben Gamari's avatar
Ben Gamari committed
162 163
    RtsFlags.GcFlags.squeezeUpdFrames   = true;
    RtsFlags.GcFlags.compact            = false;
164
    RtsFlags.GcFlags.compactThreshold   = 30.0;
Ben Gamari's avatar
Ben Gamari committed
165
    RtsFlags.GcFlags.sweep              = false;
Simon Marlow's avatar
Simon Marlow committed
166
    RtsFlags.GcFlags.idleGCDelayTime    = USToTime(300000); // 300ms
167
    RtsFlags.GcFlags.interIdleGCWait    = 0;
Ben Gamari's avatar
Ben Gamari committed
168
#if defined(THREADED_RTS)
Ben Gamari's avatar
Ben Gamari committed
169
    RtsFlags.GcFlags.doIdleGC           = true;
170
#else
Ben Gamari's avatar
Ben Gamari committed
171
    RtsFlags.GcFlags.doIdleGC           = false;
172
#endif
173
    RtsFlags.GcFlags.heapBase           = 0;   /* means don't care */
174
    RtsFlags.GcFlags.allocLimitGrace    = (100*1024) / BLOCK_SIZE;
Ben Gamari's avatar
Ben Gamari committed
175
    RtsFlags.GcFlags.numa               = false;
Simon Marlow's avatar
Simon Marlow committed
176
    RtsFlags.GcFlags.numaMask           = 1;
Ben Gamari's avatar
Ben Gamari committed
177
    RtsFlags.GcFlags.ringBell           = false;
Simon Marlow's avatar
Simon Marlow committed
178
    RtsFlags.GcFlags.longGCSync         = 0; /* detection turned off */
Ben Gamari's avatar
Ben Gamari committed
179 180 181 182 183 184

    RtsFlags.DebugFlags.scheduler       = false;
    RtsFlags.DebugFlags.interpreter     = false;
    RtsFlags.DebugFlags.weak            = false;
    RtsFlags.DebugFlags.gccafs          = false;
    RtsFlags.DebugFlags.gc              = false;
185
    RtsFlags.DebugFlags.nonmoving_gc    = false;
Ben Gamari's avatar
Ben Gamari committed
186 187
    RtsFlags.DebugFlags.block_alloc     = false;
    RtsFlags.DebugFlags.sanity          = false;
Tobias Guggenmos's avatar
Tobias Guggenmos committed
188
    RtsFlags.DebugFlags.zero_on_gc      = false;
Ben Gamari's avatar
Ben Gamari committed
189 190 191 192 193 194 195 196 197
    RtsFlags.DebugFlags.stable          = false;
    RtsFlags.DebugFlags.stm             = false;
    RtsFlags.DebugFlags.prof            = false;
    RtsFlags.DebugFlags.apply           = false;
    RtsFlags.DebugFlags.linker          = false;
    RtsFlags.DebugFlags.squeeze         = false;
    RtsFlags.DebugFlags.hpc             = false;
    RtsFlags.DebugFlags.sparks          = false;
    RtsFlags.DebugFlags.numa            = false;
198
    RtsFlags.DebugFlags.compact         = false;
199

Simon Marlow's avatar
Simon Marlow committed
200
#if defined(PROFILING)
niteria's avatar
niteria committed
201 202
    RtsFlags.CcFlags.doCostCentres      = COST_CENTRES_NONE;
    RtsFlags.CcFlags.outputFileNameStem = NULL;
Simon Marlow's avatar
Simon Marlow committed
203
#endif /* PROFILING */
204

Ben Gamari's avatar
Ben Gamari committed
205
    RtsFlags.ProfFlags.doHeapProfile      = false;
niteria's avatar
niteria committed
206
    RtsFlags.ProfFlags.heapProfileInterval = USToTime(100000); // 100ms
207

Ben Gamari's avatar
Ben Gamari committed
208
#if defined(PROFILING)
Ben Gamari's avatar
Ben Gamari committed
209 210
    RtsFlags.ProfFlags.includeTSOs        = false;
    RtsFlags.ProfFlags.showCCSOnException = false;
211
    RtsFlags.ProfFlags.maxRetainerSetSize = 8;
ravi@bluespec.com's avatar
ravi@bluespec.com committed
212
    RtsFlags.ProfFlags.ccsLength          = 25;
213 214 215 216
    RtsFlags.ProfFlags.modSelector        = NULL;
    RtsFlags.ProfFlags.descrSelector      = NULL;
    RtsFlags.ProfFlags.typeSelector       = NULL;
    RtsFlags.ProfFlags.ccSelector         = NULL;
217
    RtsFlags.ProfFlags.ccsSelector        = NULL;
218 219
    RtsFlags.ProfFlags.retainerSelector   = NULL;
    RtsFlags.ProfFlags.bioSelector        = NULL;
220 221
#endif

Ben Gamari's avatar
Ben Gamari committed
222
#if defined(TRACING)
223
    RtsFlags.TraceFlags.tracing       = TRACE_NONE;
Ben Gamari's avatar
Ben Gamari committed
224 225 226
    RtsFlags.TraceFlags.timestamp     = false;
    RtsFlags.TraceFlags.scheduler     = false;
    RtsFlags.TraceFlags.gc            = false;
227
    RtsFlags.TraceFlags.nonmoving_gc  = false;
Ben Gamari's avatar
Ben Gamari committed
228 229 230
    RtsFlags.TraceFlags.sparks_sampled= false;
    RtsFlags.TraceFlags.sparks_full   = false;
    RtsFlags.TraceFlags.user          = false;
231
    RtsFlags.TraceFlags.trace_output  = NULL;
Simon Marlow's avatar
Simon Marlow committed
232 233
#endif

Ben Gamari's avatar
Ben Gamari committed
234
#if defined(PROFILING)
Simon Marlow's avatar
Simon Marlow committed
235 236 237 238 239 240
    // When profiling we want a lot more ticks
    RtsFlags.MiscFlags.tickInterval     = USToTime(1000);  // 1ms
#else
    RtsFlags.MiscFlags.tickInterval     = DEFAULT_TICK_INTERVAL;
#endif
    RtsFlags.ConcFlags.ctxtSwitchTime   = USToTime(20000); // 20ms
241

Ben Gamari's avatar
Ben Gamari committed
242
    RtsFlags.MiscFlags.install_signal_handlers = true;
243
    RtsFlags.MiscFlags.install_seh_handlers    = true;
244
    RtsFlags.MiscFlags.generate_stack_trace    = true;
245
    RtsFlags.MiscFlags.generate_dump_file      = false;
246
    RtsFlags.MiscFlags.machineReadable         = false;
247
    RtsFlags.MiscFlags.disableDelayedOsMemoryReturn = false;
248
    RtsFlags.MiscFlags.internalCounters        = false;
249
    RtsFlags.MiscFlags.linkerAlwaysPic         = DEFAULT_LINKER_ALWAYS_PIC;
250
    RtsFlags.MiscFlags.linkerMemBase           = 0;
251

Ben Gamari's avatar
Ben Gamari committed
252
#if defined(THREADED_RTS)
Simon Marlow's avatar
Simon Marlow committed
253
    RtsFlags.ParFlags.nCapabilities     = 1;
Ben Gamari's avatar
Ben Gamari committed
254
    RtsFlags.ParFlags.migrate           = true;
255
    RtsFlags.ParFlags.parGcEnabled      = 1;
256
    RtsFlags.ParFlags.parGcGen          = 0;
Ben Gamari's avatar
Ben Gamari committed
257
    RtsFlags.ParFlags.parGcLoadBalancingEnabled = true;
258
    RtsFlags.ParFlags.parGcLoadBalancingGen = ~0u; /* auto, based on -A */
259
    RtsFlags.ParFlags.parGcNoSyncWithIdle   = 0;
260
    RtsFlags.ParFlags.parGcThreads      = 0; /* defaults to -N */
261
    RtsFlags.ParFlags.setAffinity       = 0;
262
#endif
263

Simon Marlow's avatar
Simon Marlow committed
264
#if defined(THREADED_RTS)
Austin Seipp's avatar
Austin Seipp committed
265
    RtsFlags.ParFlags.maxLocalSparks    = 4096;
Simon Marlow's avatar
Simon Marlow committed
266
#endif /* THREADED_RTS */
267

Ben Gamari's avatar
Ben Gamari committed
268
#if defined(TICKY_TICKY)
Ben Gamari's avatar
Ben Gamari committed
269
    RtsFlags.TickyFlags.showTickyStats   = false;
Austin Seipp's avatar
Austin Seipp committed
270
    RtsFlags.TickyFlags.tickyFile        = NULL;
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
#endif
}

static const char *
usage_text[] = {
"",
"Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
"",
"   +RTS    Indicates run time system options follow",
"   -RTS    Indicates program arguments follow",
"  --RTS    Indicates that ALL subsequent arguments will be given to the",
"           program (including any of these RTS flags)",
"",
"The following run time system options are available:",
"",
286
"  -?       Prints this message and exits; the program is not executed",
287
"  --info   Print information about the RTS used by this program",
288
"",
Jan Stolarek's avatar
Jan Stolarek committed
289 290
"  -K<size>  Sets the maximum stack size (default: 80% of the heap)",
"            Egs: -K32k -K512k -K8M",
291 292 293
"  -ki<size> Sets the initial thread stack size (default 1k)  Egs: -ki4k -ki2m",
"  -kc<size> Sets the stack chunk size (default 32k)",
"  -kb<size> Sets the stack chunk buffer size (default 1k)",
294
"",
295
"  -A<size>  Sets the minimum allocation area size (default 1m) Egs: -A20m -A10k",
Simon Marlow's avatar
Simon Marlow committed
296 297
"  -AL<size> Sets the amount of large-object memory that can be allocated",
"            before a GC is triggered (default: the value of -A)",
Ömer Sinan Ağacan's avatar
Ömer Sinan Ağacan committed
298 299 300
"  -F<n>     Sets the collecting threshold for old generations as a factor of",
"            the live data in that generation the last time it was collected",
"            (default: 2.0)",
Simon Marlow's avatar
Simon Marlow committed
301 302 303 304
"  -n<size>  Allocation area chunk size (0 = disabled, default: 0)",
"  -O<size>  Sets the minimum size of the old generation (default 1M)",
"  -M<size>  Sets the maximum heap size (default unlimited)  Egs: -M256k -M1G",
"  -H<size>  Sets the minimum heap size (default 0M)   Egs: -H24m  -H1G",
305 306 307
"  -xb<addr> Sets the address from which a suitable start for the heap memory",
"            will be searched from. This is useful if the default address",
"            clashes with some third-party library.",
308
"  -xn       Use the non-moving collector for the old generation.",
Simon Marlow's avatar
Simon Marlow committed
309 310 311
"  -m<n>     Minimum % of heap which must be available (default 3%)",
"  -G<n>     Number of generations (default: 2)",
"  -c<n>     Use in-place compaction instead of copying in the oldest generation",
312 313 314 315
"           when live data is at least <n>% of the maximum heap size set with",
"           -M (default: 30%)",
"  -c       Use in-place compaction for all oldest generation collections",
"           (the default is to use copying)",
316
"  -w       Use mark-region for the oldest generation (experimental)",
317
#if defined(THREADED_RTS)
318 319
"  -I<sec>  Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
#endif
320
"",
321
"  -T         Collect GC statistics (useful for in-program statistics access)",
322 323 324
"  -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
"  -s[<file>] Summary  GC statistics (if <file> omitted, uses stderr)",
"  -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
325 326
"",
"",
327 328
"  -Z         Don't squeeze out update frames on stack overflow",
"  -B         Sound the bell at the start of each garbage collection",
Simon Marlow's avatar
Simon Marlow committed
329
#if defined(PROFILING)
330
"",
331 332 333 334 335 336
"  -p         Time/allocation profile in tree format ",
"             (output file <output prefix>.prof)",
"  -po<file>  Override profiling output file name prefix (program name by default)",
"  -P         More detailed Time/Allocation profile in tree format",
"  -Pa        Give information about *all* cost centres in tree format",
"  -pj        Output cost-center profile in JSON format",
337
"",
338
"  -h         Heap residency profile, by cost centre stack",
339 340 341
"  -h<break-down> Heap residency profile (hp2ps) (output file <program>.hp)",
"     break-down: c = cost centre stack (default)",
"                 m = module",
342
"                 T = closure type",
343 344 345 346
"                 d = closure description",
"                 y = type description",
"                 r = retainer",
"                 b = biography (LAG,DRAG,VOID,USE)",
347
"  A subset of closures may be selected thusly:",
348 349
"    -hc<cc>,...  specific cost centre(s) (top of stack only)",
"    -hC<cc>,...  specific cost centre(s) (anywhere in stack)",
350 351 352 353 354
"    -hm<mod>...  all cost centres from the specified modules(s)",
"    -hd<des>,... closures with specified closure descriptions",
"    -hy<typ>...  closures with specified type descriptions",
"    -hr<cc>...   closures with specified retainers",
"    -hb<bio>...  closures with specified biographies (lag,drag,void,use)",
355 356
"",
"  -R<size>       Set the maximum retainer set size (default: 8)",
thoughtpolice's avatar
thoughtpolice committed
357
"",
ravi@bluespec.com's avatar
ravi@bluespec.com committed
358 359
"  -L<chars>      Maximum length of a cost-centre stack in a heap profile",
"                 (default: 25)",
360
"",
361 362
"  -xt            Include threads (TSOs) in a heap profile",
"",
363
"  -xc      Show current cost centre stack on raising an exception",
364 365 366
#else /* PROFILING */
"  -h       Heap residency profile (output file <program>.hp)",
"  -hT      Produce a heap profile grouped by closure type",
367
#endif /* PROFILING */
Simon Marlow's avatar
Simon Marlow committed
368

Ben Gamari's avatar
Ben Gamari committed
369
#if defined(TRACING)
Simon Marlow's avatar
Simon Marlow committed
370
"",
371 372
"  -ol<file>  Send binary eventlog to <file> (default: <program>.eventlog)",
"  -l[flags]  Log events to a file",
Ben Gamari's avatar
Ben Gamari committed
373
#  if defined(DEBUG)
374 375 376 377
"  -v[flags]  Log events to stderr",
#  endif
"             where [flags] can contain:",
"                s    scheduler events",
378
"                g    GC and heap events",
379 380
"                p    par spark events (sampled)",
"                f    par spark events (full detail)",
381 382
"                u    user events (emitted from Haskell code)",
"                a    all event classes above",
Ben Gamari's avatar
Ben Gamari committed
383
#  if defined(DEBUG)
384 385
"                t    add time stamps (only useful with -v)",
#  endif
386
"               -x    disable an event class, for any flag above",
387
"             the initial enabled event classes are 'sgpu'",
Simon Marlow's avatar
Simon Marlow committed
388 389
#endif

Simon Marlow's avatar
Simon Marlow committed
390
"  -i<sec>  Time between heap profile samples (seconds, default: 0.1)",
391 392
"",
#if defined(TICKY_TICKY)
393
"  -r<file>  Produce ticky-ticky statistics (with -rstderr for stderr)",
394 395
"",
#endif
396 397 398
"  -C<secs>  Context-switch interval in seconds.",
"            0 or no argument means switch as often as possible.",
"            Default: 0.02 sec.",
Simon Marlow's avatar
Simon Marlow committed
399 400
"  -V<secs>  Master tick interval in seconds (0 == disable timer).",
"            This sets the resolution for -C and the heap profile timer -i,",
401
"            and is the frequency of time profile samples.",
Ben Gamari's avatar
Ben Gamari committed
402
#if defined(PROFILING)
Simon Marlow's avatar
Simon Marlow committed
403 404 405 406
"            Default: 0.001 sec.",
#else
"            Default: 0.01 sec.",
#endif
407 408 409
"",
#if defined(DEBUG)
"  -Ds  DEBUG: scheduler",
410
"  -Di  DEBUG: interpreter",
411 412 413
"  -Dw  DEBUG: weak",
"  -DG  DEBUG: gccafs",
"  -Dg  DEBUG: gc",
414
"  -Dn  DEBUG: non-moving gc",
415 416
"  -Db  DEBUG: block",
"  -DS  DEBUG: sanity",
Tobias Guggenmos's avatar
Tobias Guggenmos committed
417
"  -DZ  DEBUG: zero freed memory during GC",
418 419
"  -Dt  DEBUG: stable",
"  -Dp  DEBUG: prof",
420
"  -Da  DEBUG: apply",
421
"  -Dl  DEBUG: linker",
422
"  -Dm  DEBUG: stm",
Simon Marlow's avatar
Simon Marlow committed
423
"  -Dz  DEBUG: stack squeezing",
424
"  -Dc  DEBUG: program coverage",
425
"  -Dr  DEBUG: sparks",
426
"  -DC  DEBUG: compact",
427
"",
428
"     NOTE: DEBUG events are sent to stderr by default; add -l to create a",
429
"     binary event log file instead.",
430
"",
431
#endif /* DEBUG */
432
#if defined(THREADED_RTS) && !defined(NOSMP)
433 434
"  -N[<n>]    Use <n> processors (default: 1, -N alone determines",
"             the number of processors to use automatically)",
MarcelineVQ's avatar
MarcelineVQ committed
435
"  -maxN[<n>] Use up to <n> processors automatically",
436 437 438
"  -qg[<n>]  Use parallel GC only for generations >= <n>",
"            (default: 0, -qg alone turns off parallel GC)",
"  -qb[<n>]  Use load-balancing in the parallel GC only for generations >= <n>",
Ömer Sinan Ağacan's avatar
Ömer Sinan Ağacan committed
439
"            (default: 1 for -A < 32M, 0 otherwise;",
440
"             -qb alone turns off load-balancing)",
441
"  -qn<n>    Use <n> threads for parallel GC (defaults to value of -N)",
442
"  -qa       Use the OS to set thread affinity (experimental)",
443
"  -qm       Don't automatically migrate threads between CPUs",
444 445 446
"  -qi<n>    If a processor has been idle for the last <n> GCs, do not",
"            wake it up for a non-load-balancing parallel GC.",
"            (0 disables,  default: 0)",
Simon Marlow's avatar
Simon Marlow committed
447 448 449 450 451 452 453 454
"  --numa[=<node_mask>]",
"            Use NUMA, nodes given by <node_mask> (default: off)",
#if defined(DEBUG)
"  --debug-numa[=<num_nodes>]",
"            Pretend NUMA: like --numa, but without the system calls.",
"            Can be used on non-NUMA systems for debugging.",
"",
#endif
455
#endif
456 457
"  --install-signal-handlers=<yes|no>",
"            Install signal handlers (default: yes)",
458 459 460
#if defined(mingw32_HOST_OS)
"  --install-seh-handlers=<yes|no>",
"            Install exception handlers (default: yes)",
461 462 463 464
"  --generate-crash-dumps",
"            Generate Windows crash dumps, requires exception handlers",
"            to be installed. Implies --install-signal-handlers=yes.",
"            (default: no)",
465 466 467 468
"  --generate-stack-traces=<yes|no>",
"            Generate a stack trace when your application encounters a",
"            fatal error. When symbols are available an attempt will be",
"            made to resolve addresses to names. (default: yes)",
469
#endif
Simon Marlow's avatar
Simon Marlow committed
470
#if defined(THREADED_RTS)
471 472
"  -e<n>     Maximum number of outstanding local sparks (default: 4096)",
#endif
473
#if defined(x86_64_HOST_ARCH)
474 475 476 477 478
#if !DEFAULT_LINKER_ALWAYS_PIC
"  -xp       Assume that all object files were compiled with -fPIC",
"            -fexternal-dynamic-refs and load them anywhere in the address",
"            space",
#endif
479 480 481
"  -xm       Base address to mmap memory in the GHCi linker",
"            (hex; must be <80000000)",
#endif
482 483
"  -xq       The allocation limit given to a thread after it receives",
"            an AllocationLimitExceeded exception. (default: 100k)",
484
"",
dobenour's avatar
dobenour committed
485 486 487 488 489
"  -Mgrace=<n>",
"            The amount of allocation after the program receives a",
"            HeapOverflow exception before the exception is thrown again, if",
"            the program is still exceeding the heap limit.",
"",
490 491
"RTS options may also be specified using the GHCRTS environment variable.",
"",
492 493 494 495 496 497
"Other RTS options may be available for programs compiled a different way.",
"The GHC User's Guide has full details.",
"",
0
};

498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
/**
Note [Windows Unicode Arguments]
~~~~~~~~~~~~~~~~~~~~~~~~~~
On Windows argv is usually encoded in the current Codepage which might not
support unicode.

Instead of ignoring the arguments to hs_init we expect them to be utf-8
encoded when coming from a custom main function. In the regular hs_main we
get the unicode arguments from the windows API and pass them along utf8
encoded instead.

This reduces special casing of arguments in later parts of the RTS and base
libraries to dealing with slash differences and using utf8 instead of the
current locale on Windows when decoding arguments.

*/

#if defined(mingw32_HOST_OS)
//Allocate a buffer and return the string utf8 encoded.
char* lpcwstrToUTF8(const wchar_t* utf16_str)
{
    //Check the utf8 encoded size first
    int res = WideCharToMultiByte(CP_UTF8, 0, utf16_str, -1, NULL, 0,
                                  NULL, NULL);
    if (res == 0) {
        return NULL;
    }
    char* buffer = (char*) stgMallocBytes((size_t)res, "getUTF8Args 2");
    res = WideCharToMultiByte(CP_UTF8, 0, utf16_str, -1, buffer, res,
                              NULL, NULL);
    return buffer;
}

char** getUTF8Args(int* argc)
{
    LPCWSTR cmdLine = GetCommandLineW();
    LPWSTR* argvw = CommandLineToArgvW(cmdLine, argc);

    // We create two argument arrays, one which is later permutated by the RTS
    // instead of the main argv.
    // The other one is used to free the allocted memory later.
    char** argv = (char**) stgMallocBytes(sizeof(char*) * (*argc + 1),
                                          "getUTF8Args 1");
    win32_full_utf8_argv = (char**) stgMallocBytes(sizeof(char*) * (*argc + 1),
                                                   "getUTF8Args 1");

    for (int i = 0; i < *argc; i++)
    {
        argv[i] = lpcwstrToUTF8(argvw[i]);
    }
    argv[*argc] = NULL;
    memcpy(win32_full_utf8_argv, argv, sizeof(char*) * (*argc + 1));

    LocalFree(argvw);
    win32_utf8_argv = argv;
    win32_full_utf8_argc = *argc;
    return argv;
}
#endif

Ben Gamari's avatar
Ben Gamari committed
558
STATIC_INLINE bool strequal(const char *a, const char * b)
559 560 561 562
{
    return(strcmp(a, b) == 0);
}

563 564 565 566 567 568 569 570 571 572 573 574 575
// We can't predict up front how much space we'll need for rts_argv,
// because it involves parsing ghc_rts_opts and GHCRTS, so we
// expand it on demand.
static void appendRtsArg (char *arg)
{
    if (rts_argc == rts_argv_size) {
        rts_argv_size *= 2;
        rts_argv = stgReallocBytes(rts_argv, rts_argv_size * sizeof (char *),
                                   "RtsFlags.c:appendRtsArg");
    }
    rts_argv[rts_argc++] = arg;
}

576
static void splitRtsFlags(const char *s)
577
{
578 579
    const char *c1, *c2;
    char *t;
580 581 582

    c1 = s;
    do {
Austin Seipp's avatar
Austin Seipp committed
583 584 585
        while (isspace(*c1)) { c1++; };
        c2 = c1;
        while (!isspace(*c2) && *c2 != '\0') { c2++; };
thoughtpolice's avatar
thoughtpolice committed
586

Austin Seipp's avatar
Austin Seipp committed
587
        if (c1 == c2) { break; }
thoughtpolice's avatar
thoughtpolice committed
588

589 590 591
        t = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
        strncpy(t, c1, c2-c1);
        t[c2-c1] = '\0';
592
        appendRtsArg(t);
593

Austin Seipp's avatar
Austin Seipp committed
594
        c1 = c2;
595 596
    } while (*c1 != '\0');
}
thoughtpolice's avatar
thoughtpolice committed
597

598 599
static void errorRtsOptsDisabled(const char *s)
{
600
    char *advice;
601
    if (rtsConfig.rts_hs_main) {
602 603 604 605 606 607 608
        advice = "Link with -rtsopts to enable them.";
    } else {
        advice = "Use hs_init_with_rtsopts() to enable them.";
    }
    errorBelch(s, advice);
}

609 610 611 612 613 614 615
/* -----------------------------------------------------------------------------
   Parse the command line arguments, collecting options for the RTS.

   On return:
     - argv[] is *modified*, any RTS options have been stripped out
     - *argc  contains the new count of arguments in argv[]

616
     - rts_argv[]  (global) contains a copy of the collected RTS args
617 618
     - rts_argc    (global) contains the count of args in rts_argv

619
     - prog_argv[] (global) contains a copy of the non-RTS args (== argv)
620 621
     - prog_argc   (global) contains the count of args in prog_argv

622
     - prog_name   (global) contains the basename of prog_argv[0]
623

624 625
     - rtsConfig   (global) contains the supplied RtsConfig

626 627
  On Windows argv is assumed to be utf8 encoded for unicode compatibility.
  See Note [Windows Unicode Arguments]
628

629 630
  -------------------------------------------------------------------------- */

631
void setupRtsFlags (int *argc, char *argv[], RtsConfig rts_config)
632
{
633 634 635
    uint32_t mode;
    uint32_t total_arg;
    uint32_t arg, rts_argc0;
636

637 638
    rtsConfig = rts_config;

639
    setProgName (argv);
640 641 642
    total_arg = *argc;
    arg = 1;

643
    if (*argc > 1) { *argc = 1; };
644 645
    rts_argc = 0;

646 647
    rts_argv_size = total_arg + 1;
    rts_argv = stgMallocBytes(rts_argv_size * sizeof (char *), "setupRtsFlags");
648

649
    rts_argc0 = rts_argc;
650

651
    // process arguments from the -with-rtsopts compile-time flag first
652 653 654
    // (arguments from the GHCRTS environment variable and the command
    // line override these).
    {
655 656 657 658
        if (rtsConfig.rts_opts != NULL) {
            splitRtsFlags(rtsConfig.rts_opts);
            // opts from rts_opts are always enabled:
            procRtsOpts(rts_argc0, RtsOptsAll);
659 660
            rts_argc0 = rts_argc;
        }
661 662
    }

663
    // process arguments from the GHCRTS environment variable next
664
    // (arguments from the command line override these).
665 666
    // If we ignore all non-builtin rtsOpts we skip these.
    if(rtsConfig.rts_opts_enabled != RtsOptsIgnoreAll)
667
    {
Austin Seipp's avatar
Austin Seipp committed
668
        char *ghc_rts = getenv("GHCRTS");
669

Austin Seipp's avatar
Austin Seipp committed
670
        if (ghc_rts != NULL) {
671 672 673
            if (rtsConfig.rts_opts_enabled == RtsOptsNone) {
                errorRtsOptsDisabled(
                    "Warning: Ignoring GHCRTS variable as RTS options are disabled.\n         %s");
674
                // We don't actually exit, just warn
675 676
            } else {
                splitRtsFlags(ghc_rts);
677
                procRtsOpts(rts_argc0, rtsConfig.rts_opts_enabled);
678
                rts_argc0 = rts_argc;
679
            }
680
        }
681
    }
682

683

684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
    // If we ignore all commandline rtsOpts we skip processing of argv by
    // the RTS completely
    if(!(rtsConfig.rts_opts_enabled == RtsOptsIgnoreAll ||
         rtsConfig.rts_opts_enabled == RtsOptsIgnore)
    )
    {
        // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
        //   argv[0] must be PGM argument -- leave in argv
        //
        for (mode = PGM; arg < total_arg; arg++) {
            // The '--RTS' argument disables all future
            // +RTS ... -RTS processing.
            if (strequal("--RTS", argv[arg])) {
                arg++;
                break;
            }
            // The '--' argument is passed through to the program, but
            // disables all further +RTS ... -RTS processing.
            else if (strequal("--", argv[arg])) {
                break;
            }
            else if (strequal("+RTS", argv[arg])) {
                mode = RTS;
            }
            else if (strequal("-RTS", argv[arg])) {
                mode = PGM;
            }
            else if (mode == RTS) {
                appendRtsArg(copyArg(argv[arg]));
            }
            else {
                argv[(*argc)++] = argv[arg];
            }
Austin Seipp's avatar
Austin Seipp committed
717
        }
718

719
    }
720

721 722
    // process remaining program arguments
    for (; arg < total_arg; arg++) {
Austin Seipp's avatar
Austin Seipp committed
723
        argv[(*argc)++] = argv[arg];
724 725
    }
    argv[*argc] = (char *) 0;
726

727
    procRtsOpts(rts_argc0, rtsConfig.rts_opts_enabled);
728

729
    appendRtsArg((char *)0);
Simon Marlow's avatar
Simon Marlow committed
730
    rts_argc--; // appendRtsArg will have bumped it for the NULL (#7227)
731

732 733 734 735 736 737 738
    normaliseRtsOpts();

    setProgArgv(*argc, argv);

    if (RtsFlags.GcFlags.statsFile != NULL) {
        initStatsFile (RtsFlags.GcFlags.statsFile);
    }
Ben Gamari's avatar
Ben Gamari committed
739
#if defined(TICKY_TICKY)
740
    if (RtsFlags.TickyFlags.tickyFile != NULL) {
741
        initStatsFile (RtsFlags.TickyFlags.tickyFile);
742
    }
743
#endif
744 745 746 747 748 749
}

/* -----------------------------------------------------------------------------
 * procRtsOpts: Process rts_argv between rts_argc0 and rts_argc.
 * -------------------------------------------------------------------------- */

750
#if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_TYPES_H) && !defined(mingw32_HOST_OS)
751
static void checkSuid(RtsOptsEnabledEnum enabled)
752 753
{
    if (enabled == RtsOptsSafeOnly) {
Austin Seipp's avatar
Austin Seipp committed
754 755
        /* This doesn't cover linux/posix capabilities like CAP_DAC_OVERRIDE,
           we'd have to link with -lcap for that. */
756
        if ((getuid() != geteuid()) || (getgid() != getegid())) {
757 758
            errorRtsOptsDisabled(
                "RTS options are disabled for setuid binaries. %s");
759 760
            stg_exit(EXIT_FAILURE);
        }
761
    }
762
}
763
#else
764
static void checkSuid (RtsOptsEnabledEnum enabled STG_UNUSED)
765 766 767
{
}
#endif
768

769
static void checkUnsafe(RtsOptsEnabledEnum enabled)
770 771
{
    if (enabled == RtsOptsSafeOnly) {
772
        errorRtsOptsDisabled("Most RTS options are disabled. %s");
773 774 775 776
        stg_exit(EXIT_FAILURE);
    }
}

777 778
static void procRtsOpts (int rts_argc0,
                         RtsOptsEnabledEnum rtsOptsEnabled)
779
{
Ben Gamari's avatar
Ben Gamari committed
780
    bool error = false;
781
    int arg;
782
    int unchecked_arg_start;
783

784 785
    if (!(rts_argc0 < rts_argc)) return;

786
    if (rtsOptsEnabled == RtsOptsNone) {
787
        errorRtsOptsDisabled("RTS options are disabled. %s");
788 789 790
        stg_exit(EXIT_FAILURE);
    }

791
    checkSuid(rtsOptsEnabled);
792

793
    // Process RTS (rts_argv) part: mainly to determine statsfile
794
    for (arg = rts_argc0; arg < rts_argc; arg++) {
795 796

        /* We handle RtsOptsSafeOnly mode by declaring each option as
Austin Seipp's avatar
Austin Seipp committed
797 798 799
           either OPTION_SAFE or OPTION_UNSAFE. To make sure we cover
           every branch we use an option_checked flag which is reset
           at the start each iteration and checked at the end. */
Ben Gamari's avatar
Ben Gamari committed
800
        bool option_checked = false;
801

802
// See Note [OPTION_SAFE vs OPTION_UNSAFE].
Ben Gamari's avatar
Ben Gamari committed
803 804
#define OPTION_SAFE option_checked = true;
#define OPTION_UNSAFE checkUnsafe(rtsOptsEnabled); option_checked = true;
805

806
        if (rts_argv[arg][0] != '-') {
Austin Seipp's avatar
Austin Seipp committed
807 808
            fflush(stdout);
            errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
Ben Gamari's avatar
Ben Gamari committed
809
            error = true;
810 811

        } else {
812
            /* 0 is dash, 1 is first letter */
813
            /* see #9839 */
814
            unchecked_arg_start = 1;
Simon Marlow's avatar
Simon Marlow committed
815
            switch(rts_argv[arg][1]) {
816

Austin Seipp's avatar
Austin Seipp committed
817 818 819 820 821 822
              /* process: general args, then PROFILING-only ones, then
                 CONCURRENT-only, TICKY-only (same order as defined in
                 RtsFlags.lh); within those groups, mostly in
                 case-insensitive alphabetical order.  Final group is
                 x*, which allows for more options.
              */
823

Ben Gamari's avatar
Ben Gamari committed
824
#if defined(TICKY_TICKY)
825 826 827
# define TICKY_BUILD_ONLY(x) x
#else
# define TICKY_BUILD_ONLY(x) \
828 829
errorBelch("the flag %s requires the program to be built with -ticky", \
           rts_argv[arg]);                                             \
Ben Gamari's avatar
Ben Gamari committed
830
error = true;
831 832
#endif

Ben Gamari's avatar
Ben Gamari committed
833
#if defined(PROFILING)
834 835 836
# define PROFILING_BUILD_ONLY(x)   x
#else
# define PROFILING_BUILD_ONLY(x) \
837 838
errorBelch("the flag %s requires the program to be built with -prof", \
           rts_argv[arg]);                                            \
Ben Gamari's avatar
Ben Gamari committed
839
error = true;
840 841
#endif

Ben Gamari's avatar
Ben Gamari committed
842
#if defined(TRACING)
843
# define TRACING_BUILD_ONLY(x)   x
Simon Marlow's avatar
Simon Marlow committed
844
#else