[project @ 1998-11-26 09:17:22 by sof]
[ghc-hetmet.git] / ghc / runtime / main / RtsFlags.lc
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1995
3 %
4 \section{Runtime-system runtime flags}
5
6 Everything to do with RTS runtime flags, including RTS parameters
7 that can be set by them, either directly or indirectly.
8
9 @rtsFlags.lh@ defines the data structure that holds all of them.
10
11 \begin{code}
12 #include "rtsdefs.h"
13
14 struct RTS_FLAGS RTSflags; /* actually declare the data structure */
15 struct ALL_FLAGS AllFlags;
16
17 /* some fwd decls */
18 static I_     decode(const char *);
19 static void   bad_option(const char *);
20 static FILE * open_stats_file (I_ arg,
21                 int argc, char *argv[], int rts_argc, char *rts_argv[],
22                 const char *FILENAME_FMT);
23 #ifdef GRAN
24 static void   process_gran_option(int arg, 
25                 int *rts_argc, char *rts_argv[], rtsBool *error);
26 #endif
27
28 /* extern decls */
29 long strtol  PROTO((const char *, char **, int));
30 \end{code}
31
32 %************************************************************************
33 %*                                                                      *
34 \subsection{Initial default values for @RTSFlags@}
35 %*                                                                      *
36 %************************************************************************
37
38 \begin{code}
39 void
40 initRtsFlagsDefaults (STG_NO_ARGS)
41 {
42     RTSflags.GcFlags.statsFile          = NULL;
43     RTSflags.GcFlags.giveStats          = NO_GC_STATS;
44
45     RTSflags.GcFlags.stksSize           = 0x10002;  /* 2^16 = 16Kwords = 64Kbytes */
46     RTSflags.GcFlags.heapSize           = 0x100002; /* 2^20 =  1Mwords =  4Mbytes  */
47     RTSflags.GcFlags.allocAreaSize      = 0x4002;   /* 2^14 = 16Kwords = 64Kbytes;
48                                                        plus 2 cache-friendly words */
49     RTSflags.GcFlags.allocAreaSizeGiven = rtsFalse;
50     RTSflags.GcFlags.specifiedOldGenSize= 0;    /* means: use all heap available */
51     RTSflags.GcFlags.pcFreeHeap         = 3;    /* 3% */
52     /* minAllocAreaSize is derived; set in initSM,
53        after we know pcFreeHeap and heapSize */
54
55     RTSflags.GcFlags.force2s            = rtsFalse;
56     RTSflags.GcFlags.forceGC            = rtsFalse;
57     RTSflags.GcFlags.forcingInterval    = 5000000; /* 5MB (or words?) */
58     RTSflags.GcFlags.ringBell           = rtsFalse;
59     RTSflags.GcFlags.trace              = 0; /* not turned on */
60
61     RTSflags.GcFlags.lazyBlackHoling    = rtsTrue;
62     RTSflags.GcFlags.doSelectorsAtGC    = rtsTrue;
63     RTSflags.GcFlags.squeezeUpdFrames   = rtsTrue;
64
65 #if defined(PROFILING) || defined(PAR)
66     RTSflags.CcFlags.doCostCentres      = 0;
67     RTSflags.CcFlags.sortBy             = SORTCC_TIME;
68
69     /* "ctxtSwitchTicks", "profilerTicks", & "msecsPerTick" are
70         derived info, so they are set after ctxtSwitchTime has been
71         determined.
72     */
73 #endif /* PROFILING or PAR */
74
75 #ifdef PROFILING
76     RTSflags.ProfFlags.doHeapProfile = rtsFalse;
77
78     RTSflags.ProfFlags.ccSelector    = NULL;
79     RTSflags.ProfFlags.modSelector   = NULL;
80     RTSflags.ProfFlags.grpSelector   = NULL;
81     RTSflags.ProfFlags.descrSelector = NULL;
82     RTSflags.ProfFlags.typeSelector  = NULL;
83     RTSflags.ProfFlags.kindSelector  = NULL;
84 #endif /* PROFILING */
85 /* there really shouldn't be a threads limit for concurrent mandatory threads.
86    For now, unlimitied means less than 64k (there's a storage overhead) -- SOF
87 */
88 #if defined(CONCURRENT) && !defined(GRAN)
89     RTSflags.ConcFlags.ctxtSwitchTime   = CS_MIN_MILLISECS;  /* In milliseconds */
90     RTSflags.ConcFlags.maxThreads       = 65536;
91     RTSflags.ConcFlags.stkChunkSize     = 1024;
92     RTSflags.ConcFlags.maxLocalSparks   = 65536;
93 #endif /* CONCURRENT only */
94
95 #ifdef GRAN
96     RTSflags.ConcFlags.ctxtSwitchTime   = CS_MIN_MILLISECS;  /* In milliseconds */
97     RTSflags.ConcFlags.maxThreads       = 32;
98     RTSflags.ConcFlags.stkChunkSize     = 1024;
99     RTSflags.ConcFlags.maxLocalSparks   = 500;
100 #endif /* GRAN */
101
102 #ifdef PAR
103     RTSflags.ParFlags.parallelStats     = rtsFalse;
104     RTSflags.ParFlags.granSimStats      = rtsFalse;
105     RTSflags.ParFlags.granSimStats_Binary = rtsFalse;
106
107     RTSflags.ParFlags.outputDisabled    = rtsFalse;
108
109     RTSflags.ParFlags.packBufferSize    = 1024;
110 #endif /* PAR */
111
112 #ifdef GRAN
113     RTSflags.GranFlags.granSimStats     = rtsFalse;
114     RTSflags.GranFlags.granSimStats_suppressed  = rtsFalse;
115     RTSflags.GranFlags.granSimStats_Binary = rtsFalse;
116     RTSflags.GranFlags.granSimStats_Sparks = rtsFalse;
117     RTSflags.GranFlags.granSimStats_Heap = rtsFalse;
118     RTSflags.GranFlags.labelling        = rtsFalse;
119     RTSflags.GranFlags.packBufferSize   = 1024;
120     RTSflags.GranFlags.packBufferSize_internal = GRANSIM_DEFAULT_PACK_BUFFER_SIZE;
121
122     RTSflags.GranFlags.proc  = MAX_PROC;
123     RTSflags.GranFlags.max_fishes = MAX_FISHES;
124     RTSflags.GranFlags.time_slice = GRAN_TIME_SLICE;
125     RTSflags.GranFlags.Light = rtsFalse;
126
127     RTSflags.GranFlags.gran_latency =             LATENCY;          
128     RTSflags.GranFlags.gran_additional_latency =  ADDITIONAL_LATENCY; 
129     RTSflags.GranFlags.gran_fetchtime =           FETCHTIME; 
130     RTSflags.GranFlags.gran_lunblocktime =        LOCALUNBLOCKTIME; 
131     RTSflags.GranFlags.gran_gunblocktime =        GLOBALUNBLOCKTIME;
132     RTSflags.GranFlags.gran_mpacktime =           MSGPACKTIME;      
133     RTSflags.GranFlags.gran_munpacktime =         MSGUNPACKTIME;
134     RTSflags.GranFlags.gran_mtidytime =           MSGTIDYTIME;
135
136     RTSflags.GranFlags.gran_threadcreatetime =         THREADCREATETIME;
137     RTSflags.GranFlags.gran_threadqueuetime =          THREADQUEUETIME;
138     RTSflags.GranFlags.gran_threaddescheduletime =     THREADDESCHEDULETIME;
139     RTSflags.GranFlags.gran_threadscheduletime =       THREADSCHEDULETIME;
140     RTSflags.GranFlags.gran_threadcontextswitchtime =  THREADCONTEXTSWITCHTIME;
141
142     RTSflags.GranFlags.gran_arith_cost =         ARITH_COST;       
143     RTSflags.GranFlags.gran_branch_cost =        BRANCH_COST; 
144     RTSflags.GranFlags.gran_load_cost =          LOAD_COST;        
145     RTSflags.GranFlags.gran_store_cost =         STORE_COST; 
146     RTSflags.GranFlags.gran_float_cost =         FLOAT_COST;       
147
148     RTSflags.GranFlags.gran_heapalloc_cost =     HEAPALLOC_COST;
149
150     RTSflags.GranFlags.gran_pri_spark_overhead = PRI_SPARK_OVERHEAD;        
151     RTSflags.GranFlags.gran_pri_sched_overhead = PRI_SCHED_OVERHEAD;        
152
153     RTSflags.GranFlags.DoFairSchedule = rtsFalse;             
154     RTSflags.GranFlags.DoReScheduleOnFetch = rtsFalse;        
155     RTSflags.GranFlags.DoStealThreadsFirst = rtsFalse;        
156     RTSflags.GranFlags.SimplifiedFetch = rtsFalse;            
157     RTSflags.GranFlags.DoAlwaysCreateThreads = rtsFalse;      
158     RTSflags.GranFlags.DoGUMMFetching = rtsFalse;             
159     RTSflags.GranFlags.DoThreadMigration = rtsFalse;          
160     RTSflags.GranFlags.FetchStrategy = 2;                     
161     RTSflags.GranFlags.PreferSparksOfLocalNodes = rtsFalse;   
162     RTSflags.GranFlags.DoPrioritySparking = rtsFalse;         
163     RTSflags.GranFlags.DoPriorityScheduling = rtsFalse;       
164     RTSflags.GranFlags.SparkPriority = 0;
165     RTSflags.GranFlags.SparkPriority2 = 0; 
166     RTSflags.GranFlags.RandomPriorities = rtsFalse;           
167     RTSflags.GranFlags.InversePriorities = rtsFalse;          
168     RTSflags.GranFlags.IgnorePriorities = rtsFalse;           
169     RTSflags.GranFlags.ThunksToPack = 0;                      
170     RTSflags.GranFlags.RandomSteal = rtsTrue;
171     RTSflags.GranFlags.NoForward = rtsFalse;
172     RTSflags.GranFlags.PrintFetchMisses = rtsFalse;
173
174     RTSflags.GranFlags.debug = 0x0;
175     RTSflags.GranFlags.event_trace = rtsFalse;
176     RTSflags.GranFlags.event_trace_all = rtsFalse;
177 #endif
178
179 #ifdef TICKY_TICKY
180     RTSflags.TickyFlags.showTickyStats  = rtsFalse;
181     RTSflags.TickyFlags.tickyFile       = NULL;
182
183     AllFlags.doUpdEntryCounts           = rtsTrue; /*ToDo:move? */
184 #endif
185 }
186 \end{code}
187
188 %************************************************************************
189 %*                                                                      *
190 \subsection{Usage message for runtime-system (RTS) flags}
191 %*                                                                      *
192 %************************************************************************
193
194 \begin{code}
195 static const char *
196 usage_text[] = {
197 "",
198 "Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
199 "",
200 "   +RTS    Indicates run time system options follow",
201 "   -RTS    Indicates program arguments follow",
202 "  --RTS    Indicates that ALL subsequent arguments will be given to the",
203 "           program (including any of these RTS flags)",
204 "",
205 "The following run time system options are available:",
206 "",
207 "  -? -f    Prints this message and exits; the program is not executed",
208 "",
209 "  -K<size> Sets the stack size (default 64k)    Egs: -K32k   -K512k",
210 "  -H<size> Sets the heap size  (default 4M)          -H512k  -H16M",
211 "  -s<file> Summary GC statistics   (default file: <program>.stat)",
212 "  -S<file> Detailed GC statistics  (with -Sstderr going to stderr)",
213 "",
214 #if defined(GCap)
215 "  -M<n>%   Sets minimum size of alloc area as % of heap (default 3%)",
216 "  -A<size> Fixes size of alloc area, overriding any minimum (-A gives 64k)",
217 "  -G<size> Fixes size of major generation (default is dynamic threshold)",
218 "  -F2s     Forces program compiled for Appel gc to use 2s collection",
219 #else
220 # if defined(GCgn)
221 "  -A<size> Specifies size of alloc area (default 64k)",
222 "  -G<size> Fixes size of major generation (default is available heap)",
223 "  -F2s     Forces program compiled for Gen gc to use 2s collection",
224 # else
225 "  -M<n>%   Minimum % of heap which must be available (default 3%)",
226 "  -A<size> Fixes size of heap area allocated between GCs (-A gives 64k)",
227 # endif
228 #endif
229 "  -j<size> Forces major GC at every <size> bytes allocated",
230 #if defined(GCdu)
231 "  -u<percent> Fixes residency threshold at which mode switches (range 0.0..0.95)",
232 #endif
233 "",
234 "  -N       No black-holing during GC (for use when a signal handler is present)",
235 "  -Z       Don't squeeze out update frames on stack overflow",
236 "  -B       Sound the bell at the start of each (major) garbage collection",
237 #if defined(PROFILING) || defined(PAR)
238 "",
239 "  -p<sort> Produce cost centre time profile  (output file <program>.prof)",
240 "             sort: T = time (default), A = alloc, C = cost centre label",
241 "  -P<sort> Produce serial time profile (output file <program>.time)",
242 "             and a -p profile with detailed tick/alloc info",
243 # if defined(PROFILING)
244 "",
245 "  -h<break-down> Heap residency profile      (output file <program>.hp)",
246 "     break-down: C = cost centre (default), M = module, G = group",
247 "                 D = closure description, Y = type description",
248 "                 T<ints>,<start> = time closure created",
249 "                    ints:  no. of interval bands plotted (default 18)",
250 "                    start: seconds after which intervals start (default 0.0)",
251 "  A subset of closures may be selected by the attached cost centre using:",
252 "    -c{mod:lab,mod:lab...}, specific module:label cost centre(s)",
253 "    -m{mod,mod...} all cost centres from the specified modules(s)",
254 "    -g{grp,grp...} all cost centres from the specified group(s)",
255 "  Selections can also be made by description, type, kind and age:",
256 "    -d{des,des...} closures with specified closure descriptions",
257 "    -y{typ,typ...} closures with specified type descriptions",
258 "    -k{knd,knd...} closures of the specified kinds",
259 "    -a<age>        closures which survived <age> complete intervals",
260 "  The selection logic used is summarised as follows:",
261 "    ([-c] or [-m] or [-g]) and ([-d] or [-y] or [-k]) and [-a]",
262 "    where an option is true if not specified",
263 # endif
264 "",
265 "  -z<tbl><size>  set hash table <size> for <tbl> (C, M, G, D or Y)",
266 "",
267 "  -i<secs> Number of seconds in a profiling interval (default 1.0):",
268 "           heap profile (-h) and/or serial time profile (-P) frequency",
269 #endif /* PROFILING or PAR */
270 "",
271 #if defined(TICKY_TICKY)
272 "  -r<file>  Produce reduction profiling statistics (with -rstderr for stderr)",
273 "",
274 #endif
275 "  -T<level> Trace garbage collection execution (debugging)",
276 #ifdef CONCURRENT
277 "",
278 # ifdef PAR
279 "  -N<n>     Use <n> PVMish processors in parallel (default: 2)",
280 /* NB: the -N<n> is implemented by the driver!! */
281 # endif
282 "  -C<secs>  Context-switch interval in seconds",
283 "                (0 or no argument means switch as often as possible)",
284 "                the default is .01 sec; resolution is .01 sec",
285 "  -e<size>        Size of spark pools (default 100)",
286 # ifdef PAR
287 "  -q        Enable activity profile (output files in ~/<program>*.gr)",
288 "  -qb       Enable binary activity profile (output file /tmp/<program>.gb)",
289 "  -Q<size>  Set pack-buffer size (default: 1024)",
290 # else
291 "  -q[v]     Enable quasi-parallel profile (output file <program>.qp)",
292 # endif
293 "  -t<num>   Set maximum number of advisory threads per PE (default 32)",
294 "  -o<num>   Set stack chunk size (default 1024)",
295 # ifdef PAR
296 "  -d        Turn on PVM-ish debugging",
297 "  -O        Disable output for performance measurement",
298 # endif /* PAR */
299 # ifdef GRAN  /* ToDo: fill in decent Docu here */
300 "  -b...     All GranSim options start with -b; see GranSim User's Guide for details",
301 # endif
302 #endif /* CONCURRENT */
303 "",
304 "Other RTS options may be available for programs compiled a different way.",
305 "The GHC User's Guide has full details.",
306 "",
307 0
308 };
309 \end{code}
310
311 %************************************************************************
312 %*                                                                      *
313 \subsection{Processing command-line arguments to set @RTSFlags@}
314 %*                                                                      *
315 %************************************************************************
316
317 \begin{code}
318 #define RTS 1
319 #define PGM 0
320
321 #ifndef atof
322 extern double atof();
323 /* no proto because some machines use const and some do not */
324 #endif
325
326 static __inline__ rtsBool
327 strequal(const char *a, const char * b)
328 {
329     return(strcmp(a, b) == 0);
330 }
331
332 void
333 setupRtsFlags(int *argc, char *argv[], int *rts_argc, char *rts_argv[])
334 {
335     rtsBool error = rtsFalse;
336     I_ mode;
337     I_ arg, total_arg;
338     char *last_slash;
339
340     /* Remove directory from argv[0] -- default files in current directory */
341
342     if ((last_slash = (char *) strrchr(argv[0], '/')) != NULL)
343         strcpy(argv[0], last_slash+1);
344
345     /* Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts */
346     /*   argv[0] must be PGM argument -- leave in argv                 */
347
348     total_arg = *argc;
349     arg = 1;
350
351     *argc = 1;
352     *rts_argc = 0;
353
354     for (mode = PGM; arg < total_arg && ! strequal("--RTS", argv[arg]); arg++) {
355         if (strequal("+RTS", argv[arg])) {
356             mode = RTS;
357         }
358         else if (strequal("-RTS", argv[arg])) {
359             mode = PGM;
360         }
361         else if (mode == RTS && *rts_argc < MAX_RTS_ARGS-1) {
362             rts_argv[(*rts_argc)++] = argv[arg];
363         }
364         else if (mode == PGM) {
365             argv[(*argc)++] = argv[arg];
366         }
367         else {
368             fflush(stdout);
369             fprintf(stderr, "setupRtsFlags: Too many RTS arguments (max %d)\n",
370                     MAX_RTS_ARGS-1);
371             EXIT(EXIT_FAILURE);
372         }
373     }
374     if (arg < total_arg) {
375         /* arg must be --RTS; process remaining program arguments */
376         while (++arg < total_arg) {
377             argv[(*argc)++] = argv[arg];
378         }
379     }
380     argv[*argc] = (char *) 0;
381     rts_argv[*rts_argc] = (char *) 0;
382
383     /* Process RTS (rts_argv) part: mainly to determine statsfile */
384
385     for (arg = 0; arg < *rts_argc; arg++) {
386         if (rts_argv[arg][0] != '-') {
387             fflush(stdout);
388             fprintf(stderr, "setupRtsFlags: Unexpected RTS argument: %s\n",
389                     rts_argv[arg]);
390             error = rtsTrue;
391
392         } else {
393             switch(rts_argv[arg][1]) {
394
395               /* process: general args, then PROFILING-only ones,
396                  then CONCURRENT-only, PARallel-only, GRAN-only,
397                  TICKY-only (same order as defined in RtsFlags.lh);
398                  within those groups, mostly in case-insensitive
399                  alphabetical order.
400               */
401
402 #ifdef TICKY_TICKY
403 # define TICKY_BUILD_ONLY(x) x
404 #else
405 # define TICKY_BUILD_ONLY(x) \
406 fprintf(stderr, "setupRtsFlags: GHC not built for: ticky-ticky stats\n"); \
407 error = rtsTrue;
408 #endif
409
410 #if (defined(PROFILING) || defined(PAR))
411 # define COST_CENTRE_USING_BUILD_ONLY(x) x
412 #else
413 # define COST_CENTRE_USING_BUILD_ONLY(x) \
414 fprintf(stderr, "setupRtsFlags: GHC not built for: -prof or -parallel\n"); \
415 error = rtsTrue;
416 #endif
417
418 #ifdef PROFILING
419 # define PROFILING_BUILD_ONLY(x)   x
420 #else
421 # define PROFILING_BUILD_ONLY(x) \
422 fprintf(stderr, "setupRtsFlags: GHC not built for: -prof\n"); \
423 error = rtsTrue;
424 #endif
425
426 #ifdef CONCURRENT
427 # define CONCURRENT_BUILD_ONLY(x)  x
428 #else
429 # define CONCURRENT_BUILD_ONLY(x) \
430 fprintf(stderr, "setupRtsFlags: GHC not built for: -concurrent\n"); \
431 error = rtsTrue;
432 #endif
433
434 #ifdef PAR
435 # define PAR_BUILD_ONLY(x)      x
436 #else
437 # define PAR_BUILD_ONLY(x) \
438 fprintf(stderr, "setupRtsFlags: GHC not built for: -parallel\n"); \
439 error = rtsTrue;
440 #endif
441
442 #ifdef GRAN
443 # define GRAN_BUILD_ONLY(x)     x
444 #else
445 # define GRAN_BUILD_ONLY(x) \
446 fprintf(stderr, "setupRtsFlags: GHC not built for: -gransim\n"); \
447 error = rtsTrue;
448 #endif
449
450               /* =========== GENERAL ========================== */
451               case '?':
452               case 'f':
453                 error = rtsTrue;
454                 break;
455
456               case 'A':
457                 RTSflags.GcFlags.allocAreaSize
458                   = decode(rts_argv[arg]+2) / sizeof(W_);
459                 RTSflags.GcFlags.allocAreaSizeGiven = rtsTrue;
460                 break;
461
462               case 'B':
463                 RTSflags.GcFlags.ringBell = rtsTrue;
464                 break;
465
466               case 'F':
467                 if (strequal(rts_argv[arg]+2, "2s")) {
468                     RTSflags.GcFlags.force2s = rtsTrue;
469                 } else {
470                     bad_option( rts_argv[arg] );
471                 }
472                 break;
473
474               case 'G':
475                 RTSflags.GcFlags.specifiedOldGenSize
476                   = decode(rts_argv[arg]+2) / sizeof(W_);
477                 break;
478
479               case 'K':
480                 RTSflags.GcFlags.stksSize = decode(rts_argv[arg]+2) / sizeof(W_);
481
482                 if (RTSflags.GcFlags.stksSize == 0) bad_option( rts_argv[arg] );
483                 break;
484
485               case 'H':
486                 RTSflags.GcFlags.heapSize = decode(rts_argv[arg]+2) / sizeof(W_);
487                 /* user give size in *bytes* but "heapSize" is in *words* */
488
489                 if (RTSflags.GcFlags.heapSize <= 0) bad_option(rts_argv[arg]);
490                 break;
491
492               case 'j': /* force GC option */
493                 RTSflags.GcFlags.forceGC = rtsTrue;
494                 if (rts_argv[arg][2]) {
495                     RTSflags.GcFlags.forcingInterval
496                         = decode(rts_argv[arg]+2) / sizeof(W_);
497                 }
498                 break;
499
500               case 'M':
501                 RTSflags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
502
503                 if (RTSflags.GcFlags.pcFreeHeap < 0 || RTSflags.GcFlags.pcFreeHeap > 100)
504                     bad_option( rts_argv[arg] );
505                 break;
506
507               case 'N':
508                 RTSflags.GcFlags.lazyBlackHoling = rtsFalse;
509                 break;
510
511               case 'n':
512                 RTSflags.GcFlags.doSelectorsAtGC = rtsFalse;
513                 break;
514
515               case 'S': /* NB: no difference at present ! */
516               case 's':
517                 RTSflags.GcFlags.giveStats ++; /* will be VERBOSE_GC_STATS */
518 #ifdef PAR
519                 /* Opening all those files would almost certainly fail... */
520                 RTSflags.ParFlags.parallelStats = rtsTrue;
521                 RTSflags.GcFlags.statsFile = stderr; /* temporary; ToDo: rm */
522 #else
523                 RTSflags.GcFlags.statsFile
524                   = open_stats_file(arg, *argc, argv,
525                         *rts_argc, rts_argv, STAT_FILENAME_FMT);
526
527                 if (RTSflags.GcFlags.statsFile == NULL) error = rtsTrue;
528 #endif
529                 break;
530
531               case 'T':
532                 if (rts_argv[arg][2] != '\0')
533                     RTSflags.GcFlags.trace
534                       = (W_) strtol(rts_argv[arg]+2, (char **)NULL, 0);
535                 else
536                     RTSflags.GcFlags.trace = 1; /* slightly weird; why, really? */
537                 break;
538
539               case 'Z':
540                 RTSflags.GcFlags.squeezeUpdFrames = rtsFalse;
541                 break;
542
543               /* =========== PROFILING ========================== */
544
545               case 'P': /* detailed cost centre profiling (time/alloc) */
546                 COST_CENTRE_USING_BUILD_ONLY(
547                 RTSflags.CcFlags.doCostCentres++;
548                 )
549               case 'p': /* cost centre profiling (time/alloc) */
550                 COST_CENTRE_USING_BUILD_ONLY(
551                 RTSflags.CcFlags.doCostCentres++;
552
553                 switch (rts_argv[arg][2]) {
554                   case SORTCC_LABEL:
555                   case SORTCC_TIME:
556                   case SORTCC_ALLOC:
557                         RTSflags.CcFlags.sortBy = rts_argv[arg][2];
558                     break;
559                   default:
560                         RTSflags.CcFlags.sortBy = SORTCC_TIME;
561                     break;
562                 }
563                 ) break;
564
565               case 'i': /* serial profiling -- initial timer interval */
566                 COST_CENTRE_USING_BUILD_ONLY(
567                 interval_ticks = (I_) ((atof(rts_argv[arg]+2) * TICK_FREQUENCY));
568                 if (interval_ticks <= 0)
569                     interval_ticks = 1;
570                 ) break;
571
572               case 'h': /* serial heap profile */
573                 PROFILING_BUILD_ONLY(
574                 switch (rts_argv[arg][2]) {
575                   case '\0':
576                   case CCchar:
577                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_CC;
578                     break;
579                   case MODchar:
580                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
581                     break;
582                   case GRPchar:
583                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_GRP;
584                     break;
585                   case DESCRchar:
586                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
587                     break;
588                   case TYPEchar:
589                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
590                     break;
591                   case TIMEchar:
592                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_TIME;
593                     if (rts_argv[arg][3]) {
594                         char *start_str = strchr(rts_argv[arg]+3, ',');
595                         I_ intervals;
596                         if (start_str) *start_str = '\0';
597
598                         if ((intervals = decode(rts_argv[arg]+3)) != 0) {
599                             time_intervals = (hash_t) intervals;
600                             /* ToDo: and what if it *is* zero intervals??? */
601                         }
602                         if (start_str) {
603                             earlier_ticks = (I_)((atof(start_str + 1) * TICK_FREQUENCY));
604                         }
605                     }
606                     break;
607                   default:
608                     fprintf(stderr, "Invalid heap profile option: %s\n",
609                             rts_argv[arg]);
610                     error = rtsTrue;
611                 }
612                 ) break;
613
614               case 'z': /* size of index tables */
615                 PROFILING_BUILD_ONLY(
616                 switch (rts_argv[arg][2]) {
617                   case CCchar:
618                     max_cc_no = (hash_t) decode(rts_argv[arg]+3);
619                     if (max_cc_no == 0) {
620                         fprintf(stderr, "Bad number of cost centres %s\n", rts_argv[arg]);
621                         error = rtsTrue;
622                     }
623                     break;
624                   case MODchar:
625                     max_mod_no = (hash_t) decode(rts_argv[arg]+3);
626                     if (max_mod_no == 0) {
627                         fprintf(stderr, "Bad number of modules %s\n", rts_argv[arg]);
628                         error = rtsTrue;
629                     }
630                     break;
631                   case GRPchar:
632                     max_grp_no = (hash_t) decode(rts_argv[arg]+3);
633                     if (max_grp_no == 0) {
634                         fprintf(stderr, "Bad number of groups %s\n", rts_argv[arg]);
635                         error = rtsTrue;
636                     }
637                     break;
638                   case DESCRchar:
639                     max_descr_no = (hash_t) decode(rts_argv[arg]+3);
640                     if (max_descr_no == 0) {
641                         fprintf(stderr, "Bad number of closure descriptions %s\n", rts_argv[arg]);
642                         error = rtsTrue;
643                     }
644                     break;
645                   case TYPEchar:
646                     max_type_no = (hash_t) decode(rts_argv[arg]+3);
647                     if (max_type_no == 0) {
648                         fprintf(stderr, "Bad number of type descriptions %s\n", rts_argv[arg]);
649                         error = rtsTrue;
650                     }
651                     break;
652                   default:
653                     fprintf(stderr, "Invalid index table size option: %s\n",
654                             rts_argv[arg]);
655                     error = rtsTrue;
656                 }
657                 ) break;
658
659               case 'c': /* cost centre label select */
660               case 'm': /* cost centre module select */
661               case 'g': /* cost centre group select */
662               case 'd': /* closure descr select */
663               case 'y': /* closure type select */
664               case 'k': /* closure kind select */
665                 PROFILING_BUILD_ONLY(
666                 {char *left  = strchr(rts_argv[arg], '{');
667                  char *right = strrchr(rts_argv[arg], '}');
668
669                 if (! left || ! right ||
670                         strrchr(rts_argv[arg], '{') != left ||
671                          strchr(rts_argv[arg], '}') != right) {
672                     fprintf(stderr, "Invalid heap profiling selection bracketing\n   %s\n", rts_argv[arg]);
673                     error = rtsTrue;
674                 } else {
675                     *right = '\0';
676                     switch (rts_argv[arg][1]) {
677                       case 'c': /* cost centre label select */
678                         RTSflags.ProfFlags.ccSelector = left + 1;
679                         break;
680                       case 'm': /* cost centre module select */
681                         RTSflags.ProfFlags.modSelector = left + 1;
682                         break;
683                       case 'g': /* cost centre group select */
684                         RTSflags.ProfFlags.grpSelector = left + 1;
685                         break;
686                       case 'd': /* closure descr select */
687                         RTSflags.ProfFlags.descrSelector = left + 1;
688                         break;
689                       case 'y': /* closure type select */
690                         RTSflags.ProfFlags.typeSelector = left + 1;
691                         break;
692                       case 'k': /* closure kind select */
693                         RTSflags.ProfFlags.kindSelector = left + 1;
694                         break;
695                     }
696                 }}
697                 ) break;
698
699               /* =========== CONCURRENT ========================= */
700               case 'C': /* context switch interval */
701                 CONCURRENT_BUILD_ONLY (
702                 if (rts_argv[arg][2] == '\0')
703                     RTSflags.ConcFlags.ctxtSwitchTime = 0;
704                 else {
705                     I_ cst; /* tmp */
706
707                     /* Convert to milliseconds */
708                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
709                     cst = (cst / CS_MIN_MILLISECS) * CS_MIN_MILLISECS;
710                     if (cst < CS_MIN_MILLISECS)
711                         cst = CS_MIN_MILLISECS;
712
713                     RTSflags.ConcFlags.ctxtSwitchTime = cst;
714                 }
715                 ) break;
716
717               case 't':
718                 CONCURRENT_BUILD_ONLY(
719                 if (rts_argv[arg][2] != '\0') {
720                     RTSflags.ConcFlags.maxThreads
721                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
722                 } else {
723                     fprintf(stderr, "setupRtsFlags: missing size for -t\n");
724                     error = rtsTrue;
725                 }
726                 ) break;
727
728               case 'o':
729                 CONCURRENT_BUILD_ONLY (
730                 if (rts_argv[arg][2] != '\0') {
731                     I_ size = decode(rts_argv[arg]+2);
732
733                     if (size < MIN_STKO_CHUNK_SIZE)
734                         size = MIN_STKO_CHUNK_SIZE;
735
736                     RTSflags.ConcFlags.stkChunkSize = size;
737                 } else {
738                     fprintf(stderr, "setupRtsFlags: missing size for -o\n");
739                     error = rtsTrue;
740                 }
741                 ) break;
742
743               /* =========== PARALLEL =========================== */
744               case 'e':
745                 CONCURRENT_BUILD_ONLY(
746                 if (rts_argv[arg][2] != '\0') { /* otherwise, stick w/ the default */
747
748                     RTSflags.ConcFlags.maxLocalSparks
749                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
750
751                     if (RTSflags.ConcFlags.maxLocalSparks <= 0) {
752                         fprintf(stderr, "setupRtsFlags: bad value for -e\n");
753                         error = rtsTrue;
754                     }
755                 }
756                 ) break;
757
758               case 'O':
759                 PAR_BUILD_ONLY(
760                 RTSflags.ParFlags.outputDisabled = rtsTrue;
761                 ) break;
762
763               case 'q': /* activity profile option */
764                 PAR_BUILD_ONLY(
765                 if (rts_argv[arg][2] == 'b')
766                     RTSflags.ParFlags.granSimStats_Binary = rtsTrue;
767                 else
768                     RTSflags.ParFlags.granSimStats = rtsTrue;
769                 ) break;
770
771 #if 0 /* or??? */
772               case 'q': /* quasi-parallel profile option */
773                 GRAN_BUILD_ONLY (
774                 if (rts_argv[arg][2] == 'v')
775                     do_qp_prof = 2;
776                 else
777                     do_qp_prof++;
778                 ) break;
779 #endif /* 0??? */
780
781               case 'Q': /* Set pack buffer size */
782                 PAR_BUILD_ONLY(
783                 if (rts_argv[arg][2] != '\0') {
784                     RTSflags.ParFlags.packBufferSize = decode(rts_argv[arg]+2);
785                 } else {
786                     fprintf(stderr, "setupRtsFlags: missing size of PackBuffer (for -Q)\n");
787                     error = rtsTrue;
788                 }
789                 ) break;
790
791               /* =========== GRAN =============================== */
792
793               case 'b':
794                 GRAN_BUILD_ONLY(
795                 process_gran_option(arg, rts_argc, rts_argv, &error);
796                 ) break;
797
798               /* =========== TICKY ============================== */
799
800               case 'r': /* Basic profiling stats */
801                 TICKY_BUILD_ONLY(
802
803                 RTSflags.TickyFlags.showTickyStats = rtsTrue;
804                 RTSflags.TickyFlags.tickyFile
805                   = open_stats_file(arg, *argc, argv,
806                         *rts_argc, rts_argv, TICKY_FILENAME_FMT);
807
808                 if (RTSflags.TickyFlags.tickyFile == NULL) error = rtsTrue;
809                 ) break;
810
811               /* =========== OH DEAR ============================ */
812               default:
813                 fprintf(stderr, "setupRtsFlags: Unknown RTS option: %s\n",rts_argv[arg]);
814                 error = rtsTrue;
815                 break;
816             }
817         }
818     }
819     if (error) {
820         const char **p;
821
822         fflush(stdout);
823         for (p = usage_text; *p; p++)
824             fprintf(stderr, "%s\n", *p);
825         EXIT(EXIT_FAILURE);
826     }
827
828 }
829
830 #if defined(GRAN)
831 void
832 enable_GrAnSimLight() {
833
834     fprintf(stderr,"GrAnSim Light enabled (infinite number of processors;  0 communication costs)\n");
835     RTSflags.GranFlags.Light=rtsTrue;
836     RTSflags.GranFlags.gran_latency = 
837         RTSflags.GranFlags.gran_fetchtime = 
838         RTSflags.GranFlags.gran_additional_latency =
839         RTSflags.GranFlags.gran_gunblocktime = 
840         RTSflags.GranFlags.gran_lunblocktime =
841         RTSflags.GranFlags.gran_threadcreatetime = 
842         RTSflags.GranFlags.gran_threadqueuetime =
843         RTSflags.GranFlags.gran_threadscheduletime = 
844         RTSflags.GranFlags.gran_threaddescheduletime =
845         RTSflags.GranFlags.gran_threadcontextswitchtime = 0;
846   
847     RTSflags.GranFlags.gran_mpacktime = 
848         RTSflags.GranFlags.gran_munpacktime = 0;
849
850     RTSflags.GranFlags.DoFairSchedule = rtsTrue;
851     RTSflags.GranFlags.DoReScheduleOnFetch = rtsFalse;
852     RTSflags.GranFlags.DoAlwaysCreateThreads = rtsTrue;
853     /* FetchStrategy is irrelevant in GrAnSim-Light */
854
855     /* GrAnSim Light often creates an abundance of parallel threads,
856        each with its own stack etc. Therefore, it's in general a good
857        idea to use small stack chunks (use the -o<size> option to 
858        increase it again). 
859     */
860     RTSflags.ConcFlags.stkChunkSize = 100;
861
862     RTSflags.GranFlags.proc = 1; 
863 }
864
865 static void
866 process_gran_option(int arg, int *rts_argc, char *rts_argv[], rtsBool *error)
867 {
868     if (rts_argv[arg][1] != 'b') /* All GranSim options start with -b */
869       return;
870
871       /* Should we emulate hbcpp */
872       if(strcmp((rts_argv[arg]+2),"roken")==0) {
873         RTSflags.GranFlags.DoAlwaysCreateThreads=rtsTrue;
874         strcpy(rts_argv[arg]+2,"oring");
875       }
876
877       /* or a ridiculously idealised simulator */
878       if(strcmp((rts_argv[arg]+2),"oring")==0) {
879         RTSflags.GranFlags.gran_latency = 
880         RTSflags.GranFlags.gran_fetchtime = 
881         RTSflags.GranFlags.gran_additional_latency =
882         RTSflags.GranFlags.gran_gunblocktime = 
883         RTSflags.GranFlags.gran_lunblocktime =
884         RTSflags.GranFlags.gran_threadcreatetime = 
885         RTSflags.GranFlags.gran_threadqueuetime =
886         RTSflags.GranFlags.gran_threadscheduletime = 
887         RTSflags.GranFlags.gran_threaddescheduletime =
888         RTSflags.GranFlags.gran_threadcontextswitchtime = 0;
889
890         RTSflags.GranFlags.gran_mpacktime = 
891         RTSflags.GranFlags.gran_munpacktime = 0;
892
893         RTSflags.GranFlags.gran_arith_cost = 
894         RTSflags.GranFlags.gran_float_cost = 
895         RTSflags.GranFlags.gran_load_cost =
896         RTSflags.GranFlags.gran_store_cost = 
897         RTSflags.GranFlags.gran_branch_cost = 0;
898
899         RTSflags.GranFlags.gran_heapalloc_cost = 1;
900
901         /* ++RTSflags.GranFlags.DoFairSchedule; */
902         RTSflags.GranFlags.DoStealThreadsFirst = rtsTrue;         /* -bZ */
903         RTSflags.GranFlags.DoThreadMigration  = rtsTrue;          /* -bM */
904         RTSflags.GranFlags.granSimStats = rtsTrue;                /* -bP */
905         return;
906       }
907
908       /* or a somewhat idealised simulator */
909       if(strcmp((rts_argv[arg]+2),"onzo")==0) {
910         RTSflags.GranFlags.gran_latency = 
911         RTSflags.GranFlags.gran_fetchtime = 
912         RTSflags.GranFlags.gran_additional_latency =
913         RTSflags.GranFlags.gran_gunblocktime = 
914         RTSflags.GranFlags.gran_lunblocktime =
915         RTSflags.GranFlags.gran_threadcreatetime = 
916         RTSflags.GranFlags.gran_threadqueuetime =
917         RTSflags.GranFlags.gran_threadscheduletime = 
918         RTSflags.GranFlags.gran_threaddescheduletime =
919         RTSflags.GranFlags.gran_threadcontextswitchtime = 0;
920
921         RTSflags.GranFlags.gran_mpacktime = 
922         RTSflags.GranFlags.gran_munpacktime = 0;
923         
924         RTSflags.GranFlags.gran_heapalloc_cost = 1;
925
926         /* RTSflags.GranFlags.DoFairSchedule  = rtsTrue; */       /* -b-R */
927         /* RTSflags.GranFlags.DoStealThreadsFirst = rtsTrue; */   /* -b-T */
928         RTSflags.GranFlags.DoReScheduleOnFetch = rtsTrue;         /* -bZ */
929         RTSflags.GranFlags.DoThreadMigration  = rtsTrue;          /* -bM */
930         RTSflags.GranFlags.granSimStats = rtsTrue;                /* -bP */
931 #  if defined(GRAN_CHECK) && defined(GRAN)
932         RTSflags.GranFlags.debug = 0x20;       /* print event statistics   */
933 #  endif
934         return;
935       }
936
937       /* Communication and task creation cost parameters */
938       switch(rts_argv[arg][2]) {
939         case ':':
940           enable_GrAnSimLight();       /* set flags for GrAnSim-Light mode */
941           break;
942
943         case 'l':
944           if (rts_argv[arg][3] != '\0')
945             {
946               RTSflags.GranFlags.gran_gunblocktime = 
947               RTSflags.GranFlags.gran_latency = decode(rts_argv[arg]+3);
948               RTSflags.GranFlags.gran_fetchtime = 2*RTSflags.GranFlags.gran_latency;
949             }
950           else
951             RTSflags.GranFlags.gran_latency = LATENCY;
952           break;
953
954         case 'a':
955           if (rts_argv[arg][3] != '\0')
956             RTSflags.GranFlags.gran_additional_latency = decode(rts_argv[arg]+3);
957           else
958             RTSflags.GranFlags.gran_additional_latency = ADDITIONAL_LATENCY;
959           break;
960
961         case 'm':
962           if (rts_argv[arg][3] != '\0')
963             RTSflags.GranFlags.gran_mpacktime = decode(rts_argv[arg]+3);
964           else
965             RTSflags.GranFlags.gran_mpacktime = MSGPACKTIME;
966           break;
967
968         case 'x':
969           if (rts_argv[arg][3] != '\0')
970             RTSflags.GranFlags.gran_mtidytime = decode(rts_argv[arg]+3);
971           else
972             RTSflags.GranFlags.gran_mtidytime = 0;
973           break;
974
975         case 'r':
976           if (rts_argv[arg][3] != '\0')
977             RTSflags.GranFlags.gran_munpacktime = decode(rts_argv[arg]+3);
978           else
979             RTSflags.GranFlags.gran_munpacktime = MSGUNPACKTIME;
980           break;
981           
982         case 'g':
983           if (rts_argv[arg][3] != '\0')
984             RTSflags.GranFlags.gran_fetchtime = decode(rts_argv[arg]+3);
985           else
986             RTSflags.GranFlags.gran_fetchtime = FETCHTIME;
987           break;
988           
989         case 'n':
990           if (rts_argv[arg][3] != '\0')
991             RTSflags.GranFlags.gran_gunblocktime = decode(rts_argv[arg]+3);
992           else
993             RTSflags.GranFlags.gran_gunblocktime = GLOBALUNBLOCKTIME;
994           break;
995
996         case 'u':
997           if (rts_argv[arg][3] != '\0')
998             RTSflags.GranFlags.gran_lunblocktime = decode(rts_argv[arg]+3);
999           else
1000             RTSflags.GranFlags.gran_lunblocktime = LOCALUNBLOCKTIME;
1001           break;
1002
1003         /* Thread-related metrics */
1004         case 't':
1005           if (rts_argv[arg][3] != '\0')
1006             RTSflags.GranFlags.gran_threadcreatetime = decode(rts_argv[arg]+3);
1007           else
1008             RTSflags.GranFlags.gran_threadcreatetime = THREADCREATETIME;
1009           break;
1010           
1011         case 'q':
1012           if (rts_argv[arg][3] != '\0')
1013             RTSflags.GranFlags.gran_threadqueuetime = decode(rts_argv[arg]+3);
1014           else
1015             RTSflags.GranFlags.gran_threadqueuetime = THREADQUEUETIME;
1016           break;
1017           
1018         case 'c':
1019           if (rts_argv[arg][3] != '\0')
1020             RTSflags.GranFlags.gran_threadscheduletime = decode(rts_argv[arg]+3);
1021           else
1022             RTSflags.GranFlags.gran_threadscheduletime = THREADSCHEDULETIME;
1023           
1024           RTSflags.GranFlags.gran_threadcontextswitchtime = RTSflags.GranFlags.gran_threadscheduletime
1025             + RTSflags.GranFlags.gran_threaddescheduletime;
1026           break;
1027
1028         case 'd':
1029           if (rts_argv[arg][3] != '\0')
1030             RTSflags.GranFlags.gran_threaddescheduletime = decode(rts_argv[arg]+3);
1031           else
1032             RTSflags.GranFlags.gran_threaddescheduletime = THREADDESCHEDULETIME;
1033           
1034           RTSflags.GranFlags.gran_threadcontextswitchtime = RTSflags.GranFlags.gran_threadscheduletime
1035             + RTSflags.GranFlags.gran_threaddescheduletime;
1036           break;
1037
1038         /* Instruction Cost Metrics */
1039         case 'A':
1040           if (rts_argv[arg][3] != '\0')
1041             RTSflags.GranFlags.gran_arith_cost = decode(rts_argv[arg]+3);
1042           else
1043             RTSflags.GranFlags.gran_arith_cost = ARITH_COST;
1044           break;
1045
1046         case 'F':
1047           if (rts_argv[arg][3] != '\0')
1048             RTSflags.GranFlags.gran_float_cost = decode(rts_argv[arg]+3);
1049           else
1050             RTSflags.GranFlags.gran_float_cost = FLOAT_COST;
1051           break;
1052                       
1053         case 'B':
1054           if (rts_argv[arg][3] != '\0')
1055             RTSflags.GranFlags.gran_branch_cost = decode(rts_argv[arg]+3);
1056           else
1057             RTSflags.GranFlags.gran_branch_cost = BRANCH_COST;
1058           break;
1059
1060         case 'L':
1061           if (rts_argv[arg][3] != '\0')
1062             RTSflags.GranFlags.gran_load_cost = decode(rts_argv[arg]+3);
1063           else
1064             RTSflags.GranFlags.gran_load_cost = LOAD_COST;
1065           break;
1066           
1067         case 'S':
1068           if (rts_argv[arg][3] != '\0')
1069             RTSflags.GranFlags.gran_store_cost = decode(rts_argv[arg]+3);
1070           else
1071             RTSflags.GranFlags.gran_store_cost = STORE_COST;
1072           break;
1073
1074         case 'H':
1075           if (rts_argv[arg][3] != '\0')
1076             RTSflags.GranFlags.gran_heapalloc_cost = decode(rts_argv[arg]+3);
1077           else
1078             RTSflags.GranFlags.gran_heapalloc_cost = 0;
1079           break;
1080
1081         case 'y':
1082           RTSflags.GranFlags.DoReScheduleOnFetch = rtsTrue;
1083           if (rts_argv[arg][3] != '\0')
1084             RTSflags.GranFlags.FetchStrategy = decode(rts_argv[arg]+3);
1085           else
1086             RTSflags.GranFlags.FetchStrategy = 2;
1087           if (RTSflags.GranFlags.FetchStrategy == 0)
1088             RTSflags.GranFlags.DoReScheduleOnFetch = rtsFalse;
1089           break;
1090           
1091         case 'K':   /* sort overhead (per elem in spark list) */
1092           if (rts_argv[arg][3] != '\0')
1093             RTSflags.GranFlags.gran_pri_spark_overhead = decode(rts_argv[arg]+3);
1094           else
1095             RTSflags.GranFlags.gran_pri_spark_overhead = PRI_SPARK_OVERHEAD;
1096           fprintf(stderr,"Overhead for pri spark: %d (per elem).\n",
1097                          RTSflags.GranFlags.gran_pri_spark_overhead);
1098           break;
1099
1100         case 'O':  /* sort overhead (per elem in spark list) */
1101           if (rts_argv[arg][3] != '\0')
1102             RTSflags.GranFlags.gran_pri_sched_overhead = decode(rts_argv[arg]+3);
1103           else
1104             RTSflags.GranFlags.gran_pri_sched_overhead = PRI_SCHED_OVERHEAD;
1105           fprintf(stderr,"Overhead for pri sched: %d (per elem).\n",
1106                        RTSflags.GranFlags.gran_pri_sched_overhead);
1107           break;
1108
1109         /* General Parameters */
1110         case 'p':
1111           if (rts_argv[arg][3] != '\0')
1112             {
1113               RTSflags.GranFlags.proc = decode(rts_argv[arg]+3);
1114               if (RTSflags.GranFlags.proc==0) {
1115                   enable_GrAnSimLight(); /* set flags for GrAnSim-Light mode */
1116               } else if (RTSflags.GranFlags.proc > MAX_PROC || 
1117                          RTSflags.GranFlags.proc < 1)
1118                 {
1119                   fprintf(stderr,"setupRtsFlags: no more than %u processors
1120 allowed\n", 
1121                           MAX_PROC);
1122                   *error = rtsTrue;
1123                 }
1124             }
1125           else
1126             RTSflags.GranFlags.proc = MAX_PROC;
1127           break;
1128
1129         case 'f':
1130           if (rts_argv[arg][3] != '\0')
1131             RTSflags.GranFlags.max_fishes = decode(rts_argv[arg]+3);
1132           else
1133             RTSflags.GranFlags.max_fishes = MAX_FISHES;
1134           break;
1135           
1136         case 'w':
1137           if (rts_argv[arg][3] != '\0')
1138             RTSflags.GranFlags.time_slice = decode(rts_argv[arg]+3);
1139           else
1140             RTSflags.GranFlags.time_slice = GRAN_TIME_SLICE;
1141           break;
1142           
1143         case 'C':
1144           RTSflags.GranFlags.DoAlwaysCreateThreads=rtsTrue;
1145           RTSflags.GranFlags.DoThreadMigration=rtsTrue;
1146           break;
1147
1148         case 'G':
1149           fprintf(stderr,"Bulk fetching enabled.\n");
1150           RTSflags.GranFlags.DoGUMMFetching=rtsTrue;
1151           break;
1152           
1153         case 'M':
1154           fprintf(stderr,"Thread migration enabled.\n");
1155           RTSflags.GranFlags.DoThreadMigration=rtsTrue;
1156           break;
1157
1158         case 'R':
1159           fprintf(stderr,"Fair Scheduling enabled.\n");
1160           RTSflags.GranFlags.DoFairSchedule=rtsTrue;
1161           break;
1162           
1163         case 'I':
1164           fprintf(stderr,"Priority Scheduling enabled.\n");
1165           RTSflags.GranFlags.DoPriorityScheduling=rtsTrue;
1166           break;
1167
1168         case 'T':
1169           RTSflags.GranFlags.DoStealThreadsFirst=rtsTrue;
1170           RTSflags.GranFlags.DoThreadMigration=rtsTrue;
1171           break;
1172           
1173         case 'Z':
1174           RTSflags.GranFlags.DoReScheduleOnFetch=rtsTrue;
1175           break;
1176           
1177         case 'z':
1178           RTSflags.GranFlags.SimplifiedFetch=rtsTrue;
1179           break;
1180           
1181         case 'N':
1182           RTSflags.GranFlags.PreferSparksOfLocalNodes=rtsTrue;
1183           break;
1184           
1185         case 'b':
1186           RTSflags.GranFlags.granSimStats_Binary=rtsTrue;
1187           break;
1188           
1189         case 'P':
1190           RTSflags.GranFlags.granSimStats=rtsTrue;
1191           break;
1192
1193         case 's':
1194           RTSflags.GranFlags.granSimStats_Sparks=rtsTrue;
1195           break;
1196
1197         case 'h':
1198           RTSflags.GranFlags.granSimStats_Heap=rtsTrue;
1199           break;
1200
1201         case 'U':
1202           RTSflags.GranFlags.labelling=rtsTrue;
1203           break;
1204
1205         case 'Y':   /* syntax: -bY<n>[,<n>]  n ... pos int */ 
1206           if (rts_argv[arg][3] != '\0') {
1207             char *arg0, *tmp;
1208             
1209             arg0 = rts_argv[arg]+3;
1210             if ((tmp = strstr(arg0,","))==NULL) {
1211               RTSflags.GranFlags.SparkPriority = decode(arg0);
1212               fprintf(stderr,"SparkPriority: %u.\n",RTSflags.GranFlags.SparkPriority);
1213             } else {
1214               *(tmp++) = '\0'; 
1215               RTSflags.GranFlags.SparkPriority = decode(arg0);
1216               RTSflags.GranFlags.SparkPriority2 = decode(tmp);
1217               fprintf(stderr,"SparkPriority: %u.\n",
1218                       RTSflags.GranFlags.SparkPriority);
1219               fprintf(stderr,"SparkPriority2:%u.\n",
1220                       RTSflags.GranFlags.SparkPriority2);
1221               if (RTSflags.GranFlags.SparkPriority2 < 
1222                   RTSflags.GranFlags.SparkPriority) {
1223                 fprintf(stderr,"WARNING: 2nd pri < main pri (%u<%u); 2nd pri has no effect\n",
1224                         RTSflags.GranFlags.SparkPriority2,
1225                         RTSflags.GranFlags.SparkPriority);
1226               }
1227             }
1228           } else {
1229             /* plain pri spark is now invoked with -bX  
1230                RTSflags.GranFlags.DoPrioritySparking = 1;
1231                fprintf(stderr,"PrioritySparking.\n");
1232             */
1233           }
1234           break;
1235
1236         case 'Q':
1237           if (rts_argv[arg][3] != '\0') {
1238             RTSflags.GranFlags.ThunksToPack = decode(rts_argv[arg]+3);
1239           } else {
1240             RTSflags.GranFlags.ThunksToPack = 1;
1241           }
1242           fprintf(stderr,"Thunks To Pack in one packet: %u.\n",
1243                   RTSflags.GranFlags.ThunksToPack);
1244           break;
1245                       
1246         case 'e':
1247           RTSflags.GranFlags.RandomSteal = rtsFalse;
1248           fprintf(stderr,"Deterministic mode (no random stealing)\n");
1249                       break;
1250
1251           /* The following class of options contains eXperimental */
1252           /* features in connection with exploiting granularity */
1253           /* information. I.e. if -bY is chosen these options */
1254           /* tell the RTS what to do with the supplied info --HWL */
1255
1256         case 'W':
1257           if (rts_argv[arg][3] != '\0') {
1258             RTSflags.GranFlags.packBufferSize_internal = decode(rts_argv[arg]+3);
1259           } else {
1260             RTSflags.GranFlags.packBufferSize_internal = GRANSIM_DEFAULT_PACK_BUFFER_SIZE;
1261           }
1262           fprintf(stderr,"Size of GranSim internal pack buffer: %u.\n",
1263                   RTSflags.GranFlags.packBufferSize_internal);
1264           break;
1265                       
1266         case 'X':
1267           switch(rts_argv[arg][3]) {
1268             
1269             case '\0':
1270               RTSflags.GranFlags.DoPrioritySparking = 1;
1271               fprintf(stderr,"Priority Sparking with Normal Priorities.\n");
1272               RTSflags.GranFlags.InversePriorities = rtsFalse; 
1273               RTSflags.GranFlags.RandomPriorities = rtsFalse;
1274               RTSflags.GranFlags.IgnorePriorities = rtsFalse;
1275               break;
1276                         
1277             case 'I':
1278               RTSflags.GranFlags.DoPrioritySparking = 1;
1279               fprintf(stderr,"Priority Sparking with Inverse Priorities.\n");
1280               RTSflags.GranFlags.InversePriorities++; 
1281               break;
1282               
1283             case 'R': 
1284               RTSflags.GranFlags.DoPrioritySparking = 1;
1285               fprintf(stderr,"Priority Sparking with Random Priorities.\n");
1286               RTSflags.GranFlags.RandomPriorities++;
1287               break;
1288               
1289             case 'N':
1290               RTSflags.GranFlags.DoPrioritySparking = 1;
1291               fprintf(stderr,"Priority Sparking with No Priorities.\n");
1292               RTSflags.GranFlags.IgnorePriorities++;
1293               break;
1294               
1295             default:
1296               bad_option( rts_argv[arg] );
1297               break;
1298           }
1299           break;
1300
1301         case '-':
1302           switch(rts_argv[arg][3]) {
1303             
1304             case 'C':
1305               RTSflags.GranFlags.DoAlwaysCreateThreads=rtsFalse;
1306               RTSflags.GranFlags.DoThreadMigration=rtsFalse;
1307               break;
1308
1309             case 'G':
1310               RTSflags.GranFlags.DoGUMMFetching=rtsFalse;
1311               break;
1312               
1313             case 'M':
1314               RTSflags.GranFlags.DoThreadMigration=rtsFalse;
1315               break;
1316
1317             case 'R':
1318               RTSflags.GranFlags.DoFairSchedule=rtsFalse;
1319               break;
1320
1321             case 'T':
1322               RTSflags.GranFlags.DoStealThreadsFirst=rtsFalse;
1323               RTSflags.GranFlags.DoThreadMigration=rtsFalse;
1324               break;
1325
1326             case 'Z':
1327               RTSflags.GranFlags.DoReScheduleOnFetch=rtsFalse;
1328               break;
1329               
1330             case 'N':
1331               RTSflags.GranFlags.PreferSparksOfLocalNodes=rtsFalse;
1332                          break;
1333                          
1334             case 'P':
1335               RTSflags.GranFlags.granSimStats_suppressed=rtsTrue;
1336               break;
1337
1338             case 's':
1339               RTSflags.GranFlags.granSimStats_Sparks=rtsFalse;
1340               break;
1341             
1342             case 'h':
1343               RTSflags.GranFlags.granSimStats_Heap=rtsFalse;
1344               break;
1345             
1346             case 'b':
1347               RTSflags.GranFlags.granSimStats_Binary=rtsFalse;
1348               break;
1349                          
1350             case 'X':
1351               RTSflags.GranFlags.DoPrioritySparking = rtsFalse;
1352               break;
1353
1354             case 'Y':
1355               RTSflags.GranFlags.DoPrioritySparking = rtsFalse;
1356               RTSflags.GranFlags.SparkPriority = rtsFalse;
1357               break;
1358
1359             case 'I':
1360               RTSflags.GranFlags.DoPriorityScheduling = rtsFalse;
1361               break;
1362
1363             case 'e':
1364               RTSflags.GranFlags.RandomSteal = rtsFalse;
1365               break;
1366
1367             default:
1368               bad_option( rts_argv[arg] );
1369               break;
1370           }
1371           break;
1372
1373 #  if defined(GRAN_CHECK) && defined(GRAN)
1374         case 'D':
1375           switch(rts_argv[arg][3]) {
1376             case 'Q':    /* Set pack buffer size (same as 'Q' in GUM) */
1377               if (rts_argv[arg][4] != '\0') {
1378                 RTSflags.GranFlags.packBufferSize = decode(rts_argv[arg]+4);
1379                 fprintf(stderr,"Pack buffer size: %d\n",
1380                         RTSflags.GranFlags.packBufferSize);
1381               } else {
1382                 fprintf(stderr, "setupRtsFlags: missing size of PackBuffer (for -Q)\n");
1383                 error = rtsTrue;
1384               }
1385               break;
1386
1387             case 'e':       /* event trace */
1388               fprintf(stderr,"Printing event trace.\n");
1389               RTSflags.GranFlags.event_trace=rtsTrue;
1390               break;
1391               
1392             case 'f':
1393               fprintf(stderr,"Printing forwarding of FETCHNODES.\n");
1394               RTSflags.GranFlags.debug |= 0x2; /* print fwd messages */
1395               break;
1396
1397             case 'z':
1398               fprintf(stderr,"Check for blocked on fetch.\n");
1399               RTSflags.GranFlags.debug |= 0x4; /* debug non-reschedule-on-fetch */
1400               break;
1401               
1402             case 't':
1403               fprintf(stderr,"Check for TSO asleep on fetch.\n");
1404               RTSflags.GranFlags.debug |= 0x10; /* debug TSO asleep for fetch  */
1405               break;
1406
1407             case 'E':
1408               fprintf(stderr,"Printing event statistics.\n");
1409               RTSflags.GranFlags.debug |= 0x20; /* print event statistics   */
1410               break;
1411               
1412             case 'F':
1413               fprintf(stderr,"Prohibiting forward.\n");
1414               RTSflags.GranFlags.NoForward = rtsTrue; /* prohibit forwarding   */
1415               break;
1416               
1417             case 'm':
1418               fprintf(stderr,"Printing fetch misses.\n");
1419               RTSflags.GranFlags.PrintFetchMisses = rtsTrue; /* prohibit forwarding   */
1420               break;
1421
1422             case 'd':
1423               fprintf(stderr,"Debug mode.\n");
1424               RTSflags.GranFlags.debug |= 0x40; 
1425                             break;
1426
1427             case 'D':
1428               fprintf(stderr,"Severe debug mode.\n");
1429               RTSflags.GranFlags.debug |= 0x80; 
1430               break;
1431               
1432             case 'q':
1433               fprintf(stderr,"FULL event trace.\n");
1434               RTSflags.GranFlags.event_trace_all =rtsTrue;
1435               break;
1436
1437             case 'G':
1438               fprintf(stderr,"Debugging packet fetching.\n");
1439               RTSflags.GranFlags.debug |= 0x100; 
1440               break;
1441               
1442             case 'n':
1443               fprintf(stderr,"Ignore events till end of time slice\n");
1444               RTSflags.GranFlags.debug |= 0x200; 
1445               IgnoreEvents = rtsTrue;
1446               break;
1447
1448             case 'S':
1449               fprintf(stderr,"Check that spark queues are sorted.\n");
1450               RTSflags.GranFlags.debug |= 0x400; 
1451               break;
1452
1453             case 'H':
1454               fprintf(stderr,"Print heap allocation messages (RBH).\n");
1455               RTSflags.GranFlags.debug |= 0x800; 
1456               break;
1457
1458             case 'p':
1459               fprintf(stderr,"Debug breadth-first pruning.\n");
1460               RTSflags.GranFlags.debug |= 0x1000; 
1461               break;
1462               
1463             case 'r':
1464               fprintf(stderr,"Debug random stealing.\n");
1465               RTSflags.GranFlags.debug |= 0x2000; 
1466               break;
1467
1468             case 'B':
1469               fprintf(stderr,"Debug busyness.\n");
1470               RTSflags.GranFlags.debug |= 0x4000; 
1471               break;
1472
1473             case 'P':
1474               fprintf(stderr,"Debug pack buffer handling.\n");
1475               RTSflags.GranFlags.debug |= 0x8000; 
1476               break;
1477
1478             case 's':
1479               fprintf(stderr,"Debug spark-queue manipulations.\n");
1480               RTSflags.GranFlags.debug |= 0x10000; 
1481               break;
1482               
1483             case ':':
1484               fprintf(stderr,"Debug GrAnSim Light.\n");
1485               RTSflags.GranFlags.debug |= 0x20000; 
1486               break;
1487               
1488             case '\0':
1489               RTSflags.GranFlags.debug = 1;
1490               break;
1491
1492             default:
1493               bad_option( rts_argv[arg] );
1494               break;
1495           }
1496           break;
1497 #  endif  /* GRAN_CHECK */
1498       default:
1499         bad_option( rts_argv[arg] );
1500         break;
1501      }
1502 }      
1503 #endif /* GRAN */
1504 \end{code}
1505
1506 %************************************************************************
1507 %*                                                                      *
1508 \subsection{Profiling RTS Arguments}
1509 %*                                                                      *
1510 %************************************************************************
1511
1512 \begin{code}
1513 I_ MaxResidency = 0;     /* in words; for stats only */
1514 I_ ResidencySamples = 0; /* for stats only */
1515
1516 void
1517 initSM(void)
1518 {
1519     RTSflags.GcFlags.minAllocAreaSize
1520       = (I_) (RTSflags.GcFlags.heapSize * RTSflags.GcFlags.pcFreeHeap / 100);
1521     /*
1522         This needs to be here, in case the user changed some of these
1523         values with a "hook".
1524     */
1525 }
1526 \end{code}
1527
1528 %************************************************************************
1529 %*                                                                      *
1530 \subsection{Utility bits}
1531 %*                                                                      *
1532 %************************************************************************
1533
1534 \begin{code}
1535 static FILE *           /* return NULL on error */
1536 open_stats_file (
1537     I_ arg,
1538     int argc, char *argv[],
1539     int rts_argc, char *rts_argv[],
1540     const char *FILENAME_FMT)
1541 {
1542     FILE *f = NULL;
1543
1544     if (strequal(rts_argv[arg]+2, "stderr")) /* use real stderr */
1545         f = stderr;
1546     else if (rts_argv[arg][2] != '\0')      /* stats file specified */
1547         f = fopen(rts_argv[arg]+2,"w");
1548     else {
1549         char stats_filename[STATS_FILENAME_MAXLEN]; /* default <program>.<ext> */
1550         sprintf(stats_filename, FILENAME_FMT, argv[0]);
1551         f = fopen(stats_filename,"w");
1552     }
1553     if (f == NULL) {
1554         fprintf(stderr, "Can't open stats file %s\n", rts_argv[arg]+2);
1555     } else {
1556         /* Write argv and rtsv into start of stats file */
1557         I_ count;
1558         for(count = 0; count < argc; count++)
1559             fprintf(f, "%s ", argv[count]);
1560         fprintf(f, "+RTS ");
1561         for(count = 0; count < rts_argc; count++)
1562             fprintf(f, "%s ", rts_argv[count]);
1563         fprintf(f, "\n");
1564     }
1565
1566     return(f);
1567 }
1568
1569 static I_
1570 decode(const char *s)
1571 {
1572     I_ c;
1573     StgDouble m;
1574
1575     if (!*s)
1576         return 0;
1577
1578     m = atof(s);
1579     c = s[strlen(s)-1];
1580
1581     if (c == 'g' || c == 'G')
1582         m *= 1000*1000*1000;    /* UNchecked! */
1583     else if (c == 'm' || c == 'M')
1584         m *= 1000*1000;                 /* We do not use powers of 2 (1024) */
1585     else if (c == 'k' || c == 'K')      /* to avoid possible bad effects on */
1586         m *= 1000;                      /* a direct-mapped cache.           */ 
1587     else if (c == 'w' || c == 'W')
1588         m *= sizeof(W_);
1589
1590     return (I_)m;
1591 }
1592
1593 static void
1594 bad_option(const char *s)
1595 {
1596   fflush(stdout);
1597   fprintf(stderr, "initSM: Bad RTS option: %s\n", s);
1598   EXIT(EXIT_FAILURE);
1599 }               
1600 \end{code}