Attempt to fix #2512 and #2063; add +RTS -xm<address> -RTS option
[ghc-hetmet.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 #include "RtsFlags.h"
13 #include "RtsUtils.h"
14 #include "Profiling.h"
15
16 #ifdef HAVE_CTYPE_H
17 #include <ctype.h>
18 #endif
19
20 #include <stdlib.h>
21 #include <string.h>
22
23 // Flag Structure
24 RTS_FLAGS RtsFlags;
25
26 /*
27  * Split argument lists
28  */
29 int     prog_argc = 0;    /* an "int" so as to match normal "argc" */
30 char  **prog_argv = NULL;
31 int     full_prog_argc = 0;    /* an "int" so as to match normal "argc" */
32 char  **full_prog_argv = NULL;
33 char   *prog_name = NULL; /* 'basename' of prog_argv[0] */
34 int     rts_argc = 0;  /* ditto */
35 char   *rts_argv[MAX_RTS_ARGS];
36
37 /*
38  * constants, used later 
39  */
40 #define RTS 1
41 #define PGM 0
42
43 #if defined(GRAN)
44
45 static char *gran_debug_opts_strs[] = {
46   "DEBUG (-bDe, -bD1): event_trace; printing event trace.\n",
47   "DEBUG (-bDE, -bD2): event_stats; printing event statistics.\n",
48   "DEBUG (-bDb, -bD4): bq; check blocking queues\n",
49   "DEBUG (-bDG, -bD8): pack; routines for (un-)packing graph structures.\n",
50   "DEBUG (-bDq, -bD16): checkSparkQ; check consistency of the spark queues.\n",
51   "DEBUG (-bDf, -bD32): thunkStealing; print forwarding of fetches.\n",
52   "DEBUG (-bDr, -bD64): randomSteal; stealing sparks/threads from random PEs.\n",
53   "DEBUG (-bDF, -bD128): findWork; searching spark-pools (local & remote), thread queues for work.\n",
54   "DEBUG (-bDu, -bD256): unused; currently unused flag.\n",
55   "DEBUG (-bDS, -bD512): pri; priority sparking or scheduling.\n",
56   "DEBUG (-bD:, -bD1024): checkLight; check GranSim-Light setup.\n",
57   "DEBUG (-bDo, -bD2048): sortedQ; check whether spark/thread queues are sorted.\n",
58   "DEBUG (-bDz, -bD4096): blockOnFetch; check for blocked on fetch.\n",
59   "DEBUG (-bDP, -bD8192): packBuffer; routines handling pack buffer (GranSim internal!).\n",
60   "DEBUG (-bDt, -bD16384): blockOnFetch_sanity; check for TSO asleep on fetch.\n",
61 };
62
63 /* one character codes for the available debug options */
64 static char gran_debug_opts_flags[] = {
65   'e', 'E', 'b', 'G', 'q', 'f', 'r', 'F', 'u', 'S', ':', 'o', 'z', 'P', 't'
66 };
67
68 #elif defined(PAR)
69
70 static char *par_debug_opts_strs[] = {
71   "DEBUG (-qDv, -qD1): verbose; be generally verbose with parallel related stuff.\n",
72   "DEBUG (-qDq, -qD2): bq; print blocking queues.\n",
73   "DEBUG (-qDs, -qD4): schedule; scheduling of parallel threads.\n",
74   "DEBUG (-qDe, -qD8): free; free messages.\n",
75   "DEBUG (-qDr, -qD16): resume; resume messages.\n",
76   "DEBUG (-qDw, -qD32): weight; print weights and distrib GC stuff.\n",
77   "DEBUG (-qDF, -qD64): fetch; fetch messages.\n",
78   // "DEBUG (-qDa, -qD128): ack; ack messages.\n",
79   "DEBUG (-qDf, -qD128): fish; fish messages.\n",
80   //"DEBUG (-qDo, -qD512): forward; forwarding messages to other PEs.\n",
81   "DEBUG (-qDl, -qD256): tables; print internal LAGA etc tables.\n",
82   "DEBUG (-qDo, -qD512): packet; packets and graph structures when packing.\n",
83   "DEBUG (-qDp, -qD1024): pack; packing and unpacking graphs.\n",
84   "DEBUG (-qDz, -qD2048): paranoia; ridiculously detailed output (excellent for filling a partition).\n"
85 };
86
87 /* one character codes for the available debug options */
88 static char par_debug_opts_flags[] = {
89   'v', 'q', 's', 'e', 'r', 'w', 'F', 'f', 'l', 'o', 'p', 'z'
90 };
91
92 #endif /* PAR */
93
94 /* -----------------------------------------------------------------------------
95    Static function decls
96    -------------------------------------------------------------------------- */
97
98 static int              /* return NULL on error */
99 open_stats_file (
100     I_ arg,
101     int argc, char *argv[],
102     int rts_argc, char *rts_argv[],
103     const char *FILENAME_FMT,
104     FILE **file_ret);
105
106 static I_ decode(const char *s);
107 static void bad_option(const char *s);
108
109 #if defined(GRAN)
110 static void enable_GranSimLight(void);
111 static void process_gran_option(int arg, int *rts_argc, char *rts_argv[], rtsBool *error);
112 static void set_GranSim_debug_options(nat n);
113 static void help_GranSim_debug_options(nat n);
114 #elif defined(PAR)
115 static void process_par_option(int arg, int *rts_argc, char *rts_argv[], rtsBool *error);
116 static void set_par_debug_options(nat n);
117 static void help_par_debug_options(nat n);
118 #endif
119
120 /* -----------------------------------------------------------------------------
121  * Command-line option parsing routines.
122  * ---------------------------------------------------------------------------*/
123
124 void initRtsFlagsDefaults(void)
125 {
126     RtsFlags.GcFlags.statsFile          = NULL;
127     RtsFlags.GcFlags.giveStats          = NO_GC_STATS;
128
129     RtsFlags.GcFlags.maxStkSize         = (8 * 1024 * 1024) / sizeof(W_);
130     RtsFlags.GcFlags.initialStkSize     = 1024 / sizeof(W_);
131
132     RtsFlags.GcFlags.minAllocAreaSize   = (512 * 1024)        / BLOCK_SIZE;
133     RtsFlags.GcFlags.minOldGenSize      = (1024 * 1024)       / BLOCK_SIZE;
134     RtsFlags.GcFlags.maxHeapSize        = 0;    /* off by default */
135     RtsFlags.GcFlags.heapSizeSuggestion = 0;    /* none */
136     RtsFlags.GcFlags.pcFreeHeap         = 3;    /* 3% */
137     RtsFlags.GcFlags.oldGenFactor       = 2;
138 #if defined(PAR)
139     /* A hack currently needed for GUM -- HWL */
140     RtsFlags.GcFlags.generations        = 1;
141     RtsFlags.GcFlags.steps              = 2;
142     RtsFlags.GcFlags.squeezeUpdFrames   = rtsFalse;
143 #else
144     RtsFlags.GcFlags.generations        = 2;
145     RtsFlags.GcFlags.steps              = 2;
146     RtsFlags.GcFlags.squeezeUpdFrames   = rtsTrue;
147 #endif
148     RtsFlags.GcFlags.compact            = rtsFalse;
149     RtsFlags.GcFlags.compactThreshold   = 30.0;
150     RtsFlags.GcFlags.sweep              = rtsFalse;
151 #ifdef RTS_GTK_FRONTPANEL
152     RtsFlags.GcFlags.frontpanel         = rtsFalse;
153 #endif
154     RtsFlags.GcFlags.idleGCDelayTime    = 300; /* millisecs */
155
156 #if osf3_HOST_OS
157 /* ToDo: Perhaps by adjusting this value we can make linking without
158  * -static work (i.e., not generate a core-dumping executable)? */
159 # if SIZEOF_VOID_P == 8
160     RtsFlags.GcFlags.heapBase           = 0x180000000L;
161 # else
162 #  error I have no idea where to begin the heap on a non-64-bit osf3 machine.
163 # endif
164 #else
165     RtsFlags.GcFlags.heapBase           = 0;   /* means don't care */
166 #endif
167
168 #ifdef DEBUG
169     RtsFlags.DebugFlags.scheduler       = rtsFalse;
170     RtsFlags.DebugFlags.interpreter     = rtsFalse;
171     RtsFlags.DebugFlags.weak            = rtsFalse;
172     RtsFlags.DebugFlags.gccafs          = rtsFalse;
173     RtsFlags.DebugFlags.gc              = rtsFalse;
174     RtsFlags.DebugFlags.block_alloc     = rtsFalse;
175     RtsFlags.DebugFlags.sanity          = rtsFalse;
176     RtsFlags.DebugFlags.stable          = rtsFalse;
177     RtsFlags.DebugFlags.stm             = rtsFalse;
178     RtsFlags.DebugFlags.prof            = rtsFalse;
179     RtsFlags.DebugFlags.gran            = rtsFalse;
180     RtsFlags.DebugFlags.par             = rtsFalse;
181     RtsFlags.DebugFlags.linker          = rtsFalse;
182     RtsFlags.DebugFlags.squeeze         = rtsFalse;
183     RtsFlags.DebugFlags.hpc             = rtsFalse;
184 #endif
185
186 #if defined(PROFILING) || defined(PAR)
187     RtsFlags.CcFlags.doCostCentres      = 0;
188 #endif /* PROFILING or PAR */
189
190     RtsFlags.ProfFlags.doHeapProfile      = rtsFalse;
191     RtsFlags.ProfFlags.profileInterval    = 100;
192
193 #ifdef PROFILING
194     RtsFlags.ProfFlags.includeTSOs        = rtsFalse;
195     RtsFlags.ProfFlags.showCCSOnException = rtsFalse;
196     RtsFlags.ProfFlags.maxRetainerSetSize = 8;
197     RtsFlags.ProfFlags.ccsLength          = 25;
198     RtsFlags.ProfFlags.modSelector        = NULL;
199     RtsFlags.ProfFlags.descrSelector      = NULL;
200     RtsFlags.ProfFlags.typeSelector       = NULL;
201     RtsFlags.ProfFlags.ccSelector         = NULL;
202     RtsFlags.ProfFlags.ccsSelector        = NULL;
203     RtsFlags.ProfFlags.retainerSelector   = NULL;
204     RtsFlags.ProfFlags.bioSelector        = NULL;
205 #endif
206
207     RtsFlags.MiscFlags.tickInterval     = 20;  /* In milliseconds */
208     RtsFlags.ConcFlags.ctxtSwitchTime   = 20;  /* In milliseconds */
209
210     RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
211     RtsFlags.MiscFlags.linkerMemBase    = 0;
212
213 #ifdef THREADED_RTS
214     RtsFlags.ParFlags.nNodes            = 1;
215     RtsFlags.ParFlags.migrate           = rtsTrue;
216     RtsFlags.ParFlags.wakeupMigrate     = rtsFalse;
217     RtsFlags.ParFlags.gcThreads         = 1;
218 #endif
219
220 #ifdef PAR
221     RtsFlags.ParFlags.ParStats.Full       = rtsFalse;
222     RtsFlags.ParFlags.ParStats.Suppressed = rtsFalse;
223     RtsFlags.ParFlags.ParStats.Binary     = rtsFalse;
224     RtsFlags.ParFlags.ParStats.Sparks     = rtsFalse;
225     RtsFlags.ParFlags.ParStats.Heap       = rtsFalse;
226     RtsFlags.ParFlags.ParStats.NewLogfile = rtsFalse;
227     RtsFlags.ParFlags.ParStats.Global     = rtsFalse;
228
229     RtsFlags.ParFlags.outputDisabled    = rtsFalse;
230 #ifdef DIST
231     RtsFlags.ParFlags.doFairScheduling  = rtsTrue;  /* fair sched by def */
232 #else
233     RtsFlags.ParFlags.doFairScheduling  = rtsFalse;  /* unfair sched by def */
234 #endif
235     RtsFlags.ParFlags.packBufferSize    = 1024;
236     RtsFlags.ParFlags.thunksToPack      = 1; /* 0 ... infinity; */
237     RtsFlags.ParFlags.globalising       = 1; /* 0 ... everything */
238     RtsFlags.ParFlags.maxThreads        = 1024;
239     RtsFlags.ParFlags.maxFishes        = MAX_FISHES;
240     RtsFlags.ParFlags.fishDelay         = FISH_DELAY;
241 #endif
242
243 #if defined(PAR) || defined(THREADED_RTS)
244     RtsFlags.ParFlags.maxLocalSparks    = 4096;
245 #endif /* PAR || THREADED_RTS */
246
247 #if defined(GRAN)
248     /* ToDo: check defaults for GranSim and GUM */
249     RtsFlags.GcFlags.maxStkSize         = (8 * 1024 * 1024) / sizeof(W_);
250     RtsFlags.GcFlags.initialStkSize     = 1024 / sizeof(W_);
251
252     RtsFlags.GranFlags.maxThreads       = 65536; // refers to mandatory threads
253     RtsFlags.GranFlags.GranSimStats.Full        = rtsFalse;
254     RtsFlags.GranFlags.GranSimStats.Suppressed  = rtsFalse;
255     RtsFlags.GranFlags.GranSimStats.Binary      = rtsFalse;
256     RtsFlags.GranFlags.GranSimStats.Sparks      = rtsFalse;
257     RtsFlags.GranFlags.GranSimStats.Heap        = rtsFalse;
258     RtsFlags.GranFlags.GranSimStats.NewLogfile  = rtsFalse;
259     RtsFlags.GranFlags.GranSimStats.Global      = rtsFalse;
260
261     RtsFlags.GranFlags.packBufferSize   = 1024;
262     RtsFlags.GranFlags.packBufferSize_internal = GRANSIM_DEFAULT_PACK_BUFFER_SIZE;
263
264     RtsFlags.GranFlags.proc         = MAX_PROC;
265     RtsFlags.GranFlags.Fishing      = rtsFalse;
266     RtsFlags.GranFlags.maxFishes   = MAX_FISHES;
267     RtsFlags.GranFlags.time_slice   = GRAN_TIME_SLICE;
268     RtsFlags.GranFlags.Light        = rtsFalse;
269
270     RtsFlags.GranFlags.Costs.latency =             LATENCY;          
271     RtsFlags.GranFlags.Costs.additional_latency =  ADDITIONAL_LATENCY; 
272     RtsFlags.GranFlags.Costs.fetchtime =           FETCHTIME; 
273     RtsFlags.GranFlags.Costs.lunblocktime =        LOCALUNBLOCKTIME; 
274     RtsFlags.GranFlags.Costs.gunblocktime =        GLOBALUNBLOCKTIME;
275     RtsFlags.GranFlags.Costs.mpacktime =           MSGPACKTIME;      
276     RtsFlags.GranFlags.Costs.munpacktime =         MSGUNPACKTIME;
277     RtsFlags.GranFlags.Costs.mtidytime =           MSGTIDYTIME;
278
279     RtsFlags.GranFlags.Costs.threadcreatetime =         THREADCREATETIME;
280     RtsFlags.GranFlags.Costs.threadqueuetime =          THREADQUEUETIME;
281     RtsFlags.GranFlags.Costs.threaddescheduletime =     THREADDESCHEDULETIME;
282     RtsFlags.GranFlags.Costs.threadscheduletime =       THREADSCHEDULETIME;
283     RtsFlags.GranFlags.Costs.threadcontextswitchtime =  THREADCONTEXTSWITCHTIME;
284
285     RtsFlags.GranFlags.Costs.arith_cost =         ARITH_COST;       
286     RtsFlags.GranFlags.Costs.branch_cost =        BRANCH_COST; 
287     RtsFlags.GranFlags.Costs.load_cost =          LOAD_COST;        
288     RtsFlags.GranFlags.Costs.store_cost =         STORE_COST; 
289     RtsFlags.GranFlags.Costs.float_cost =         FLOAT_COST;       
290
291     RtsFlags.GranFlags.Costs.heapalloc_cost =     HEAPALLOC_COST;
292
293     RtsFlags.GranFlags.Costs.pri_spark_overhead = PRI_SPARK_OVERHEAD;        
294     RtsFlags.GranFlags.Costs.pri_sched_overhead = PRI_SCHED_OVERHEAD;        
295
296     RtsFlags.GranFlags.DoFairSchedule           = rtsFalse;             
297     RtsFlags.GranFlags.DoAsyncFetch             = rtsFalse;        
298     RtsFlags.GranFlags.DoStealThreadsFirst      = rtsFalse;        
299     RtsFlags.GranFlags.DoAlwaysCreateThreads    = rtsFalse;      
300     RtsFlags.GranFlags.DoBulkFetching           = rtsFalse;             
301     RtsFlags.GranFlags.DoThreadMigration        = rtsFalse;          
302     RtsFlags.GranFlags.FetchStrategy            = 2;                     
303     RtsFlags.GranFlags.PreferSparksOfLocalNodes = rtsFalse;   
304     RtsFlags.GranFlags.DoPrioritySparking       = rtsFalse;         
305     RtsFlags.GranFlags.DoPriorityScheduling     = rtsFalse;       
306     RtsFlags.GranFlags.SparkPriority            = 0;
307     RtsFlags.GranFlags.SparkPriority2           = 0; 
308     RtsFlags.GranFlags.RandomPriorities         = rtsFalse;           
309     RtsFlags.GranFlags.InversePriorities        = rtsFalse;          
310     RtsFlags.GranFlags.IgnorePriorities         = rtsFalse;           
311     RtsFlags.GranFlags.ThunksToPack             = 0;                      
312     RtsFlags.GranFlags.RandomSteal              = rtsTrue;
313 #endif
314
315 #ifdef TICKY_TICKY
316     RtsFlags.TickyFlags.showTickyStats   = rtsFalse;
317     RtsFlags.TickyFlags.tickyFile        = NULL;
318 #endif
319
320     RtsFlags.TraceFlags.timestamp       = rtsFalse;
321     RtsFlags.TraceFlags.sched           = rtsFalse;
322     RtsFlags.TraceFlags.gc              = rtsFalse;
323
324 #ifdef USE_PAPI
325     /* By default no special measurements taken */
326     RtsFlags.PapiFlags.eventType        = 0;
327     RtsFlags.PapiFlags.numUserEvents    = 0;
328 #endif
329 }
330
331 static const char *
332 usage_text[] = {
333 "",
334 "Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
335 "",
336 "   +RTS    Indicates run time system options follow",
337 "   -RTS    Indicates program arguments follow",
338 "  --RTS    Indicates that ALL subsequent arguments will be given to the",
339 "           program (including any of these RTS flags)",
340 "",
341 "The following run time system options are available:",
342 "",
343 "  -?       Prints this message and exits; the program is not executed",
344 "  --info   Print information about the RTS used by this program",
345 "",
346 "  -K<size> Sets the maximum stack size (default 8M)  Egs: -K32k   -K512k",
347 "  -k<size> Sets the initial thread stack size (default 1k)  Egs: -k4k   -k2m",
348 "",
349 "  -A<size> Sets the minimum allocation area size (default 256k) Egs: -A1m -A10k",
350 "  -M<size> Sets the maximum heap size (default unlimited)  Egs: -M256k -M1G",
351 "  -H<size> Sets the minimum heap size (default 0M)   Egs: -H24m  -H1G",
352 "  -m<n>    Minimum % of heap which must be available (default 3%)",
353 "  -G<n>    Number of generations (default: 2)",
354 "  -T<n>    Number of steps in younger generations (default: 2)",
355 "  -c<n>    Auto-enable compaction of the oldest generation when live data is",
356 "           at least <n>% of the maximum heap size set with -M (default: 30%)",
357 "  -c       Enable compaction for all major collections",
358 "  -w       Use mark-region for the oldest generation (experimental)",
359 #if defined(THREADED_RTS)
360 "  -I<sec>  Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
361 #endif
362 "",
363 "  -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
364 "  -s[<file>] Summary  GC statistics (if <file> omitted, uses stderr)",
365 "  -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
366 #ifdef RTS_GTK_FRONTPANEL
367 "  -f       Display front panel (requires X11 & GTK+)",
368 #endif
369 "",
370 "",
371 "  -Z       Don't squeeze out update frames on stack overflow",
372 "  -B       Sound the bell at the start of each garbage collection",
373 #if defined(PROFILING) || defined(PAR)
374 "",
375 "  -px      Time/allocation profile (XML)  (output file <program>.prof)",
376 "  -p       Time/allocation profile        (output file <program>.prof)",
377 "  -P       More detailed Time/Allocation profile",
378 "  -Pa      Give information about *all* cost centres",
379
380 # if defined(PROFILING)
381 "",
382 "  -hx            Heap residency profile (XML)   (output file <program>.prof)",
383 "  -h<break-down> Heap residency profile (hp2ps) (output file <program>.hp)",
384 "     break-down: c = cost centre stack (default)",
385 "                 m = module",
386 "                 d = closure description",
387 "                 y = type description",
388 "                 r = retainer",
389 "                 b = biography (LAG,DRAG,VOID,USE)",
390 "  A subset of closures may be selected thusly:",
391 "    -hc<cc>,...  specific cost centre(s) (top of stack only)",
392 "    -hC<cc>,...  specific cost centre(s) (anywhere in stack)",
393 "    -hm<mod>...  all cost centres from the specified modules(s)",
394 "    -hd<des>,... closures with specified closure descriptions",
395 "    -hy<typ>...  closures with specified type descriptions",
396 "    -hr<cc>...   closures with specified retainers",
397 "    -hb<bio>...  closures with specified biographies (lag,drag,void,use)",
398 "",
399 "  -R<size>       Set the maximum retainer set size (default: 8)",
400 "", 
401 "  -L<chars>      Maximum length of a cost-centre stack in a heap profile",
402 "                 (default: 25)",
403 "",
404 "  -xt            Include threads (TSOs) in a heap profile",
405 "",
406 "  -xc      Show current cost centre stack on raising an exception",
407 "",
408 # endif
409 #endif /* PROFILING or PAR */
410 #if !defined(PROFILING)
411 "",
412 "  -hT      Heap residency profile (output file <program>.hp)",
413 #endif
414 "  -i<sec>  Time between heap samples (seconds, default: 0.1)",
415 "",
416 #if defined(TICKY_TICKY)
417 "  -r<file>  Produce ticky-ticky statistics (with -rstderr for stderr)",
418 "",
419 #endif
420 #if defined(PAR)
421 "  -N<n>     Use <n> PVMish processors in parallel (default: 2)",
422 /* NB: the -N<n> is implemented by the driver!! */
423 #endif
424 "  -C<secs>  Context-switch interval in seconds.",
425 "            0 or no argument means switch as often as possible.",
426 "            Default: 0.02 sec; resolution is set by -V below.",
427 "  -V<secs>  Master tick interval in seconds (0 == disable timer).",
428 "            This sets the resolution for -C and the profile timer -i.",
429 "            Default: 0.02 sec.",
430 "",
431 "  -vs       Trace scheduler events (see also -Ds with -debug)",
432 "  -vt       Time-stamp trace messages",
433 "",
434 #if defined(DEBUG)
435 "  -Ds  DEBUG: scheduler",
436 "  -Di  DEBUG: interpreter",
437 "  -Dw  DEBUG: weak",
438 "  -DG  DEBUG: gccafs",
439 "  -Dg  DEBUG: gc",
440 "  -Db  DEBUG: block",
441 "  -DS  DEBUG: sanity",
442 "  -Dt  DEBUG: stable",
443 "  -Dp  DEBUG: prof",
444 "  -Dr  DEBUG: gran",
445 "  -DP  DEBUG: par",
446 "  -Dl  DEBUG: linker",
447 "  -Dm  DEBUG: stm",
448 "  -Dz  DEBUG: stack squezing",
449 "  -Dc  DEBUG: program coverage",
450 "",
451 #endif /* DEBUG */
452 #if defined(THREADED_RTS) && !defined(NOSMP)
453 "  -N<n>     Use <n> OS threads (default: 1) (also sets -g)",
454 "  -g<n>     Use <n> OS threads for GC (default: 1)",
455 "  -qm       Don't automatically migrate threads between CPUs",
456 "  -qw       Migrate a thread to the current CPU when it is woken up",
457 #endif
458 "  --install-signal-handlers=<yes|no>",
459 "            Install signal handlers (default: yes)",
460 #if defined(THREADED_RTS) || defined(PAR)
461 "  -e<size>  Size of spark pools (default 100)",
462 #endif
463 #if defined(PAR)
464 "  -t<num>   Set maximum number of advisory threads per PE (default 32)",
465 "  -qP       Enable activity profile (output files in ~/<program>*.gr)",
466 "  -qQ<size> Set pack-buffer size (default: 1024)",
467 "  -qd       Turn on PVM-ish debugging",
468 "  -qO       Disable output for performance measurement",
469 #endif
470 #if defined(THREADED_RTS) || defined(PAR)
471 "  -e<n>     Maximum number of outstanding local sparks (default: 4096)",
472 #endif
473 #if defined(PAR)
474 "  -d        Turn on PVM-ish debugging",
475 "  -O        Disable output for performance measurement",
476 #endif /* PAR */
477 #if defined(GRAN)  /* ToDo: fill in decent Docu here */
478 "  -b...     All GranSim options start with -b; see GranSim User's Guide for details",
479 #endif
480 #if defined(x86_64_HOST_ARCH)
481 "  -xm       Base address to mmap memory in the GHCi linker",
482 "            (hex; must be <80000000)",
483 #endif
484 #if defined(USE_PAPI)
485 "  -aX       CPU performance counter measurements using PAPI",
486 "            (use with the -s<file> option).  X is one of:",
487 "",
488 /* "            y - cycles", */
489 "            1 - level 1 cache misses",
490 "            2 - level 2 cache misses",
491 "            b - branch mispredictions",
492 "            s - stalled cycles",
493 "            e - cache miss and branch misprediction events",
494 #endif
495 "",
496 "RTS options may also be specified using the GHCRTS environment variable.",
497 "",
498 "Other RTS options may be available for programs compiled a different way.",
499 "The GHC User's Guide has full details.",
500 "",
501 0
502 };
503
504 STATIC_INLINE rtsBool
505 strequal(const char *a, const char * b)
506 {
507     return(strcmp(a, b) == 0);
508 }
509
510 static void
511 splitRtsFlags(char *s, int *rts_argc, char *rts_argv[])
512 {
513     char *c1, *c2;
514
515     c1 = s;
516     do {
517         while (isspace(*c1)) { c1++; };
518         c2 = c1;
519         while (!isspace(*c2) && *c2 != '\0') { c2++; };
520         
521         if (c1 == c2) { break; }
522         
523         if (*rts_argc < MAX_RTS_ARGS-1) {
524             s = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
525             strncpy(s, c1, c2-c1);
526             s[c2-c1] = '\0';
527             rts_argv[(*rts_argc)++] = s;
528         } else {
529             barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
530         }
531         
532         c1 = c2;
533     } while (*c1 != '\0');
534 }
535     
536 void
537 setupRtsFlags(int *argc, char *argv[], int *rts_argc, char *rts_argv[])
538 {
539     rtsBool error = rtsFalse;
540     I_ mode;
541     I_ arg, total_arg;
542
543     setProgName (argv);
544     total_arg = *argc;
545     arg = 1;
546
547     *argc = 1;
548     *rts_argc = 0;
549
550     // process arguments from the ghc_rts_opts global variable first.
551     // (arguments from the GHCRTS environment variable and the command
552     // line override these).
553     {
554         if (ghc_rts_opts != NULL) {
555             splitRtsFlags(ghc_rts_opts, rts_argc, rts_argv);
556         }
557     }
558
559     // process arguments from the GHCRTS environment variable next
560     // (arguments from the command line override these).
561     {
562         char *ghc_rts = getenv("GHCRTS");
563
564         if (ghc_rts != NULL) {
565             splitRtsFlags(ghc_rts, rts_argc, rts_argv);
566         }
567     }
568
569     // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
570     //   argv[0] must be PGM argument -- leave in argv
571
572     for (mode = PGM; arg < total_arg; arg++) {
573         // The '--RTS' argument disables all future +RTS ... -RTS processing.
574         if (strequal("--RTS", argv[arg])) {
575             arg++;
576             break;
577         }
578         // The '--' argument is passed through to the program, but
579         // disables all further +RTS ... -RTS processing.
580         else if (strequal("--", argv[arg])) {
581             break;
582         }
583         else if (strequal("+RTS", argv[arg])) {
584             mode = RTS;
585         }
586         else if (strequal("-RTS", argv[arg])) {
587             mode = PGM;
588         }
589         else if (mode == RTS && *rts_argc < MAX_RTS_ARGS-1) {
590             rts_argv[(*rts_argc)++] = argv[arg];
591         }
592         else if (mode == PGM) {
593             argv[(*argc)++] = argv[arg];
594         }
595         else {
596           barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
597         }
598     }
599     // process remaining program arguments
600     for (; arg < total_arg; arg++) {
601         argv[(*argc)++] = argv[arg];
602     }
603     argv[*argc] = (char *) 0;
604     rts_argv[*rts_argc] = (char *) 0;
605
606     // Process RTS (rts_argv) part: mainly to determine statsfile
607     for (arg = 0; arg < *rts_argc; arg++) {
608         if (rts_argv[arg][0] != '-') {
609             fflush(stdout);
610             errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
611             error = rtsTrue;
612
613         } else {
614             switch(rts_argv[arg][1]) {
615
616               /* process: general args, then PROFILING-only ones,
617                  then CONCURRENT-only, PARallel-only, GRAN-only,
618                  TICKY-only (same order as defined in RtsFlags.lh);
619                  within those groups, mostly in case-insensitive
620                  alphabetical order.
621                  Final group is x*, which allows for more options.
622               */
623
624 #ifdef TICKY_TICKY
625 # define TICKY_BUILD_ONLY(x) x
626 #else
627 # define TICKY_BUILD_ONLY(x) \
628 errorBelch("not built for: ticky-ticky stats"); \
629 error = rtsTrue;
630 #endif
631
632 #if defined(PROFILING) 
633 # define COST_CENTRE_USING_BUILD_ONLY(x) x
634 #else
635 # define COST_CENTRE_USING_BUILD_ONLY(x) \
636 errorBelch("not built for: -prof or -parallel"); \
637 error = rtsTrue;
638 #endif
639
640 #ifdef PROFILING
641 # define PROFILING_BUILD_ONLY(x)   x
642 #else
643 # define PROFILING_BUILD_ONLY(x) \
644 errorBelch("not built for: -prof"); \
645 error = rtsTrue;
646 #endif
647
648 #ifdef PAR
649 # define PAR_BUILD_ONLY(x)      x
650 #else
651 # define PAR_BUILD_ONLY(x) \
652 errorBelch("not built for: -parallel"); \
653 error = rtsTrue;
654 #endif
655
656 #ifdef THREADED_RTS
657 # define THREADED_BUILD_ONLY(x)      x
658 #else
659 # define THREADED_BUILD_ONLY(x) \
660 errorBelch("not built for: -smp"); \
661 error = rtsTrue;
662 #endif
663
664 #if defined(THREADED_RTS) || defined(PAR)
665 # define PAR_OR_THREADED_BUILD_ONLY(x)      x
666 #else
667 # define PAR_OR_THREADED_BUILD_ONLY(x) \
668 errorBelch("not built for: -parallel or -smp"); \
669 error = rtsTrue;
670 #endif
671
672 #ifdef GRAN
673 # define GRAN_BUILD_ONLY(x)     x
674 #else
675 # define GRAN_BUILD_ONLY(x) \
676 errorBelch("not built for: -gransim"); \
677 error = rtsTrue;
678 #endif
679
680               /* =========== GENERAL ========================== */
681               case '?':
682                 error = rtsTrue;
683                 break;
684
685               /* This isn't going to allow us to keep related options
686                  together as we add more --* flags. We really need a
687                  proper options parser. */
688               case '-':
689                   if (strequal("install-signal-handlers=yes",
690                                &rts_argv[arg][2])) {
691                       RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
692                   }
693                   else if (strequal("install-signal-handlers=no",
694                                &rts_argv[arg][2])) {
695                       RtsFlags.MiscFlags.install_signal_handlers = rtsFalse;
696                   }
697                   else if (strequal("info",
698                                &rts_argv[arg][2])) {
699                       printRtsInfo();
700                       exit(0);
701                   }
702                   else {
703                       errorBelch("unknown RTS option: %s",rts_argv[arg]);
704                       error = rtsTrue;
705                   }
706                   break;
707               case 'A':
708                 RtsFlags.GcFlags.minAllocAreaSize
709                   = decode(rts_argv[arg]+2) / BLOCK_SIZE;
710                 if (RtsFlags.GcFlags.minAllocAreaSize <= 0) {
711                   bad_option(rts_argv[arg]);
712                 }
713                 break;
714
715 #ifdef USE_PAPI
716               case 'a':
717                 switch(rts_argv[arg][2]) {
718                 case '1':
719                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L1;
720                   break;
721                 case '2':
722                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_CACHE_L2;
723                   break;
724                 case 'b':
725                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_BRANCH;
726                   break;
727                 case 's':
728                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_STALLS;
729                   break;
730                 case 'e':
731                   RtsFlags.PapiFlags.eventType = PAPI_FLAG_CB_EVENTS;
732                   break;
733                 case '+':
734                   if (RtsFlags.PapiFlags.numUserEvents >= MAX_PAPI_USER_EVENTS) {
735                       errorBelch("maximum number of PAPI events reached");
736                       stg_exit(EXIT_FAILURE);
737                   }
738                   RtsFlags.PapiFlags.eventType = PAPI_USER_EVENTS;
739                   RtsFlags.PapiFlags.userEvents[RtsFlags.PapiFlags.numUserEvents++] = rts_argv[arg] + 3;
740                   break;
741                 default:
742                   bad_option( rts_argv[arg] );
743                 }
744                 break;
745 #endif
746
747               case 'B':
748                 RtsFlags.GcFlags.ringBell = rtsTrue;
749                 break;
750
751               case 'c':
752                   if (rts_argv[arg][2] != '\0') {
753                       RtsFlags.GcFlags.compactThreshold =
754                           atof(rts_argv[arg]+2);
755                   } else {
756                       RtsFlags.GcFlags.compact = rtsTrue;
757                   }
758                   break;
759
760               case 'w':
761                 RtsFlags.GcFlags.sweep = rtsTrue;
762                 break;
763
764               case 'F':
765                 RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
766               
767                 if (RtsFlags.GcFlags.oldGenFactor < 0)
768                   bad_option( rts_argv[arg] );
769                 break;
770               
771 #ifdef DEBUG
772               case 'D':
773               { 
774                   char *c;
775
776                   for (c  = rts_argv[arg] + 2; *c != '\0'; c++) {
777                       switch (*c) {
778                       case 's':
779                           RtsFlags.DebugFlags.scheduler = rtsTrue;
780                           break;
781                       case 'i':
782                           RtsFlags.DebugFlags.interpreter = rtsTrue;
783                           break;
784                       case 'w':
785                           RtsFlags.DebugFlags.weak = rtsTrue;
786                           break;
787                       case 'G':
788                           RtsFlags.DebugFlags.gccafs = rtsTrue;
789                           break;
790                       case 'g':
791                           RtsFlags.DebugFlags.gc = rtsTrue;
792                           break;
793                       case 'b':
794                           RtsFlags.DebugFlags.block_alloc = rtsTrue;
795                           break;
796                       case 'S':
797                           RtsFlags.DebugFlags.sanity = rtsTrue;
798                           break;
799                       case 't':
800                           RtsFlags.DebugFlags.stable = rtsTrue;
801                           break;
802                       case 'p':
803                           RtsFlags.DebugFlags.prof = rtsTrue;
804                           break;
805                       case 'r':
806                           RtsFlags.DebugFlags.gran = rtsTrue;
807                           break;
808                       case 'P':
809                           RtsFlags.DebugFlags.par = rtsTrue;
810                           break;
811                       case 'l':
812                           RtsFlags.DebugFlags.linker = rtsTrue;
813                           break;
814                       case 'a':
815                           RtsFlags.DebugFlags.apply = rtsTrue;
816                           break;
817                       case 'm':
818                           RtsFlags.DebugFlags.stm = rtsTrue;
819                           break;
820                       case 'z':
821                           RtsFlags.DebugFlags.squeeze = rtsTrue;
822                           break;
823                       case 'c':
824                           RtsFlags.DebugFlags.hpc = rtsTrue;
825                           break;
826                       default:
827                           bad_option( rts_argv[arg] );
828                       }
829                   }
830                   break;
831               }
832 #endif
833
834               case 'K':
835                 RtsFlags.GcFlags.maxStkSize = 
836                   decode(rts_argv[arg]+2) / sizeof(W_);
837
838                 if (RtsFlags.GcFlags.maxStkSize == 0) 
839                   bad_option( rts_argv[arg] );
840                 break;
841
842               case 'k':
843                 RtsFlags.GcFlags.initialStkSize = 
844                   decode(rts_argv[arg]+2) / sizeof(W_);
845
846                 if (RtsFlags.GcFlags.initialStkSize == 0) 
847                   bad_option( rts_argv[arg] );
848                 break;
849
850               case 'M':
851                 RtsFlags.GcFlags.maxHeapSize = 
852                   decode(rts_argv[arg]+2) / BLOCK_SIZE;
853                 /* user give size in *bytes* but "maxHeapSize" is in *blocks* */
854
855                 if (RtsFlags.GcFlags.maxHeapSize <= 0) {
856                   bad_option(rts_argv[arg]);
857                 }
858                 break;
859
860               case 'm':
861                 RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
862
863                 if (RtsFlags.GcFlags.pcFreeHeap < 0 || 
864                     RtsFlags.GcFlags.pcFreeHeap > 100)
865                   bad_option( rts_argv[arg] );
866                 break;
867
868               case 'G':
869                 RtsFlags.GcFlags.generations = decode(rts_argv[arg]+2);
870                 if (RtsFlags.GcFlags.generations < 1) {
871                   bad_option(rts_argv[arg]);
872                 }
873                 break;
874
875               case 'T':
876                 RtsFlags.GcFlags.steps = decode(rts_argv[arg]+2);
877                 if (RtsFlags.GcFlags.steps < 1) {
878                   bad_option(rts_argv[arg]);
879                 }
880                 break;
881
882               case 'H':
883                 RtsFlags.GcFlags.heapSizeSuggestion = 
884                   decode(rts_argv[arg]+2) / BLOCK_SIZE;
885                 break;
886
887 #ifdef RTS_GTK_FRONTPANEL
888               case 'f':
889                   RtsFlags.GcFlags.frontpanel = rtsTrue;
890                   break;
891 #endif
892
893               case 'I': /* idle GC delay */
894                 if (rts_argv[arg][2] == '\0') {
895                   /* use default */
896                 } else {
897                     I_ cst; /* tmp */
898
899                     /* Convert to millisecs */
900                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
901                     RtsFlags.GcFlags.idleGCDelayTime = cst;
902                 }
903                 break;
904
905               case 'S':
906                   RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
907                   goto stats;
908
909               case 's':
910                   RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
911                   goto stats;
912
913               case 't':
914                   RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
915                   goto stats;
916
917             stats:
918 #ifdef PAR
919                 /* Opening all those files would almost certainly fail... */
920                 // RtsFlags.ParFlags.ParStats.Full = rtsTrue;
921                 RtsFlags.GcFlags.statsFile = NULL; /* temporary; ToDo: rm */
922 #else
923                 { 
924                     int r;
925                     r = open_stats_file(arg, *argc, argv,
926                                         *rts_argc, rts_argv, NULL,
927                                         &RtsFlags.GcFlags.statsFile);
928                     if (r == -1) { error = rtsTrue; }
929                 }
930 #endif
931                   break;
932
933               case 'Z':
934                 RtsFlags.GcFlags.squeezeUpdFrames = rtsFalse;
935                 break;
936
937               /* =========== PROFILING ========================== */
938
939               case 'P': /* detailed cost centre profiling (time/alloc) */
940               case 'p': /* cost centre profiling (time/alloc) */
941                 COST_CENTRE_USING_BUILD_ONLY(
942                 switch (rts_argv[arg][2]) {
943                   case 'x':
944                     RtsFlags.CcFlags.doCostCentres = COST_CENTRES_XML;
945                     break;
946                   case 'a':
947                     RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
948                     break;
949                   default:
950                       if (rts_argv[arg][1] == 'P') {
951                           RtsFlags.CcFlags.doCostCentres =
952                               COST_CENTRES_VERBOSE;
953                       } else {
954                           RtsFlags.CcFlags.doCostCentres =
955                               COST_CENTRES_SUMMARY;
956                       }
957                       break;
958                 }
959                 ) break;
960
961               case 'R':
962                   PROFILING_BUILD_ONLY(
963                       RtsFlags.ProfFlags.maxRetainerSetSize = atof(rts_argv[arg]+2);
964                   ) break;
965               case 'L':
966                   PROFILING_BUILD_ONLY(
967                       RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
968                       if(RtsFlags.ProfFlags.ccsLength <= 0) {
969                         bad_option(rts_argv[arg]);
970                       }
971                   ) break;
972               case 'h': /* serial heap profile */
973 #if !defined(PROFILING)
974                 switch (rts_argv[arg][2]) {
975                   case '\0':
976                   case 'T':
977                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
978                     break;
979                   default:
980                     errorBelch("invalid heap profile option: %s",rts_argv[arg]);
981                     error = rtsTrue;
982                 }
983 #else
984                 PROFILING_BUILD_ONLY(
985                 switch (rts_argv[arg][2]) {
986                 case '\0':
987                 case 'C':
988                 case 'c':
989                 case 'M':
990                 case 'm':
991                 case 'D':
992                 case 'd':
993                 case 'Y':
994                 case 'y':
995                 case 'R':
996                 case 'r':
997                 case 'B':
998                 case 'b':
999                     if (rts_argv[arg][2] != '\0' && rts_argv[arg][3] != '\0') {
1000                         {
1001                             char *left  = strchr(rts_argv[arg], '{');
1002                             char *right = strrchr(rts_argv[arg], '}');
1003
1004                             // curly braces are optional, for
1005                             // backwards compat.
1006                             if (left)
1007                                 left = left+1;
1008                             else
1009                                 left = rts_argv[arg] + 3;
1010
1011                             if (!right)
1012                                 right = rts_argv[arg] + strlen(rts_argv[arg]);
1013
1014                             *right = '\0';
1015
1016                             switch (rts_argv[arg][2]) {
1017                             case 'c': // cost centre label select
1018                                 RtsFlags.ProfFlags.ccSelector = left;
1019                                 break;
1020                             case 'C':
1021                                 RtsFlags.ProfFlags.ccsSelector = left;
1022                                 break;
1023                             case 'M':
1024                             case 'm': // cost centre module select
1025                                 RtsFlags.ProfFlags.modSelector = left;
1026                                 break;
1027                             case 'D':
1028                             case 'd': // closure descr select 
1029                                 RtsFlags.ProfFlags.descrSelector = left;
1030                                 break;
1031                             case 'Y':
1032                             case 'y': // closure type select
1033                                 RtsFlags.ProfFlags.typeSelector = left;
1034                                 break;
1035                             case 'R':
1036                             case 'r': // retainer select
1037                                 RtsFlags.ProfFlags.retainerSelector = left;
1038                                 break;
1039                             case 'B':
1040                             case 'b': // biography select
1041                                 RtsFlags.ProfFlags.bioSelector = left;
1042                                 break;
1043                             }
1044                         }
1045                         break;
1046                     }
1047
1048                     if (RtsFlags.ProfFlags.doHeapProfile != 0) {
1049                         errorBelch("multiple heap profile options");
1050                         error = rtsTrue;
1051                         break;
1052                     }
1053
1054                     switch (rts_argv[arg][2]) {
1055                     case '\0':
1056                     case 'C':
1057                     case 'c':
1058                         RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
1059                         break;
1060                     case 'M':
1061                     case 'm':
1062                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
1063                           break;
1064                     case 'D':
1065                     case 'd':
1066                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
1067                           break;
1068                     case 'Y':
1069                     case 'y':
1070                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
1071                           break;
1072                     case 'R':
1073                     case 'r':
1074                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
1075                           break;
1076                     case 'B':
1077                     case 'b':
1078                           RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
1079                           break;
1080                     }
1081                     break;
1082                       
1083                 default:
1084                     errorBelch("invalid heap profile option: %s",rts_argv[arg]);
1085                     error = rtsTrue;
1086                 }
1087                 ) 
1088 #endif /* PROFILING */
1089                 break;
1090
1091               case 'i': /* heap sample interval */
1092                 if (rts_argv[arg][2] == '\0') {
1093                   /* use default */
1094                 } else {
1095                     I_ cst; /* tmp */
1096
1097                     /* Convert to milliseconds */
1098                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
1099                     RtsFlags.ProfFlags.profileInterval = cst;
1100                 }
1101                 break;
1102
1103               /* =========== CONCURRENT ========================= */
1104               case 'C': /* context switch interval */
1105                 if (rts_argv[arg][2] == '\0')
1106                     RtsFlags.ConcFlags.ctxtSwitchTime = 0;
1107                 else {
1108                     I_ cst; /* tmp */
1109
1110                     /* Convert to milliseconds */
1111                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
1112                     RtsFlags.ConcFlags.ctxtSwitchTime = cst;
1113                 }
1114                 break;
1115
1116               case 'V': /* master tick interval */
1117                 if (rts_argv[arg][2] == '\0') {
1118                     // turns off ticks completely
1119                     RtsFlags.MiscFlags.tickInterval = 0;
1120                 } else {
1121                     I_ cst; /* tmp */
1122
1123                     /* Convert to milliseconds */
1124                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
1125                     RtsFlags.MiscFlags.tickInterval = cst;
1126                 }
1127                 break;
1128
1129 #if defined(THREADED_RTS) && !defined(NOSMP)
1130               case 'N':
1131                 THREADED_BUILD_ONLY(
1132                 if (rts_argv[arg][2] != '\0') {
1133                     RtsFlags.ParFlags.nNodes
1134                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1135                     // set -g at the same time as -N by default
1136                     RtsFlags.ParFlags.gcThreads = RtsFlags.ParFlags.nNodes;
1137                     if (RtsFlags.ParFlags.nNodes <= 0) {
1138                       errorBelch("bad value for -N");
1139                       error = rtsTrue;
1140                     }
1141 #if defined(PROFILING)
1142                     if (RtsFlags.ParFlags.nNodes > 1) {
1143                         errorBelch("bad option %s: only -N1 is supported with profiling", rts_argv[arg]);
1144                       error = rtsTrue;
1145                     }
1146 #endif
1147                 }
1148                 ) break;
1149
1150               case 'g':
1151                 THREADED_BUILD_ONLY(
1152                 if (rts_argv[arg][2] != '\0') {
1153                     RtsFlags.ParFlags.gcThreads
1154                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1155                     if (RtsFlags.ParFlags.gcThreads <= 0) {
1156                       errorBelch("bad value for -g");
1157                       error = rtsTrue;
1158                     }
1159                 }
1160                 ) break;
1161
1162               case 'q':
1163                     switch (rts_argv[arg][2]) {
1164                     case '\0':
1165                         errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1166                         error = rtsTrue;
1167                         break;
1168                     case 'm':
1169                         RtsFlags.ParFlags.migrate = rtsFalse;
1170                         break;
1171                     case 'w':
1172                         RtsFlags.ParFlags.wakeupMigrate = rtsTrue;
1173                         break;
1174                     default:
1175                         errorBelch("unknown RTS option: %s",rts_argv[arg]);
1176                         error = rtsTrue;
1177                         break;
1178                     }
1179                     break;
1180 #endif
1181               /* =========== PARALLEL =========================== */
1182               case 'e':
1183                 PAR_OR_THREADED_BUILD_ONLY(
1184                 if (rts_argv[arg][2] != '\0') {
1185                     RtsFlags.ParFlags.maxLocalSparks
1186                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1187                     if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
1188                       errorBelch("bad value for -e");
1189                       error = rtsTrue;
1190                     }
1191                 }
1192                 ) break;
1193
1194 #ifdef PAR
1195               case 'q':
1196                 PAR_BUILD_ONLY(
1197                   process_par_option(arg, rts_argc, rts_argv, &error);
1198                 ) break;
1199 #endif
1200
1201               /* =========== GRAN =============================== */
1202
1203               case 'b':
1204                 GRAN_BUILD_ONLY(
1205                   process_gran_option(arg, rts_argc, rts_argv, &error);
1206                 ) break;
1207
1208               /* =========== TICKY ============================== */
1209
1210               case 'r': /* Basic profiling stats */
1211                 TICKY_BUILD_ONLY(
1212
1213                 RtsFlags.TickyFlags.showTickyStats = rtsTrue;
1214
1215                 { 
1216                     int r;
1217                     r = open_stats_file(arg, *argc, argv,
1218                                         *rts_argc, rts_argv, TICKY_FILENAME_FMT,
1219                                         &RtsFlags.TickyFlags.tickyFile);
1220                     if (r == -1) { error = rtsTrue; }
1221                 }
1222                 ) break;
1223
1224               /* =========== TRACING ---------=================== */
1225
1226               case 'v':
1227                 switch(rts_argv[arg][2]) {
1228                 case '\0':
1229                     errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1230                     error = rtsTrue;
1231                     break;
1232                 case 't':
1233                     RtsFlags.TraceFlags.timestamp = rtsTrue;
1234                     break;
1235                 case 's':
1236                     RtsFlags.TraceFlags.sched = rtsTrue;
1237                     break;
1238                 case 'g':
1239                     RtsFlags.TraceFlags.gc = rtsTrue;
1240                     break;
1241                 default:
1242                     errorBelch("unknown RTS option: %s",rts_argv[arg]);
1243                     error = rtsTrue;
1244                     break;
1245                 }
1246                 break;
1247
1248               /* =========== EXTENDED OPTIONS =================== */
1249
1250               case 'x': /* Extend the argument space */
1251                 switch(rts_argv[arg][2]) {
1252                   case '\0':
1253                     errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1254                     error = rtsTrue;
1255                     break;
1256
1257                 case 'b': /* heapBase in hex; undocumented */
1258                     if (rts_argv[arg][3] != '\0') {
1259                         RtsFlags.GcFlags.heapBase
1260                             = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1261                     } else {
1262                         errorBelch("-xb: requires argument");
1263                         error = rtsTrue;
1264                     }
1265                     break;
1266
1267 #if defined(x86_64_HOST_ARCH)
1268                 case 'm': /* linkerMemBase */
1269                     if (rts_argv[arg][3] != '\0') {
1270                         RtsFlags.MiscFlags.linkerMemBase
1271                             = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1272                         if (RtsFlags.MiscFlags.linkerMemBase > 0x80000000) {
1273                             errorBelch("-xm: value must be <80000000");
1274                             error = rtsTrue;
1275                         }
1276                     } else {
1277                         RtsFlags.MiscFlags.linkerMemBase = 0;
1278                     }
1279                     break;
1280 #endif
1281
1282                 case 'c': /* Debugging tool: show current cost centre on an exception */
1283                     PROFILING_BUILD_ONLY(
1284                         RtsFlags.ProfFlags.showCCSOnException = rtsTrue;
1285                         );
1286                     break;
1287
1288                 case 't':  /* Include memory used by TSOs in a heap profile */
1289                     PROFILING_BUILD_ONLY(
1290                         RtsFlags.ProfFlags.includeTSOs = rtsTrue;
1291                         );
1292                     break;
1293
1294                   /* The option prefix '-xx' is reserved for future extension.  KSW 1999-11. */
1295
1296                   default:
1297                     errorBelch("unknown RTS option: %s",rts_argv[arg]);
1298                     error = rtsTrue;
1299                     break;
1300                 }
1301                 break;  /* defensive programming */
1302
1303               /* =========== OH DEAR ============================ */
1304               default:
1305                 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1306                 error = rtsTrue;
1307                 break;
1308             }
1309         }
1310     }
1311
1312     if (RtsFlags.MiscFlags.tickInterval < 0) {
1313         RtsFlags.MiscFlags.tickInterval = 50;
1314     }
1315
1316     // If the master timer is disabled, turn off the other timers.
1317     if (RtsFlags.MiscFlags.tickInterval == 0) {
1318         RtsFlags.ConcFlags.ctxtSwitchTime  = 0;
1319         RtsFlags.GcFlags.idleGCDelayTime   = 0;
1320         RtsFlags.ProfFlags.profileInterval = 0;
1321     }
1322
1323     // Determine what tick interval we should use for the RTS timer
1324     // by taking the shortest of the various intervals that we need to
1325     // monitor.
1326     if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1327         RtsFlags.MiscFlags.tickInterval =
1328             stg_min(RtsFlags.ConcFlags.ctxtSwitchTime,
1329                     RtsFlags.MiscFlags.tickInterval);
1330     }
1331
1332     if (RtsFlags.GcFlags.idleGCDelayTime > 0) {
1333         RtsFlags.MiscFlags.tickInterval =
1334             stg_min(RtsFlags.GcFlags.idleGCDelayTime,
1335                     RtsFlags.MiscFlags.tickInterval);
1336     }
1337
1338     if (RtsFlags.ProfFlags.profileInterval > 0) {
1339         RtsFlags.MiscFlags.tickInterval =
1340             stg_min(RtsFlags.ProfFlags.profileInterval,
1341                     RtsFlags.MiscFlags.tickInterval);
1342     }
1343
1344     if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1345         RtsFlags.ConcFlags.ctxtSwitchTicks =
1346             RtsFlags.ConcFlags.ctxtSwitchTime /
1347             RtsFlags.MiscFlags.tickInterval;
1348     } else {
1349         RtsFlags.ConcFlags.ctxtSwitchTicks = 0;
1350     }
1351
1352     if (RtsFlags.ProfFlags.profileInterval > 0) {
1353         RtsFlags.ProfFlags.profileIntervalTicks =
1354             RtsFlags.ProfFlags.profileInterval / 
1355             RtsFlags.MiscFlags.tickInterval;
1356     } else {
1357         RtsFlags.ProfFlags.profileIntervalTicks = 0;
1358     }
1359
1360     if (error) {
1361         const char **p;
1362
1363         fflush(stdout);
1364         for (p = usage_text; *p; p++)
1365             errorBelch("%s", *p);
1366         stg_exit(EXIT_FAILURE);
1367     }
1368 }
1369
1370 #if defined(GRAN)
1371
1372 static void
1373 enable_GranSimLight(void) {
1374
1375     debugBelch("GrAnSim Light enabled (infinite number of processors;  0 communication costs)\n");
1376     RtsFlags.GranFlags.Light=rtsTrue;
1377     RtsFlags.GranFlags.Costs.latency = 
1378         RtsFlags.GranFlags.Costs.fetchtime = 
1379         RtsFlags.GranFlags.Costs.additional_latency =
1380         RtsFlags.GranFlags.Costs.gunblocktime = 
1381         RtsFlags.GranFlags.Costs.lunblocktime =
1382         RtsFlags.GranFlags.Costs.threadcreatetime = 
1383         RtsFlags.GranFlags.Costs.threadqueuetime =
1384         RtsFlags.GranFlags.Costs.threadscheduletime = 
1385         RtsFlags.GranFlags.Costs.threaddescheduletime =
1386         RtsFlags.GranFlags.Costs.threadcontextswitchtime = 0;
1387   
1388     RtsFlags.GranFlags.Costs.mpacktime = 
1389         RtsFlags.GranFlags.Costs.munpacktime = 0;
1390
1391     RtsFlags.GranFlags.DoFairSchedule = rtsTrue;
1392     RtsFlags.GranFlags.DoAsyncFetch = rtsFalse;
1393     RtsFlags.GranFlags.DoAlwaysCreateThreads = rtsTrue;
1394     /* FetchStrategy is irrelevant in GrAnSim-Light */
1395
1396     /* GrAnSim Light often creates an abundance of parallel threads,
1397        each with its own stack etc. Therefore, it's in general a good
1398        idea to use small stack chunks (use the -o<size> option to 
1399        increase it again). 
1400     */
1401     // RtsFlags.ConcFlags.stkChunkSize = 100;
1402
1403     RtsFlags.GranFlags.proc = 1; 
1404 }
1405
1406 static void
1407 process_gran_option(int arg, int *rts_argc, char *rts_argv[], rtsBool *error)
1408 {
1409     if (rts_argv[arg][1] != 'b') /* All GranSim options start with -b */
1410       return;
1411
1412     /* or a ridiculously idealised simulator */
1413     if(strcmp((rts_argv[arg]+2),"oring")==0) {
1414       RtsFlags.GranFlags.Costs.latency = 
1415         RtsFlags.GranFlags.Costs.fetchtime = 
1416         RtsFlags.GranFlags.Costs.additional_latency =
1417         RtsFlags.GranFlags.Costs.gunblocktime = 
1418         RtsFlags.GranFlags.Costs.lunblocktime =
1419         RtsFlags.GranFlags.Costs.threadcreatetime = 
1420         RtsFlags.GranFlags.Costs.threadqueuetime =
1421         RtsFlags.GranFlags.Costs.threadscheduletime = 
1422         RtsFlags.GranFlags.Costs.threaddescheduletime =
1423         RtsFlags.GranFlags.Costs.threadcontextswitchtime = 0;
1424
1425       RtsFlags.GranFlags.Costs.mpacktime = 
1426         RtsFlags.GranFlags.Costs.munpacktime = 0;
1427
1428       RtsFlags.GranFlags.Costs.arith_cost = 
1429         RtsFlags.GranFlags.Costs.float_cost = 
1430         RtsFlags.GranFlags.Costs.load_cost =
1431         RtsFlags.GranFlags.Costs.store_cost = 
1432         RtsFlags.GranFlags.Costs.branch_cost = 0;
1433
1434       RtsFlags.GranFlags.Costs.heapalloc_cost = 1;
1435
1436       /* ++RtsFlags.GranFlags.DoFairSchedule; */
1437       RtsFlags.GranFlags.DoStealThreadsFirst = rtsTrue;        /* -bZ */
1438       RtsFlags.GranFlags.DoThreadMigration   = rtsTrue;        /* -bM */
1439       RtsFlags.GranFlags.GranSimStats.Full   = rtsTrue;        /* -bP */
1440       return;
1441     }
1442
1443       /* or a somewhat idealised simulator */
1444       if(strcmp((rts_argv[arg]+2),"onzo")==0) {
1445         RtsFlags.GranFlags.Costs.latency = 
1446         RtsFlags.GranFlags.Costs.fetchtime = 
1447         RtsFlags.GranFlags.Costs.additional_latency =
1448         RtsFlags.GranFlags.Costs.gunblocktime = 
1449         RtsFlags.GranFlags.Costs.lunblocktime =
1450         RtsFlags.GranFlags.Costs.threadcreatetime = 
1451         RtsFlags.GranFlags.Costs.threadqueuetime =
1452         RtsFlags.GranFlags.Costs.threadscheduletime = 
1453         RtsFlags.GranFlags.Costs.threaddescheduletime =
1454         RtsFlags.GranFlags.Costs.threadcontextswitchtime = 0;
1455
1456         RtsFlags.GranFlags.Costs.mpacktime = 
1457         RtsFlags.GranFlags.Costs.munpacktime = 0;
1458         
1459         RtsFlags.GranFlags.Costs.heapalloc_cost = 1;
1460
1461         /* RtsFlags.GranFlags.DoFairSchedule  = rtsTrue; */       /* -b-R */
1462         /* RtsFlags.GranFlags.DoStealThreadsFirst = rtsTrue; */   /* -b-T */
1463         RtsFlags.GranFlags.DoAsyncFetch = rtsTrue;         /* -bZ */
1464         RtsFlags.GranFlags.DoThreadMigration  = rtsTrue;          /* -bM */
1465         RtsFlags.GranFlags.GranSimStats.Full  = rtsTrue;          /* -bP */
1466 #  if defined(GRAN_CHECK) && defined(GRAN)
1467         RtsFlags.GranFlags.Debug.event_stats = rtsTrue; /* print event statistics   */
1468 #  endif
1469         return;
1470       }
1471
1472       /* Communication and task creation cost parameters */
1473       switch(rts_argv[arg][2]) {
1474         case '.':
1475           IgnoreYields = rtsTrue; // HWL HACK
1476           break;
1477
1478         case ':':
1479           enable_GranSimLight();       /* set flags for GrAnSim-Light mode */
1480           break;
1481
1482         case 'l':
1483           if (rts_argv[arg][3] != '\0')
1484             {
1485               RtsFlags.GranFlags.Costs.gunblocktime = 
1486               RtsFlags.GranFlags.Costs.latency = decode(rts_argv[arg]+3);
1487               RtsFlags.GranFlags.Costs.fetchtime = 2*RtsFlags.GranFlags.Costs.latency;
1488             }
1489           else
1490             RtsFlags.GranFlags.Costs.latency = LATENCY;
1491           break;
1492
1493         case 'a':
1494           if (rts_argv[arg][3] != '\0')
1495             RtsFlags.GranFlags.Costs.additional_latency = decode(rts_argv[arg]+3);
1496           else
1497             RtsFlags.GranFlags.Costs.additional_latency = ADDITIONAL_LATENCY;
1498           break;
1499
1500         case 'm':
1501           if (rts_argv[arg][3] != '\0')
1502             RtsFlags.GranFlags.Costs.mpacktime = decode(rts_argv[arg]+3);
1503           else
1504             RtsFlags.GranFlags.Costs.mpacktime = MSGPACKTIME;
1505           break;
1506
1507         case 'x':
1508           if (rts_argv[arg][3] != '\0')
1509             RtsFlags.GranFlags.Costs.mtidytime = decode(rts_argv[arg]+3);
1510           else
1511             RtsFlags.GranFlags.Costs.mtidytime = 0;
1512           break;
1513
1514         case 'r':
1515           if (rts_argv[arg][3] != '\0')
1516             RtsFlags.GranFlags.Costs.munpacktime = decode(rts_argv[arg]+3);
1517           else
1518             RtsFlags.GranFlags.Costs.munpacktime = MSGUNPACKTIME;
1519           break;
1520           
1521         case 'g':
1522           if (rts_argv[arg][3] != '\0')
1523             RtsFlags.GranFlags.Costs.fetchtime = decode(rts_argv[arg]+3);
1524           else
1525             RtsFlags.GranFlags.Costs.fetchtime = FETCHTIME;
1526           break;
1527           
1528         case 'n':
1529           if (rts_argv[arg][3] != '\0')
1530             RtsFlags.GranFlags.Costs.gunblocktime = decode(rts_argv[arg]+3);
1531           else
1532             RtsFlags.GranFlags.Costs.gunblocktime = GLOBALUNBLOCKTIME;
1533           break;
1534
1535         case 'u':
1536           if (rts_argv[arg][3] != '\0')
1537             RtsFlags.GranFlags.Costs.lunblocktime = decode(rts_argv[arg]+3);
1538           else
1539             RtsFlags.GranFlags.Costs.lunblocktime = LOCALUNBLOCKTIME;
1540           break;
1541
1542         /* Thread-related metrics */
1543         case 't':
1544           if (rts_argv[arg][3] != '\0')
1545             RtsFlags.GranFlags.Costs.threadcreatetime = decode(rts_argv[arg]+3);
1546           else
1547             RtsFlags.GranFlags.Costs.threadcreatetime = THREADCREATETIME;
1548           break;
1549           
1550         case 'q':
1551           if (rts_argv[arg][3] != '\0')
1552             RtsFlags.GranFlags.Costs.threadqueuetime = decode(rts_argv[arg]+3);
1553           else
1554             RtsFlags.GranFlags.Costs.threadqueuetime = THREADQUEUETIME;
1555           break;
1556           
1557         case 'c':
1558           if (rts_argv[arg][3] != '\0')
1559             RtsFlags.GranFlags.Costs.threadscheduletime = decode(rts_argv[arg]+3);
1560           else
1561             RtsFlags.GranFlags.Costs.threadscheduletime = THREADSCHEDULETIME;
1562           
1563           RtsFlags.GranFlags.Costs.threadcontextswitchtime = RtsFlags.GranFlags.Costs.threadscheduletime
1564             + RtsFlags.GranFlags.Costs.threaddescheduletime;
1565           break;
1566
1567         case 'd':
1568           if (rts_argv[arg][3] != '\0')
1569             RtsFlags.GranFlags.Costs.threaddescheduletime = decode(rts_argv[arg]+3);
1570           else
1571             RtsFlags.GranFlags.Costs.threaddescheduletime = THREADDESCHEDULETIME;
1572           
1573           RtsFlags.GranFlags.Costs.threadcontextswitchtime = RtsFlags.GranFlags.Costs.threadscheduletime
1574             + RtsFlags.GranFlags.Costs.threaddescheduletime;
1575           break;
1576
1577         /* Instruction Cost Metrics */
1578         case 'A':
1579           if (rts_argv[arg][3] != '\0')
1580             RtsFlags.GranFlags.Costs.arith_cost = decode(rts_argv[arg]+3);
1581           else
1582             RtsFlags.GranFlags.Costs.arith_cost = ARITH_COST;
1583           break;
1584
1585         case 'F':
1586           if (rts_argv[arg][3] != '\0')
1587             RtsFlags.GranFlags.Costs.float_cost = decode(rts_argv[arg]+3);
1588           else
1589             RtsFlags.GranFlags.Costs.float_cost = FLOAT_COST;
1590           break;
1591                       
1592         case 'B':
1593           if (rts_argv[arg][3] != '\0')
1594             RtsFlags.GranFlags.Costs.branch_cost = decode(rts_argv[arg]+3);
1595           else
1596             RtsFlags.GranFlags.Costs.branch_cost = BRANCH_COST;
1597           break;
1598
1599         case 'L':
1600           if (rts_argv[arg][3] != '\0')
1601             RtsFlags.GranFlags.Costs.load_cost = decode(rts_argv[arg]+3);
1602           else
1603             RtsFlags.GranFlags.Costs.load_cost = LOAD_COST;
1604           break;
1605           
1606         case 'S':
1607           if (rts_argv[arg][3] != '\0')
1608             RtsFlags.GranFlags.Costs.store_cost = decode(rts_argv[arg]+3);
1609           else
1610             RtsFlags.GranFlags.Costs.store_cost = STORE_COST;
1611           break;
1612
1613         case 'H':
1614           if (rts_argv[arg][3] != '\0')
1615             RtsFlags.GranFlags.Costs.heapalloc_cost = decode(rts_argv[arg]+3);
1616           else
1617             RtsFlags.GranFlags.Costs.heapalloc_cost = 0;
1618           break;
1619
1620         case 'y':
1621           RtsFlags.GranFlags.DoAsyncFetch = rtsTrue;
1622           if (rts_argv[arg][3] != '\0')
1623             RtsFlags.GranFlags.FetchStrategy = decode(rts_argv[arg]+3);
1624           else
1625             RtsFlags.GranFlags.FetchStrategy = 2;
1626           if (RtsFlags.GranFlags.FetchStrategy == 0)
1627             RtsFlags.GranFlags.DoAsyncFetch = rtsFalse;
1628           break;
1629           
1630         case 'K':   /* sort overhead (per elem in spark list) */
1631           if (rts_argv[arg][3] != '\0')
1632             RtsFlags.GranFlags.Costs.pri_spark_overhead = decode(rts_argv[arg]+3);
1633           else
1634             RtsFlags.GranFlags.Costs.pri_spark_overhead = PRI_SPARK_OVERHEAD;
1635           debugBelch("Overhead for pri spark: %d (per elem).\n",
1636                          RtsFlags.GranFlags.Costs.pri_spark_overhead);
1637           break;
1638
1639         case 'O':  /* sort overhead (per elem in spark list) */
1640           if (rts_argv[arg][3] != '\0')
1641             RtsFlags.GranFlags.Costs.pri_sched_overhead = decode(rts_argv[arg]+3);
1642           else
1643             RtsFlags.GranFlags.Costs.pri_sched_overhead = PRI_SCHED_OVERHEAD;
1644           debugBelch("Overhead for pri sched: %d (per elem).\n",
1645                        RtsFlags.GranFlags.Costs.pri_sched_overhead);
1646           break;
1647
1648         /* General Parameters */
1649         case 'p':
1650           if (rts_argv[arg][3] != '\0')
1651             {
1652               RtsFlags.GranFlags.proc = decode(rts_argv[arg]+3);
1653               if (RtsFlags.GranFlags.proc==0) {
1654                   enable_GranSimLight(); /* set flags for GrAnSim-Light mode */
1655               } else if (RtsFlags.GranFlags.proc > MAX_PROC || 
1656                          RtsFlags.GranFlags.proc < 1)
1657                 {
1658                   debugBelch("setupRtsFlags: no more than %u processors allowed\n",
1659                           MAX_PROC);
1660                   *error = rtsTrue;
1661                 }
1662             }
1663           else
1664             RtsFlags.GranFlags.proc = MAX_PROC;
1665           break;
1666
1667         case 'f':
1668           RtsFlags.GranFlags.Fishing = rtsTrue;
1669           if (rts_argv[arg][3] != '\0')
1670             RtsFlags.GranFlags.maxFishes = decode(rts_argv[arg]+3);
1671           else
1672             RtsFlags.GranFlags.maxFishes = MAX_FISHES;
1673           break;
1674           
1675         case 'w':
1676           if (rts_argv[arg][3] != '\0')
1677             RtsFlags.GranFlags.time_slice = decode(rts_argv[arg]+3);
1678           else
1679             RtsFlags.GranFlags.time_slice = GRAN_TIME_SLICE;
1680           break;
1681           
1682         case 'C':
1683           RtsFlags.GranFlags.DoAlwaysCreateThreads=rtsTrue;
1684           RtsFlags.GranFlags.DoThreadMigration=rtsTrue;
1685           break;
1686
1687         case 'G':
1688           debugBelch("Bulk fetching enabled.\n");
1689           RtsFlags.GranFlags.DoBulkFetching=rtsTrue;
1690           break;
1691           
1692         case 'M':
1693           debugBelch("Thread migration enabled.\n");
1694           RtsFlags.GranFlags.DoThreadMigration=rtsTrue;
1695           break;
1696
1697         case 'R':
1698           debugBelch("Fair Scheduling enabled.\n");
1699           RtsFlags.GranFlags.DoFairSchedule=rtsTrue;
1700           break;
1701           
1702         case 'I':
1703           debugBelch("Priority Scheduling enabled.\n");
1704           RtsFlags.GranFlags.DoPriorityScheduling=rtsTrue;
1705           break;
1706
1707         case 'T':
1708           RtsFlags.GranFlags.DoStealThreadsFirst=rtsTrue;
1709           RtsFlags.GranFlags.DoThreadMigration=rtsTrue;
1710           break;
1711           
1712         case 'Z':
1713           RtsFlags.GranFlags.DoAsyncFetch=rtsTrue;
1714           break;
1715           
1716 /*          case 'z': */
1717 /*        RtsFlags.GranFlags.SimplifiedFetch=rtsTrue; */
1718 /*        break; */
1719           
1720         case 'N':
1721           RtsFlags.GranFlags.PreferSparksOfLocalNodes=rtsTrue;
1722           break;
1723           
1724         case 'b':
1725           RtsFlags.GranFlags.GranSimStats.Binary=rtsTrue;
1726           break;
1727           
1728         case 'P':
1729           /* format is -bP<c> where <c> is one char describing kind of profile */
1730           RtsFlags.GranFlags.GranSimStats.Full = rtsTrue;
1731           switch(rts_argv[arg][3]) {
1732           case '\0': break; // nothing special, just an ordinary profile
1733           case '0': RtsFlags.GranFlags.GranSimStats.Suppressed = rtsTrue;
1734             break;
1735           case 'b': RtsFlags.GranFlags.GranSimStats.Binary = rtsTrue;
1736             break;
1737           case 's': RtsFlags.GranFlags.GranSimStats.Sparks = rtsTrue;
1738             break;
1739           case 'h': RtsFlags.GranFlags.GranSimStats.Heap = rtsTrue;
1740             break;
1741           case 'n': RtsFlags.GranFlags.GranSimStats.NewLogfile = rtsTrue;
1742             break;
1743           case 'g': RtsFlags.GranFlags.GranSimStats.Global = rtsTrue;
1744             break;
1745           default: barf("Unknown option -bP%c", rts_argv[arg][3]);
1746           }
1747           break;
1748
1749         case 's':
1750           RtsFlags.GranFlags.GranSimStats.Sparks=rtsTrue;
1751           break;
1752
1753         case 'h':
1754           RtsFlags.GranFlags.GranSimStats.Heap=rtsTrue;
1755           break;
1756
1757         case 'Y':   /* syntax: -bY<n>[,<n>]  n ... pos int */ 
1758           if (rts_argv[arg][3] != '\0') {
1759             char *arg0, *tmp;
1760             
1761             arg0 = rts_argv[arg]+3;
1762             if ((tmp = strstr(arg0,","))==NULL) {
1763               RtsFlags.GranFlags.SparkPriority = decode(arg0);
1764               debugBelch("SparkPriority: %u.\n",RtsFlags.GranFlags.SparkPriority);
1765             } else {
1766               *(tmp++) = '\0'; 
1767               RtsFlags.GranFlags.SparkPriority = decode(arg0);
1768               RtsFlags.GranFlags.SparkPriority2 = decode(tmp);
1769               debugBelch("SparkPriority: %u.\n",
1770                       RtsFlags.GranFlags.SparkPriority);
1771               debugBelch("SparkPriority2:%u.\n",
1772                       RtsFlags.GranFlags.SparkPriority2);
1773               if (RtsFlags.GranFlags.SparkPriority2 < 
1774                   RtsFlags.GranFlags.SparkPriority) {
1775                 debugBelch("WARNING: 2nd pri < main pri (%u<%u); 2nd pri has no effect\n",
1776                         RtsFlags.GranFlags.SparkPriority2,
1777                         RtsFlags.GranFlags.SparkPriority);
1778               }
1779             }
1780           } else {
1781             /* plain pri spark is now invoked with -bX  
1782                RtsFlags.GranFlags.DoPrioritySparking = 1;
1783                debugBelch("PrioritySparking.\n");
1784             */
1785           }
1786           break;
1787
1788         case 'Q':
1789           if (rts_argv[arg][3] != '\0') {
1790             RtsFlags.GranFlags.ThunksToPack = decode(rts_argv[arg]+3);
1791           } else {
1792             RtsFlags.GranFlags.ThunksToPack = 1;
1793           }
1794           debugBelch("Thunks To Pack in one packet: %u.\n",
1795                   RtsFlags.GranFlags.ThunksToPack);
1796           break;
1797                       
1798         case 'e':
1799           RtsFlags.GranFlags.RandomSteal = rtsFalse;
1800           debugBelch("Deterministic mode (no random stealing)\n");
1801                       break;
1802
1803           /* The following class of options contains eXperimental */
1804           /* features in connection with exploiting granularity */
1805           /* information. I.e. if -bY is chosen these options */
1806           /* tell the RTS what to do with the supplied info --HWL */
1807
1808         case 'W':
1809           if (rts_argv[arg][3] != '\0') {
1810             RtsFlags.GranFlags.packBufferSize_internal = decode(rts_argv[arg]+3);
1811           } else {
1812             RtsFlags.GranFlags.packBufferSize_internal = GRANSIM_DEFAULT_PACK_BUFFER_SIZE;
1813           }
1814           debugBelch("Size of GranSim internal pack buffer: %u.\n",
1815                   RtsFlags.GranFlags.packBufferSize_internal);
1816           break;
1817                       
1818         case 'X':
1819           switch(rts_argv[arg][3]) {
1820             
1821             case '\0':
1822               RtsFlags.GranFlags.DoPrioritySparking = 1;
1823               debugBelch("Priority Sparking with Normal Priorities.\n");
1824               RtsFlags.GranFlags.InversePriorities = rtsFalse; 
1825               RtsFlags.GranFlags.RandomPriorities = rtsFalse;
1826               RtsFlags.GranFlags.IgnorePriorities = rtsFalse;
1827               break;
1828                         
1829             case 'I':
1830               RtsFlags.GranFlags.DoPrioritySparking = 1;
1831               debugBelch("Priority Sparking with Inverse Priorities.\n");
1832               RtsFlags.GranFlags.InversePriorities++; 
1833               break;
1834               
1835             case 'R': 
1836               RtsFlags.GranFlags.DoPrioritySparking = 1;
1837               debugBelch("Priority Sparking with Random Priorities.\n");
1838               RtsFlags.GranFlags.RandomPriorities++;
1839               break;
1840               
1841             case 'N':
1842               RtsFlags.GranFlags.DoPrioritySparking = 1;
1843               debugBelch("Priority Sparking with No Priorities.\n");
1844               RtsFlags.GranFlags.IgnorePriorities++;
1845               break;
1846               
1847             default:
1848               bad_option( rts_argv[arg] );
1849               break;
1850           }
1851           break;
1852
1853         case '-':
1854           switch(rts_argv[arg][3]) {
1855             
1856             case 'C':
1857               RtsFlags.GranFlags.DoAlwaysCreateThreads=rtsFalse;
1858               RtsFlags.GranFlags.DoThreadMigration=rtsFalse;
1859               break;
1860
1861             case 'G':
1862               RtsFlags.GranFlags.DoBulkFetching=rtsFalse;
1863               break;
1864               
1865             case 'M':
1866               RtsFlags.GranFlags.DoThreadMigration=rtsFalse;
1867               break;
1868
1869             case 'R':
1870               RtsFlags.GranFlags.DoFairSchedule=rtsFalse;
1871               break;
1872
1873             case 'T':
1874               RtsFlags.GranFlags.DoStealThreadsFirst=rtsFalse;
1875               RtsFlags.GranFlags.DoThreadMigration=rtsFalse;
1876               break;
1877
1878             case 'Z':
1879               RtsFlags.GranFlags.DoAsyncFetch=rtsFalse;
1880               break;
1881               
1882             case 'N':
1883               RtsFlags.GranFlags.PreferSparksOfLocalNodes=rtsFalse;
1884                          break;
1885                          
1886             case 'P':
1887               RtsFlags.GranFlags.GranSimStats.Suppressed=rtsTrue;
1888               break;
1889
1890             case 's':
1891               RtsFlags.GranFlags.GranSimStats.Sparks=rtsFalse;
1892               break;
1893             
1894             case 'h':
1895               RtsFlags.GranFlags.GranSimStats.Heap=rtsFalse;
1896               break;
1897             
1898             case 'b':
1899               RtsFlags.GranFlags.GranSimStats.Binary=rtsFalse;
1900               break;
1901                          
1902             case 'X':
1903               RtsFlags.GranFlags.DoPrioritySparking = rtsFalse;
1904               break;
1905
1906             case 'Y':
1907               RtsFlags.GranFlags.DoPrioritySparking = rtsFalse;
1908               RtsFlags.GranFlags.SparkPriority = rtsFalse;
1909               break;
1910
1911             case 'I':
1912               RtsFlags.GranFlags.DoPriorityScheduling = rtsFalse;
1913               break;
1914
1915             case 'e':
1916               RtsFlags.GranFlags.RandomSteal = rtsFalse;
1917               break;
1918
1919             default:
1920               bad_option( rts_argv[arg] );
1921               break;
1922           }
1923           break;
1924
1925 #  if defined(GRAN_CHECK) && defined(GRAN)
1926         case 'D':
1927           switch(rts_argv[arg][3]) {
1928             case 'Q':    /* Set pack buffer size (same as 'Q' in GUM) */
1929               if (rts_argv[arg][4] != '\0') {
1930                 RtsFlags.GranFlags.packBufferSize = decode(rts_argv[arg]+4);
1931                 debugBelch("Pack buffer size: %d\n",
1932                         RtsFlags.GranFlags.packBufferSize);
1933               } else {
1934                 debugBelch("setupRtsFlags: missing size of PackBuffer (for -Q)\n");
1935                 *error = rtsTrue;
1936               }
1937               break;
1938
1939           default:
1940               if (isdigit(rts_argv[arg][3])) {/* Set all debugging options in one */
1941                 /* hack warning: interpret the flags as a binary number */
1942                 nat n = decode(rts_argv[arg]+3);
1943                 set_GranSim_debug_options(n);
1944               } else {
1945                 nat i;
1946                 for (i=0; i<=MAX_GRAN_DEBUG_OPTION; i++) 
1947                   if (rts_argv[arg][3] == gran_debug_opts_flags[i])
1948                     break;
1949                 
1950                 if (i==MAX_GRAN_DEBUG_OPTION+1) {
1951                   debugBelch("Valid GranSim debug options are:\n");
1952                   help_GranSim_debug_options(MAX_GRAN_DEBUG_MASK);
1953                   bad_option( rts_argv[arg] );
1954                 } else { // flag found; now set it
1955                   set_GranSim_debug_options(GRAN_DEBUG_MASK(i));  // 2^i
1956                 }
1957               }
1958               break;
1959               
1960 #if 0
1961             case 'e':       /* event trace; also -bD1 */
1962               debugBelch("DEBUG: event_trace; printing event trace.\n");
1963               RtsFlags.GranFlags.Debug.event_trace = rtsTrue;
1964               /* RtsFlags.GranFlags.event_trace=rtsTrue; */
1965               break;
1966               
1967             case 'E':       /* event statistics; also -bD2 */
1968               debugBelch("DEBUG: event_stats; printing event statistics.\n");
1969               RtsFlags.GranFlags.Debug.event_stats = rtsTrue;
1970               /* RtsFlags.GranFlags.Debug |= 0x20; print event statistics   */
1971               break;
1972               
1973             case 'f':       /* thunkStealing; also -bD4 */
1974               debugBelch("DEBUG: thunkStealing; printing forwarding of FETCHNODES.\n");
1975               RtsFlags.GranFlags.Debug.thunkStealing = rtsTrue;
1976               /* RtsFlags.GranFlags.Debug |= 0x2;  print fwd messages */
1977               break;
1978
1979             case 'z':       /* blockOnFetch; also -bD8 */
1980               debugBelch("DEBUG: blockOnFetch; check for blocked on fetch.\n");
1981               RtsFlags.GranFlags.Debug.blockOnFetch = rtsTrue;
1982               /* RtsFlags.GranFlags.Debug |= 0x4; debug non-reschedule-on-fetch */
1983               break;
1984               
1985             case 't':       /* blockOnFetch_sanity; also -bD16 */  
1986               debugBelch("DEBUG: blockOnFetch_sanity; check for TSO asleep on fetch.\n");
1987               RtsFlags.GranFlags.Debug.blockOnFetch_sanity = rtsTrue;
1988               /* RtsFlags.GranFlags.Debug |= 0x10; debug TSO asleep for fetch  */
1989               break;
1990
1991             case 'S':       /* priSpark; also -bD32 */
1992               debugBelch("DEBUG: priSpark; priority sparking.\n");
1993               RtsFlags.GranFlags.Debug.priSpark = rtsTrue;
1994               break;
1995
1996             case 's':       /* priSched; also -bD64 */
1997               debugBelch("DEBUG: priSched; priority scheduling.\n");
1998               RtsFlags.GranFlags.Debug.priSched = rtsTrue;
1999               break;
2000
2001             case 'F':       /* findWork; also -bD128 */
2002               debugBelch("DEBUG: findWork; searching spark-pools (local & remote), thread queues for work.\n");
2003               RtsFlags.GranFlags.Debug.findWork = rtsTrue;
2004               break;
2005               
2006             case 'g':       /* globalBlock; also -bD256 */
2007               debugBelch("DEBUG: globalBlock; blocking on remote closures (FETCHMEs etc in GUM).\n");
2008               RtsFlags.GranFlags.Debug.globalBlock = rtsTrue;
2009               break;
2010               
2011             case 'G':       /* pack; also -bD512 */
2012               debugBelch("DEBUG: pack; routines for (un-)packing graph structures.\n");
2013               RtsFlags.GranFlags.Debug.pack = rtsTrue;
2014               break;
2015               
2016             case 'P':       /* packBuffer; also -bD1024 */
2017               debugBelch("DEBUG: packBuffer; routines handling pack buffer (GranSim internal!).\n");
2018               RtsFlags.GranFlags.Debug.packBuffer = rtsTrue;
2019               break;
2020               
2021             case 'o':       /* sortedQ; also -bD2048 */
2022               debugBelch("DEBUG: sortedQ; check whether spark/thread queues are sorted.\n");
2023               RtsFlags.GranFlags.Debug.sortedQ = rtsTrue;
2024               break;
2025               
2026             case 'r':       /* randomSteal; also -bD4096 */
2027               debugBelch("DEBUG: randomSteal; stealing sparks/threads from random PEs.\n");
2028               RtsFlags.GranFlags.Debug.randomSteal = rtsTrue;
2029               break;
2030               
2031             case 'q':       /* checkSparkQ; also -bD8192 */
2032               debugBelch("DEBUG: checkSparkQ; check consistency of the spark queues.\n");
2033               RtsFlags.GranFlags.Debug.checkSparkQ = rtsTrue;
2034               break;
2035               
2036             case ':':       /* checkLight; also -bD16384 */
2037               debugBelch("DEBUG: checkLight; check GranSim-Light setup.\n");
2038               RtsFlags.GranFlags.Debug.checkLight = rtsTrue;
2039               break;
2040               
2041             case 'b':       /* bq; also -bD32768 */
2042               debugBelch("DEBUG: bq; check blocking queues\n");
2043               RtsFlags.GranFlags.Debug.bq = rtsTrue;
2044               break;
2045               
2046             case 'd':       /* all options turned on */
2047               debugBelch("DEBUG: all options turned on.\n");
2048               set_GranSim_debug_options(MAX_GRAN_DEBUG_MASK);
2049               /* RtsFlags.GranFlags.Debug |= 0x40; */
2050               break;
2051
2052 /*          case '\0': */
2053 /*            RtsFlags.GranFlags.Debug = 1; */
2054 /*            break; */
2055 #endif
2056
2057           }
2058           break;
2059 #  endif  /* GRAN_CHECK */
2060       default:
2061         bad_option( rts_argv[arg] );
2062         break;
2063       }
2064 }
2065
2066 /*
2067   Interpret n as a binary number masking GranSim debug options and set the 
2068   correxponding option. See gran_debug_opts_strs for explanations of the flags.
2069 */
2070 static void
2071 set_GranSim_debug_options(nat n) {
2072   nat i;
2073
2074   for (i=0; i<=MAX_GRAN_DEBUG_OPTION; i++) 
2075     if ((n>>i)&1) {
2076       errorBelch(gran_debug_opts_strs[i]);
2077       switch (i) {
2078         case 0: RtsFlags.GranFlags.Debug.event_trace   = rtsTrue;  break;
2079         case 1: RtsFlags.GranFlags.Debug.event_stats   = rtsTrue;  break;
2080         case 2: RtsFlags.GranFlags.Debug.bq            = rtsTrue;  break;
2081         case 3: RtsFlags.GranFlags.Debug.pack          = rtsTrue;  break;
2082         case 4: RtsFlags.GranFlags.Debug.checkSparkQ   = rtsTrue;  break;
2083         case 5: RtsFlags.GranFlags.Debug.thunkStealing = rtsTrue;  break;
2084         case 6: RtsFlags.GranFlags.Debug.randomSteal   = rtsTrue;  break;
2085         case 7: RtsFlags.GranFlags.Debug.findWork      = rtsTrue;  break;
2086         case 8: RtsFlags.GranFlags.Debug.unused        = rtsTrue;  break;
2087         case 9: RtsFlags.GranFlags.Debug.pri           = rtsTrue;  break;
2088         case 10: RtsFlags.GranFlags.Debug.checkLight   = rtsTrue;  break;
2089         case 11: RtsFlags.GranFlags.Debug.sortedQ      = rtsTrue;  break;
2090         case 12: RtsFlags.GranFlags.Debug.blockOnFetch = rtsTrue;  break;
2091         case 13: RtsFlags.GranFlags.Debug.packBuffer   = rtsTrue;  break;
2092         case 14: RtsFlags.GranFlags.Debug.blockOnFetch_sanity = rtsTrue;  break;
2093         default: barf("set_GranSim_debug_options: only %d debug options expected");
2094       } /* switch */
2095     } /* if */
2096 }
2097
2098 /*
2099   Print one line explanation for each of the GranSim debug options specified
2100   in the bitmask n.
2101 */
2102 static void
2103 help_GranSim_debug_options(nat n) {
2104   nat i;
2105
2106   for (i=0; i<=MAX_GRAN_DEBUG_OPTION; i++) 
2107     if ((n>>i)&1) 
2108       debugBelch(gran_debug_opts_strs[i]);
2109 }
2110
2111 # elif defined(PAR)
2112
2113 static void
2114 process_par_option(int arg, int *rts_argc, char *rts_argv[], rtsBool *error)
2115 {
2116
2117   if (rts_argv[arg][1] != 'q') { /* All GUM options start with -q */
2118     errorBelch("Warning: GUM option does not start with -q: %s", rts_argv[arg]);
2119     return;
2120   }
2121
2122   /* Communication and task creation cost parameters */
2123   switch(rts_argv[arg][2]) {
2124   case 'e':  /* -qe<n>  ... allow <n> local sparks */
2125     if (rts_argv[arg][3] != '\0') { /* otherwise, stick w/ the default */
2126       RtsFlags.ParFlags.maxLocalSparks
2127         = strtol(rts_argv[arg]+3, (char **) NULL, 10);
2128       
2129       if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
2130         errorBelch("setupRtsFlags: bad value for -e\n");
2131         *error = rtsTrue;
2132       }
2133     }
2134     IF_PAR_DEBUG(verbose,
2135                  errorBelch("-qe<n>: max %d local sparks", 
2136                        RtsFlags.ParFlags.maxLocalSparks));
2137     break;
2138   
2139   case 't':
2140     if (rts_argv[arg][3] != '\0') {
2141       RtsFlags.ParFlags.maxThreads
2142         = strtol(rts_argv[arg]+3, (char **) NULL, 10);
2143     } else {
2144       errorBelch("missing size for -qt\n");
2145       *error = rtsTrue;
2146     }
2147     IF_PAR_DEBUG(verbose,
2148                  errorBelch("-qt<n>: max %d threads", 
2149                        RtsFlags.ParFlags.maxThreads));
2150     break;
2151
2152   case 'f':
2153     if (rts_argv[arg][3] != '\0')
2154       RtsFlags.ParFlags.maxFishes = decode(rts_argv[arg]+3);
2155     else
2156       RtsFlags.ParFlags.maxFishes = MAX_FISHES;
2157     break;
2158     IF_PAR_DEBUG(verbose,
2159                  errorBelch("-qf<n>: max %d fishes sent out at one time", 
2160                        RtsFlags.ParFlags.maxFishes));
2161     break;
2162   
2163   case 'F':
2164     if (rts_argv[arg][3] != '\0') {
2165       RtsFlags.ParFlags.fishDelay
2166         = strtol(rts_argv[arg]+3, (char **) NULL, 10);
2167     } else {
2168       errorBelch("missing fish delay time for -qF\n");
2169       *error = rtsTrue;
2170     }
2171     IF_PAR_DEBUG(verbose,
2172                  errorBelch("-qF<n>: fish delay time %d us", 
2173                        RtsFlags.ParFlags.fishDelay));
2174     break;
2175
2176   case 'O':
2177     RtsFlags.ParFlags.outputDisabled = rtsTrue;
2178     IF_PAR_DEBUG(verbose,
2179                  errorBelch("-qO: output disabled"));
2180     break;
2181   
2182   case 'g': /* -qg<n> ... globalisation scheme */
2183     if (rts_argv[arg][3] != '\0') {
2184       RtsFlags.ParFlags.globalising = decode(rts_argv[arg]+3);
2185     } else {
2186       errorBelch("missing identifier for globalisation scheme (for -qg)\n");
2187       *error = rtsTrue;
2188     }
2189     IF_PAR_DEBUG(verbose,
2190                  debugBelch("-qg<n>: globalisation scheme set to  %d", 
2191                        RtsFlags.ParFlags.globalising));
2192     break;
2193
2194   case 'h': /* -qh<n> ... max number of thunks (except root) in packet */
2195     if (rts_argv[arg][3] != '\0') {
2196       RtsFlags.ParFlags.thunksToPack = decode(rts_argv[arg]+3);
2197     } else {
2198       errorBelch("missing number of thunks per packet (for -qh)\n");
2199       *error = rtsTrue;
2200     }
2201     IF_PAR_DEBUG(verbose,
2202                  debugBelch("-qh<n>: thunks per packet set to %d", 
2203                        RtsFlags.ParFlags.thunksToPack));
2204     break;
2205
2206   case 'P': /* -qP for writing a log file */
2207     //RtsFlags.ParFlags.ParStats.Full = rtsFalse;
2208     /* same encoding as in GranSim after -bP */ 
2209     switch(rts_argv[arg][3]) {
2210     case '\0': RtsFlags.ParFlags.ParStats.Full = rtsTrue;
2211       break; // nothing special, just an ordinary profile
2212     case '0': RtsFlags.ParFlags.ParStats.Suppressed = rtsTrue;
2213         RtsFlags.ParFlags.ParStats.Full = rtsFalse;
2214       break;
2215     case 'b': RtsFlags.ParFlags.ParStats.Binary = rtsTrue;
2216       break;
2217     case 's': RtsFlags.ParFlags.ParStats.Sparks = rtsTrue;
2218       break;
2219       //case 'h': RtsFlags.parFlags.ParStats.Heap = rtsTrue;
2220       //  break;
2221     case 'n': RtsFlags.ParFlags.ParStats.NewLogfile = rtsTrue;
2222       break;
2223     case 'g': 
2224 # if defined(PAR_TICKY)
2225       RtsFlags.ParFlags.ParStats.Global = rtsTrue;
2226 # else 
2227       errorBelch("-qPg is only possible for a PAR_TICKY RTS, which this is not");
2228       stg_exit(EXIT_FAILURE);
2229 # endif
2230       break;
2231     default: barf("Unknown option -qP%c", rts_argv[arg][2]);
2232     }
2233     IF_PAR_DEBUG(verbose,
2234                  debugBelch("(-qP) writing to log-file (RtsFlags.ParFlags.ParStats.Full=%s)",
2235                        (RtsFlags.ParFlags.ParStats.Full ? "rtsTrue" : "rtsFalse")));
2236     break;
2237   
2238   case 'Q': /* -qQ<n> ... set pack buffer size to <n> */
2239     if (rts_argv[arg][3] != '\0') {
2240       RtsFlags.ParFlags.packBufferSize = decode(rts_argv[arg]+3);
2241     } else {
2242       errorBelch("missing size of PackBuffer (for -qQ)\n");
2243       *error = rtsTrue;
2244     }
2245     IF_PAR_DEBUG(verbose,
2246                  debugBelch("-qQ<n>: pack buffer size set to %d", 
2247                        RtsFlags.ParFlags.packBufferSize));
2248     break;
2249
2250   case 'R':
2251     RtsFlags.ParFlags.doFairScheduling = rtsTrue;
2252     IF_PAR_DEBUG(verbose,
2253                  debugBelch("-qR: fair-ish scheduling"));
2254     break;
2255   
2256 # if defined(DEBUG)  
2257   case 'w':
2258     if (rts_argv[arg][3] != '\0') {
2259       RtsFlags.ParFlags.wait
2260         = strtol(rts_argv[arg]+3, (char **) NULL, 10);
2261     } else {
2262       RtsFlags.ParFlags.wait = 1000;
2263     }
2264     IF_PAR_DEBUG(verbose,
2265                  debugBelch("-qw<n>: length of wait loop after synchr before reduction: %d", 
2266                        RtsFlags.ParFlags.wait));
2267     break;
2268
2269   case 'D':  /* -qD ... all the debugging options */
2270     if (isdigit(rts_argv[arg][3])) {/* Set all debugging options in one */
2271       /* hack warning: interpret the flags as a binary number */
2272       nat n = decode(rts_argv[arg]+3);
2273       set_par_debug_options(n);
2274     } else {
2275       nat i;
2276       for (i=0; i<=MAX_PAR_DEBUG_OPTION; i++) 
2277         if (rts_argv[arg][3] == par_debug_opts_flags[i])
2278           break;
2279         
2280       if (i==MAX_PAR_DEBUG_OPTION+1) {
2281         errorBelch("Valid GUM debug options are:\n");
2282         help_par_debug_options(MAX_PAR_DEBUG_MASK);
2283         bad_option( rts_argv[arg] );
2284       } else { // flag found; now set it
2285         set_par_debug_options(PAR_DEBUG_MASK(i));  // 2^i
2286       }
2287     }
2288     break;
2289 # endif
2290   default:
2291     errorBelch("Unknown option -q%c (%d opts in total)", 
2292           rts_argv[arg][2], *rts_argc);
2293     break;
2294   } /* switch */
2295 }
2296
2297 /*
2298   Interpret n as a binary number masking Par debug options and set the 
2299   correxponding option. See par_debug_opts_strs for explanations of the flags.
2300 */
2301 static void
2302 set_par_debug_options(nat n) {
2303   nat i;
2304
2305   for (i=0; i<=MAX_PAR_DEBUG_OPTION; i++) 
2306     if ((n>>i)&1) {
2307       debugBelch(par_debug_opts_strs[i]);
2308       switch (i) {
2309         case 0: RtsFlags.ParFlags.Debug.verbose       = rtsTrue;  break;
2310         case 1: RtsFlags.ParFlags.Debug.bq            = rtsTrue;  break;
2311         case 2: RtsFlags.ParFlags.Debug.schedule      = rtsTrue;  break;
2312         case 3: RtsFlags.ParFlags.Debug.free          = rtsTrue;  break;
2313         case 4: RtsFlags.ParFlags.Debug.resume        = rtsTrue;  break;
2314         case 5: RtsFlags.ParFlags.Debug.weight        = rtsTrue;  break;
2315         case 6: RtsFlags.ParFlags.Debug.fetch         = rtsTrue;  break;
2316           //case 7: RtsFlags.ParFlags.Debug.ack           = rtsTrue;  break;
2317         case 7: RtsFlags.ParFlags.Debug.fish          = rtsTrue;  break;
2318         case 8: RtsFlags.ParFlags.Debug.tables        = rtsTrue;  break;
2319         case 9: RtsFlags.ParFlags.Debug.packet        = rtsTrue;  break;
2320         case 10: RtsFlags.ParFlags.Debug.pack         = rtsTrue;  break;
2321         case 11: RtsFlags.ParFlags.Debug.paranoia     = rtsTrue;  break;
2322         default: barf("set_par_debug_options: only %d debug options expected",
2323                       MAX_PAR_DEBUG_OPTION);
2324       } /* switch */
2325     } /* if */
2326 }
2327
2328 /*
2329   Print one line explanation for each of the GranSim debug options specified
2330   in the bitmask n.
2331 */
2332 static void
2333 help_par_debug_options(nat n) {
2334   nat i;
2335
2336   for (i=0; i<=MAX_PAR_DEBUG_OPTION; i++) 
2337     if ((n>>i)&1) 
2338       debugBelch(par_debug_opts_strs[i]);
2339 }
2340
2341 #endif /* PAR */
2342
2343 static void
2344 stats_fprintf(FILE *f, char *s, ...)
2345 {
2346     va_list ap;
2347     va_start(ap,s);
2348     if (f == NULL) {
2349         vdebugBelch(s, ap);
2350     } else {
2351         vfprintf(f, s, ap);
2352     }
2353     va_end(ap);
2354 }
2355
2356 static int              /* return -1 on error */
2357 open_stats_file (
2358     I_ arg,
2359     int argc, char *argv[],
2360     int rts_argc, char *rts_argv[],
2361     const char *FILENAME_FMT,
2362     FILE **file_ret)
2363 {
2364     FILE *f = NULL;
2365
2366     if (strequal(rts_argv[arg]+2, "stderr")
2367         || (FILENAME_FMT == NULL && rts_argv[arg][2] == '\0')) {
2368         f = NULL; /* NULL means use debugBelch */
2369     } else {
2370         if (rts_argv[arg][2] != '\0') {  /* stats file specified */
2371             f = fopen(rts_argv[arg]+2,"w");
2372         } else {
2373             char stats_filename[STATS_FILENAME_MAXLEN]; /* default <program>.<ext> */
2374             sprintf(stats_filename, FILENAME_FMT, argv[0]);
2375             f = fopen(stats_filename,"w");
2376         }
2377         if (f == NULL) {
2378             errorBelch("Can't open stats file %s\n", rts_argv[arg]+2);
2379             return -1;
2380         }
2381     }
2382     *file_ret = f;
2383
2384     {
2385         /* Write argv and rtsv into start of stats file */
2386         int count;
2387         for(count = 0; count < argc; count++) {
2388             stats_fprintf(f, "%s ", argv[count]);
2389         }
2390         stats_fprintf(f, "+RTS ");
2391         for(count = 0; count < rts_argc; count++)
2392             stats_fprintf(f, "%s ", rts_argv[count]);
2393         stats_fprintf(f, "\n");
2394     }
2395     return 0;
2396 }
2397
2398
2399
2400 static I_
2401 decode(const char *s)
2402 {
2403     I_ c;
2404     StgDouble m;
2405
2406     if (!*s)
2407         return 0;
2408
2409     m = atof(s);
2410     c = s[strlen(s)-1];
2411
2412     if (c == 'g' || c == 'G')
2413         m *= 1000*1000*1000;    /* UNchecked! */
2414     else if (c == 'm' || c == 'M')
2415         m *= 1000*1000;                 /* We do not use powers of 2 (1024) */
2416     else if (c == 'k' || c == 'K')      /* to avoid possible bad effects on */
2417         m *= 1000;                      /* a direct-mapped cache.           */ 
2418     else if (c == 'w' || c == 'W')
2419         m *= sizeof(W_);
2420
2421     return (I_)m;
2422 }
2423
2424 static void
2425 bad_option(const char *s)
2426 {
2427   errorBelch("bad RTS option: %s", s);
2428   stg_exit(EXIT_FAILURE);
2429 }
2430
2431 /* -----------------------------------------------------------------------------
2432    Getting/Setting the program's arguments.
2433
2434    These are used by System.Environment, and parts of the RTS.
2435    -------------------------------------------------------------------------- */
2436
2437 void
2438 setProgName(char *argv[])
2439 {
2440     /* Remove directory from argv[0] -- default files in current directory */
2441 #if !defined(mingw32_HOST_OS)
2442     char *last_slash;
2443     if ( (last_slash = (char *) strrchr(argv[0], '/')) != NULL ) {
2444         prog_name = last_slash+1;
2445    } else {
2446         prog_name = argv[0];
2447    }
2448 #else
2449     char* last_slash = argv[0] + (strlen(argv[0]) - 1);
2450     while ( last_slash > argv[0] ) {
2451         if ( *last_slash == '/' || *last_slash == '\\' ) {
2452             prog_name = last_slash+1;
2453             return;
2454         }
2455         last_slash--;
2456     }
2457     prog_name = argv[0];
2458 #endif
2459 }
2460
2461 void
2462 getProgArgv(int *argc, char **argv[])
2463 {
2464     if (argc) { *argc = prog_argc; }
2465     if (argv) { *argv = prog_argv; }
2466 }
2467
2468 void
2469 setProgArgv(int argc, char *argv[])
2470 {
2471    /* Usually this is done by startupHaskell, so we don't need to call this. 
2472       However, sometimes Hugs wants to change the arguments which Haskell
2473       getArgs >>= ... will be fed.  So you can do that by calling here
2474       _after_ calling startupHaskell.
2475    */
2476    prog_argc = argc;
2477    prog_argv = argv;
2478    setProgName(prog_argv);
2479 }
2480
2481 /* These functions record and recall the full arguments, including the
2482    +RTS ... -RTS options. The reason for adding them was so that the
2483    ghc-inplace program can pass /all/ the arguments on to the real ghc. */
2484 void
2485 getFullProgArgv(int *argc, char **argv[])
2486 {
2487     if (argc) { *argc = full_prog_argc; }
2488     if (argv) { *argv = full_prog_argv; }
2489 }
2490
2491 void
2492 setFullProgArgv(int argc, char *argv[])
2493 {
2494     int i;
2495     full_prog_argc = argc;
2496     full_prog_argv = stgCallocBytes(argc + 1, sizeof (char *),
2497                                     "setFullProgArgv 1");
2498     for (i = 0; i < argc; i++) {
2499         full_prog_argv[i] = stgMallocBytes(strlen(argv[i]) + 1,
2500                                            "setFullProgArgv 2");
2501         strcpy(full_prog_argv[i], argv[i]);
2502     }
2503     full_prog_argv[argc] = NULL;
2504 }
2505