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