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