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