[project @ 1997-03-22 08:42:20 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 #if 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                     PAR_BUILD_ONLY(
561                     break; /* we do not care about sortBy for parallel */
562                     )
563                     PROFILING_BUILD_ONLY(
564                     fprintf(stderr, "Invalid profiling sort option %s\n", rts_argv[arg]);
565                     error = rtsTrue;
566                     )
567                 }
568                 ) break;
569
570               case 'i': /* serial profiling -- initial timer interval */
571                 COST_CENTRE_USING_BUILD_ONLY(
572                 interval_ticks = (I_) ((atof(rts_argv[arg]+2) * TICK_FREQUENCY));
573                 if (interval_ticks <= 0)
574                     interval_ticks = 1;
575                 ) break;
576
577               case 'h': /* serial heap profile */
578                 PROFILING_BUILD_ONLY(
579                 switch (rts_argv[arg][2]) {
580                   case '\0':
581                   case CCchar:
582                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_CC;
583                     break;
584                   case MODchar:
585                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
586                     break;
587                   case GRPchar:
588                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_GRP;
589                     break;
590                   case DESCRchar:
591                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
592                     break;
593                   case TYPEchar:
594                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
595                     break;
596                   case TIMEchar:
597                     RTSflags.ProfFlags.doHeapProfile = HEAP_BY_TIME;
598                     if (rts_argv[arg][3]) {
599                         char *start_str = strchr(rts_argv[arg]+3, ',');
600                         I_ intervals;
601                         if (start_str) *start_str = '\0';
602
603                         if ((intervals = decode(rts_argv[arg]+3)) != 0) {
604                             time_intervals = (hash_t) intervals;
605                             /* ToDo: and what if it *is* zero intervals??? */
606                         }
607                         if (start_str) {
608                             earlier_ticks = (I_)((atof(start_str + 1) * TICK_FREQUENCY));
609                         }
610                     }
611                     break;
612                   default:
613                     fprintf(stderr, "Invalid heap profile option: %s\n",
614                             rts_argv[arg]);
615                     error = rtsTrue;
616                 }
617                 ) break;
618
619               case 'z': /* size of index tables */
620                 PROFILING_BUILD_ONLY(
621                 switch (rts_argv[arg][2]) {
622                   case CCchar:
623                     max_cc_no = (hash_t) decode(rts_argv[arg]+3);
624                     if (max_cc_no == 0) {
625                         fprintf(stderr, "Bad number of cost centres %s\n", rts_argv[arg]);
626                         error = rtsTrue;
627                     }
628                     break;
629                   case MODchar:
630                     max_mod_no = (hash_t) decode(rts_argv[arg]+3);
631                     if (max_mod_no == 0) {
632                         fprintf(stderr, "Bad number of modules %s\n", rts_argv[arg]);
633                         error = rtsTrue;
634                     }
635                     break;
636                   case GRPchar:
637                     max_grp_no = (hash_t) decode(rts_argv[arg]+3);
638                     if (max_grp_no == 0) {
639                         fprintf(stderr, "Bad number of groups %s\n", rts_argv[arg]);
640                         error = rtsTrue;
641                     }
642                     break;
643                   case DESCRchar:
644                     max_descr_no = (hash_t) decode(rts_argv[arg]+3);
645                     if (max_descr_no == 0) {
646                         fprintf(stderr, "Bad number of closure descriptions %s\n", rts_argv[arg]);
647                         error = rtsTrue;
648                     }
649                     break;
650                   case TYPEchar:
651                     max_type_no = (hash_t) decode(rts_argv[arg]+3);
652                     if (max_type_no == 0) {
653                         fprintf(stderr, "Bad number of type descriptions %s\n", rts_argv[arg]);
654                         error = rtsTrue;
655                     }
656                     break;
657                   default:
658                     fprintf(stderr, "Invalid index table size option: %s\n",
659                             rts_argv[arg]);
660                     error = rtsTrue;
661                 }
662                 ) break;
663
664               case 'c': /* cost centre label select */
665               case 'm': /* cost centre module select */
666               case 'g': /* cost centre group select */
667               case 'd': /* closure descr select */
668               case 'y': /* closure type select */
669               case 'k': /* closure kind select */
670                 PROFILING_BUILD_ONLY(
671                 {char *left  = strchr(rts_argv[arg], '{');
672                  char *right = strrchr(rts_argv[arg], '}');
673
674                 if (! left || ! right ||
675                         strrchr(rts_argv[arg], '{') != left ||
676                          strchr(rts_argv[arg], '}') != right) {
677                     fprintf(stderr, "Invalid heap profiling selection bracketing\n   %s\n", rts_argv[arg]);
678                     error = rtsTrue;
679                 } else {
680                     *right = '\0';
681                     switch (rts_argv[arg][1]) {
682                       case 'c': /* cost centre label select */
683                         RTSflags.ProfFlags.ccSelector = left + 1;
684                         break;
685                       case 'm': /* cost centre module select */
686                         RTSflags.ProfFlags.modSelector = left + 1;
687                         break;
688                       case 'g': /* cost centre group select */
689                         RTSflags.ProfFlags.grpSelector = left + 1;
690                         break;
691                       case 'd': /* closure descr select */
692                         RTSflags.ProfFlags.descrSelector = left + 1;
693                         break;
694                       case 't': /* closure type select */
695                         RTSflags.ProfFlags.typeSelector = left + 1;
696                         break;
697                       case 'k': /* closure kind select */
698                         RTSflags.ProfFlags.kindSelector = left + 1;
699                         break;
700                     }
701                 }}
702                 ) break;
703
704               /* =========== CONCURRENT ========================= */
705               case 'C': /* context switch interval */
706                 CONCURRENT_BUILD_ONLY (
707                 if (rts_argv[arg][2] == '\0')
708                     RTSflags.ConcFlags.ctxtSwitchTime = 0;
709                 else {
710                     I_ cst; /* tmp */
711
712                     /* Convert to milliseconds */
713                     cst = (I_) ((atof(rts_argv[arg]+2) * 1000));
714                     cst = (cst / CS_MIN_MILLISECS) * CS_MIN_MILLISECS;
715                     if (cst < CS_MIN_MILLISECS)
716                         cst = CS_MIN_MILLISECS;
717
718                     RTSflags.ConcFlags.ctxtSwitchTime = cst;
719                 }
720                 ) break;
721
722               case 't':
723                 CONCURRENT_BUILD_ONLY(
724                 if (rts_argv[arg][2] != '\0') {
725                     RTSflags.ConcFlags.maxThreads
726                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
727                 } else {
728                     fprintf(stderr, "setupRtsFlags: missing size for -t\n");
729                     error = rtsTrue;
730                 }
731                 ) break;
732
733               case 'o':
734                 CONCURRENT_BUILD_ONLY (
735                 if (rts_argv[arg][2] != '\0') {
736                     I_ size = decode(rts_argv[arg]+2);
737
738                     if (size < MIN_STKO_CHUNK_SIZE)
739                         size = MIN_STKO_CHUNK_SIZE;
740
741                     RTSflags.ConcFlags.stkChunkSize = size;
742                 } else {
743                     fprintf(stderr, "setupRtsFlags: missing size for -o\n");
744                     error = rtsTrue;
745                 }
746                 ) break;
747
748               /* =========== PARALLEL =========================== */
749               case 'e':
750                 CONCURRENT_BUILD_ONLY(
751                 if (rts_argv[arg][2] != '\0') { /* otherwise, stick w/ the default */
752
753                     RTSflags.ConcFlags.maxLocalSparks
754                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
755
756                     if (RTSflags.ConcFlags.maxLocalSparks <= 0) {
757                         fprintf(stderr, "setupRtsFlags: bad value for -e\n");
758                         error = rtsTrue;
759                     }
760                 }
761                 ) break;
762
763               case 'O':
764                 PAR_BUILD_ONLY(
765                 RTSflags.ParFlags.outputDisabled = rtsTrue;
766                 ) break;
767
768               case 'q': /* activity profile option */
769                 PAR_BUILD_ONLY(
770                 if (rts_argv[arg][2] == 'b')
771                     RTSflags.ParFlags.granSimStats_Binary = rtsTrue;
772                 else
773                     RTSflags.ParFlags.granSimStats = rtsTrue;
774                 ) break;
775
776 #if 0 /* or??? */
777               case 'q': /* quasi-parallel profile option */
778                 GRAN_BUILD_ONLY (
779                 if (rts_argv[arg][2] == 'v')
780                     do_qp_prof = 2;
781                 else
782                     do_qp_prof++;
783                 ) break;
784 #endif /* 0??? */
785
786               case 'Q': /* Set pack buffer size */
787                 PAR_BUILD_ONLY(
788                 if (rts_argv[arg][2] != '\0') {
789                     RTSflags.ParFlags.packBufferSize = decode(rts_argv[arg]+2);
790                 } else {
791                     fprintf(stderr, "setupRtsFlags: missing size of PackBuffer (for -Q)\n");
792                     error = rtsTrue;
793                 }
794                 ) break;
795
796               /* =========== GRAN =============================== */
797
798               case 'b':
799                 GRAN_BUILD_ONLY(
800                 process_gran_option(arg, rts_argc, rts_argv, &error);
801                 ) break;
802
803               /* =========== TICKY ============================== */
804
805               case 'r': /* Basic profiling stats */
806                 TICKY_BUILD_ONLY(
807
808                 RTSflags.TickyFlags.showTickyStats = rtsTrue;
809                 RTSflags.TickyFlags.tickyFile
810                   = open_stats_file(arg, *argc, argv,
811                         *rts_argc, rts_argv, TICKY_FILENAME_FMT);
812
813                 if (RTSflags.TickyFlags.tickyFile == NULL) error = rtsTrue;
814                 ) break;
815
816               /* =========== OH DEAR ============================ */
817               default:
818                 fprintf(stderr, "setupRtsFlags: Unknown RTS option: %s\n",rts_argv[arg]);
819                 error = rtsTrue;
820                 break;
821             }
822         }
823     }
824     if (error) {
825         const char **p;
826
827         fflush(stdout);
828         for (p = usage_text; *p; p++)
829             fprintf(stderr, "%s\n", *p);
830         EXIT(EXIT_FAILURE);
831     }
832
833 }
834
835 #if defined(GRAN)
836 void
837 enable_GrAnSimLight() {
838
839     fprintf(stderr,"GrAnSim Light enabled (infinite number of processors;  0 communication costs)\n");
840     RTSflags.GranFlags.Light=rtsTrue;
841     RTSflags.GranFlags.gran_latency = 
842         RTSflags.GranFlags.gran_fetchtime = 
843         RTSflags.GranFlags.gran_additional_latency =
844         RTSflags.GranFlags.gran_gunblocktime = 
845         RTSflags.GranFlags.gran_lunblocktime =
846         RTSflags.GranFlags.gran_threadcreatetime = 
847         RTSflags.GranFlags.gran_threadqueuetime =
848         RTSflags.GranFlags.gran_threadscheduletime = 
849         RTSflags.GranFlags.gran_threaddescheduletime =
850         RTSflags.GranFlags.gran_threadcontextswitchtime = 0;
851   
852     RTSflags.GranFlags.gran_mpacktime = 
853         RTSflags.GranFlags.gran_munpacktime = 0;
854
855     RTSflags.GranFlags.DoFairSchedule = rtsTrue;
856     RTSflags.GranFlags.DoReScheduleOnFetch = rtsFalse;
857     RTSflags.GranFlags.DoAlwaysCreateThreads = rtsTrue;
858     /* FetchStrategy is irrelevant in GrAnSim-Light */
859
860     /* GrAnSim Light often creates an abundance of parallel threads,
861        each with its own stack etc. Therefore, it's in general a good
862        idea to use small stack chunks (use the -o<size> option to 
863        increase it again). 
864     */
865     RTSflags.ConcFlags.stkChunkSize = 100;
866
867     RTSflags.GranFlags.proc = 1; 
868 }
869
870 static void
871 process_gran_option(int arg, int *rts_argc, char *rts_argv[], rtsBool *error)
872 {
873     if (rts_argv[arg][1] != 'b') /* All GranSim options start with -b */
874       return;
875
876       /* Should we emulate hbcpp */
877       if(strcmp((rts_argv[arg]+2),"roken")==0) {
878         RTSflags.GranFlags.DoAlwaysCreateThreads=rtsTrue;
879         strcpy(rts_argv[arg]+2,"oring");
880       }
881
882       /* or a ridiculously idealised simulator */
883       if(strcmp((rts_argv[arg]+2),"oring")==0) {
884         RTSflags.GranFlags.gran_latency = 
885         RTSflags.GranFlags.gran_fetchtime = 
886         RTSflags.GranFlags.gran_additional_latency =
887         RTSflags.GranFlags.gran_gunblocktime = 
888         RTSflags.GranFlags.gran_lunblocktime =
889         RTSflags.GranFlags.gran_threadcreatetime = 
890         RTSflags.GranFlags.gran_threadqueuetime =
891         RTSflags.GranFlags.gran_threadscheduletime = 
892         RTSflags.GranFlags.gran_threaddescheduletime =
893         RTSflags.GranFlags.gran_threadcontextswitchtime = 0;
894
895         RTSflags.GranFlags.gran_mpacktime = 
896         RTSflags.GranFlags.gran_munpacktime = 0;
897
898         RTSflags.GranFlags.gran_arith_cost = 
899         RTSflags.GranFlags.gran_float_cost = 
900         RTSflags.GranFlags.gran_load_cost =
901         RTSflags.GranFlags.gran_store_cost = 
902         RTSflags.GranFlags.gran_branch_cost = 0;
903
904         RTSflags.GranFlags.gran_heapalloc_cost = 1;
905
906         /* ++RTSflags.GranFlags.DoFairSchedule; */
907         RTSflags.GranFlags.DoStealThreadsFirst = rtsTrue;         /* -bZ */
908         RTSflags.GranFlags.DoThreadMigration  = rtsTrue;          /* -bM */
909         RTSflags.GranFlags.granSimStats = rtsTrue;                /* -bP */
910         return;
911       }
912
913       /* or a somewhat idealised simulator */
914       if(strcmp((rts_argv[arg]+2),"onzo")==0) {
915         RTSflags.GranFlags.gran_latency = 
916         RTSflags.GranFlags.gran_fetchtime = 
917         RTSflags.GranFlags.gran_additional_latency =
918         RTSflags.GranFlags.gran_gunblocktime = 
919         RTSflags.GranFlags.gran_lunblocktime =
920         RTSflags.GranFlags.gran_threadcreatetime = 
921         RTSflags.GranFlags.gran_threadqueuetime =
922         RTSflags.GranFlags.gran_threadscheduletime = 
923         RTSflags.GranFlags.gran_threaddescheduletime =
924         RTSflags.GranFlags.gran_threadcontextswitchtime = 0;
925
926         RTSflags.GranFlags.gran_mpacktime = 
927         RTSflags.GranFlags.gran_munpacktime = 0;
928         
929         RTSflags.GranFlags.gran_heapalloc_cost = 1;
930
931         /* RTSflags.GranFlags.DoFairSchedule  = rtsTrue; */       /* -b-R */
932         /* RTSflags.GranFlags.DoStealThreadsFirst = rtsTrue; */   /* -b-T */
933         RTSflags.GranFlags.DoReScheduleOnFetch = rtsTrue;         /* -bZ */
934         RTSflags.GranFlags.DoThreadMigration  = rtsTrue;          /* -bM */
935         RTSflags.GranFlags.granSimStats = rtsTrue;                /* -bP */
936 #  if defined(GRAN_CHECK) && defined(GRAN)
937         RTSflags.GranFlags.debug = 0x20;       /* print event statistics   */
938 #  endif
939         return;
940       }
941
942       /* Communication and task creation cost parameters */
943       switch(rts_argv[arg][2]) {
944         case ':':
945           enable_GrAnSimLight();       /* set flags for GrAnSim-Light mode */
946           break;
947
948         case 'l':
949           if (rts_argv[arg][3] != '\0')
950             {
951               RTSflags.GranFlags.gran_gunblocktime = 
952               RTSflags.GranFlags.gran_latency = decode(rts_argv[arg]+3);
953               RTSflags.GranFlags.gran_fetchtime = 2*RTSflags.GranFlags.gran_latency;
954             }
955           else
956             RTSflags.GranFlags.gran_latency = LATENCY;
957           break;
958
959         case 'a':
960           if (rts_argv[arg][3] != '\0')
961             RTSflags.GranFlags.gran_additional_latency = decode(rts_argv[arg]+3);
962           else
963             RTSflags.GranFlags.gran_additional_latency = ADDITIONAL_LATENCY;
964           break;
965
966         case 'm':
967           if (rts_argv[arg][3] != '\0')
968             RTSflags.GranFlags.gran_mpacktime = decode(rts_argv[arg]+3);
969           else
970             RTSflags.GranFlags.gran_mpacktime = MSGPACKTIME;
971           break;
972
973         case 'x':
974           if (rts_argv[arg][3] != '\0')
975             RTSflags.GranFlags.gran_mtidytime = decode(rts_argv[arg]+3);
976           else
977             RTSflags.GranFlags.gran_mtidytime = 0;
978           break;
979
980         case 'r':
981           if (rts_argv[arg][3] != '\0')
982             RTSflags.GranFlags.gran_munpacktime = decode(rts_argv[arg]+3);
983           else
984             RTSflags.GranFlags.gran_munpacktime = MSGUNPACKTIME;
985           break;
986           
987         case 'g':
988           if (rts_argv[arg][3] != '\0')
989             RTSflags.GranFlags.gran_fetchtime = decode(rts_argv[arg]+3);
990           else
991             RTSflags.GranFlags.gran_fetchtime = FETCHTIME;
992           break;
993           
994         case 'n':
995           if (rts_argv[arg][3] != '\0')
996             RTSflags.GranFlags.gran_gunblocktime = decode(rts_argv[arg]+3);
997           else
998             RTSflags.GranFlags.gran_gunblocktime = GLOBALUNBLOCKTIME;
999           break;
1000
1001         case 'u':
1002           if (rts_argv[arg][3] != '\0')
1003             RTSflags.GranFlags.gran_lunblocktime = decode(rts_argv[arg]+3);
1004           else
1005             RTSflags.GranFlags.gran_lunblocktime = LOCALUNBLOCKTIME;
1006           break;
1007
1008         /* Thread-related metrics */
1009         case 't':
1010           if (rts_argv[arg][3] != '\0')
1011             RTSflags.GranFlags.gran_threadcreatetime = decode(rts_argv[arg]+3);
1012           else
1013             RTSflags.GranFlags.gran_threadcreatetime = THREADCREATETIME;
1014           break;
1015           
1016         case 'q':
1017           if (rts_argv[arg][3] != '\0')
1018             RTSflags.GranFlags.gran_threadqueuetime = decode(rts_argv[arg]+3);
1019           else
1020             RTSflags.GranFlags.gran_threadqueuetime = THREADQUEUETIME;
1021           break;
1022           
1023         case 'c':
1024           if (rts_argv[arg][3] != '\0')
1025             RTSflags.GranFlags.gran_threadscheduletime = decode(rts_argv[arg]+3);
1026           else
1027             RTSflags.GranFlags.gran_threadscheduletime = THREADSCHEDULETIME;
1028           
1029           RTSflags.GranFlags.gran_threadcontextswitchtime = RTSflags.GranFlags.gran_threadscheduletime
1030             + RTSflags.GranFlags.gran_threaddescheduletime;
1031           break;
1032
1033         case 'd':
1034           if (rts_argv[arg][3] != '\0')
1035             RTSflags.GranFlags.gran_threaddescheduletime = decode(rts_argv[arg]+3);
1036           else
1037             RTSflags.GranFlags.gran_threaddescheduletime = THREADDESCHEDULETIME;
1038           
1039           RTSflags.GranFlags.gran_threadcontextswitchtime = RTSflags.GranFlags.gran_threadscheduletime
1040             + RTSflags.GranFlags.gran_threaddescheduletime;
1041           break;
1042
1043         /* Instruction Cost Metrics */
1044         case 'A':
1045           if (rts_argv[arg][3] != '\0')
1046             RTSflags.GranFlags.gran_arith_cost = decode(rts_argv[arg]+3);
1047           else
1048             RTSflags.GranFlags.gran_arith_cost = ARITH_COST;
1049           break;
1050
1051         case 'F':
1052           if (rts_argv[arg][3] != '\0')
1053             RTSflags.GranFlags.gran_float_cost = decode(rts_argv[arg]+3);
1054           else
1055             RTSflags.GranFlags.gran_float_cost = FLOAT_COST;
1056           break;
1057                       
1058         case 'B':
1059           if (rts_argv[arg][3] != '\0')
1060             RTSflags.GranFlags.gran_branch_cost = decode(rts_argv[arg]+3);
1061           else
1062             RTSflags.GranFlags.gran_branch_cost = BRANCH_COST;
1063           break;
1064
1065         case 'L':
1066           if (rts_argv[arg][3] != '\0')
1067             RTSflags.GranFlags.gran_load_cost = decode(rts_argv[arg]+3);
1068           else
1069             RTSflags.GranFlags.gran_load_cost = LOAD_COST;
1070           break;
1071           
1072         case 'S':
1073           if (rts_argv[arg][3] != '\0')
1074             RTSflags.GranFlags.gran_store_cost = decode(rts_argv[arg]+3);
1075           else
1076             RTSflags.GranFlags.gran_store_cost = STORE_COST;
1077           break;
1078
1079         case 'H':
1080           if (rts_argv[arg][3] != '\0')
1081             RTSflags.GranFlags.gran_heapalloc_cost = decode(rts_argv[arg]+3);
1082           else
1083             RTSflags.GranFlags.gran_heapalloc_cost = 0;
1084           break;
1085
1086         case 'y':
1087           RTSflags.GranFlags.DoReScheduleOnFetch = rtsTrue;
1088           if (rts_argv[arg][3] != '\0')
1089             RTSflags.GranFlags.FetchStrategy = decode(rts_argv[arg]+3);
1090           if (RTSflags.GranFlags.FetchStrategy == 0)
1091             RTSflags.GranFlags.DoReScheduleOnFetch = rtsFalse;
1092           else
1093             RTSflags.GranFlags.FetchStrategy = 2; /* default: fetch everything */
1094           break;
1095           
1096         case 'K':   /* sort overhead (per elem in spark list) */
1097           if (rts_argv[arg][3] != '\0')
1098             RTSflags.GranFlags.gran_pri_spark_overhead = decode(rts_argv[arg]+3);
1099           else
1100             RTSflags.GranFlags.gran_pri_spark_overhead = PRI_SPARK_OVERHEAD;
1101           fprintf(stderr,"Overhead for pri spark: %d (per elem).\n",
1102                          RTSflags.GranFlags.gran_pri_spark_overhead);
1103           break;
1104
1105         case 'O':  /* sort overhead (per elem in spark list) */
1106           if (rts_argv[arg][3] != '\0')
1107             RTSflags.GranFlags.gran_pri_sched_overhead = decode(rts_argv[arg]+3);
1108           else
1109             RTSflags.GranFlags.gran_pri_sched_overhead = PRI_SCHED_OVERHEAD;
1110           fprintf(stderr,"Overhead for pri sched: %d (per elem).\n",
1111                        RTSflags.GranFlags.gran_pri_sched_overhead);
1112           break;
1113
1114         /* General Parameters */
1115         case 'p':
1116           if (rts_argv[arg][3] != '\0')
1117             {
1118               RTSflags.GranFlags.proc = decode(rts_argv[arg]+3);
1119               if (RTSflags.GranFlags.proc==0) {
1120                   enable_GrAnSimLight(); /* set flags for GrAnSim-Light mode */
1121               } else if (RTSflags.GranFlags.proc > MAX_PROC || 
1122                          RTSflags.GranFlags.proc < 1)
1123                 {
1124                   fprintf(stderr,"setupRtsFlags: no more than %u processors
1125 allowed\n", 
1126                           MAX_PROC);
1127                   *error = rtsTrue;
1128                 }
1129             }
1130           else
1131             RTSflags.GranFlags.proc = MAX_PROC;
1132           break;
1133
1134         case 'f':
1135           if (rts_argv[arg][3] != '\0')
1136             RTSflags.GranFlags.max_fishes = decode(rts_argv[arg]+3);
1137           else
1138             RTSflags.GranFlags.max_fishes = 1;
1139           break;
1140           
1141         case 'w':
1142           if (rts_argv[arg][3] != '\0')
1143             RTSflags.GranFlags.time_slice = decode(rts_argv[arg]+3);
1144           else
1145             RTSflags.GranFlags.time_slice = GRAN_TIME_SLICE;
1146           break;
1147           
1148         case 'C':
1149           RTSflags.GranFlags.DoAlwaysCreateThreads=rtsTrue;
1150           RTSflags.GranFlags.DoThreadMigration=rtsTrue;
1151           break;
1152
1153         case 'G':
1154           fprintf(stderr,"Bulk fetching enabled.\n");
1155           RTSflags.GranFlags.DoGUMMFetching=rtsTrue;
1156           break;
1157           
1158         case 'M':
1159           fprintf(stderr,"Thread migration enabled.\n");
1160           RTSflags.GranFlags.DoThreadMigration=rtsTrue;
1161           break;
1162
1163         case 'R':
1164           fprintf(stderr,"Fair Scheduling enabled.\n");
1165           RTSflags.GranFlags.DoFairSchedule=rtsTrue;
1166           break;
1167           
1168         case 'I':
1169           fprintf(stderr,"Priority Scheduling enabled.\n");
1170           RTSflags.GranFlags.DoPriorityScheduling=rtsTrue;
1171           break;
1172
1173         case 'T':
1174           RTSflags.GranFlags.DoStealThreadsFirst=rtsTrue;
1175           RTSflags.GranFlags.DoThreadMigration=rtsTrue;
1176           break;
1177           
1178         case 'Z':
1179           RTSflags.GranFlags.DoReScheduleOnFetch=rtsTrue;
1180           break;
1181           
1182         case 'z':
1183           RTSflags.GranFlags.SimplifiedFetch=rtsTrue;
1184           break;
1185           
1186         case 'N':
1187           RTSflags.GranFlags.PreferSparksOfLocalNodes=rtsTrue;
1188           break;
1189           
1190         case 'b':
1191           RTSflags.GranFlags.granSimStats_Binary=rtsTrue;
1192           break;
1193           
1194         case 'P':
1195           RTSflags.GranFlags.granSimStats=rtsTrue;
1196           break;
1197
1198         case 's':
1199           RTSflags.GranFlags.granSimStats_Sparks=rtsTrue;
1200           break;
1201
1202         case 'h':
1203           RTSflags.GranFlags.granSimStats_Heap=rtsTrue;
1204           break;
1205
1206         case 'U':
1207           RTSflags.GranFlags.labelling=rtsTrue;
1208           break;
1209
1210         case 'Y':   /* syntax: -bY<n>[,<n>]  n ... pos int */ 
1211           if (rts_argv[arg][3] != '\0') {
1212             char *arg0, *tmp;
1213             
1214             arg0 = rts_argv[arg]+3;
1215             if ((tmp = strstr(arg0,","))==NULL) {
1216               RTSflags.GranFlags.SparkPriority = decode(arg0);
1217               fprintf(stderr,"SparkPriority: %u.\n",RTSflags.GranFlags.SparkPriority);
1218             } else {
1219               *(tmp++) = '\0'; 
1220               RTSflags.GranFlags.SparkPriority = decode(arg0);
1221               RTSflags.GranFlags.SparkPriority2 = decode(tmp);
1222               fprintf(stderr,"SparkPriority: %u.\n",
1223                       RTSflags.GranFlags.SparkPriority);
1224               fprintf(stderr,"SparkPriority2:%u.\n",
1225                       RTSflags.GranFlags.SparkPriority2);
1226               if (RTSflags.GranFlags.SparkPriority2 < 
1227                   RTSflags.GranFlags.SparkPriority) {
1228                 fprintf(stderr,"WARNING: 2nd pri < main pri (%u<%u); 2nd pri has no effect\n",
1229                         RTSflags.GranFlags.SparkPriority2,
1230                         RTSflags.GranFlags.SparkPriority);
1231               }
1232             }
1233           } else {
1234             /* plain pri spark is now invoked with -bX  
1235                RTSflags.GranFlags.DoPrioritySparking = 1;
1236                fprintf(stderr,"PrioritySparking.\n");
1237             */
1238           }
1239           break;
1240
1241         case 'Q':
1242           if (rts_argv[arg][3] != '\0') {
1243             RTSflags.GranFlags.ThunksToPack = decode(rts_argv[arg]+3);
1244           } else {
1245             RTSflags.GranFlags.ThunksToPack = 1;
1246           }
1247           fprintf(stderr,"Thunks To Pack in one packet: %u.\n",
1248                   RTSflags.GranFlags.ThunksToPack);
1249           break;
1250                       
1251         case 'e':
1252           RTSflags.GranFlags.RandomSteal = rtsFalse;
1253           fprintf(stderr,"Deterministic mode (no random stealing)\n");
1254                       break;
1255
1256           /* The following class of options contains eXperimental */
1257           /* features in connection with exploiting granularity */
1258           /* information. I.e. if -bY is chosen these options */
1259           /* tell the RTS what to do with the supplied info --HWL */
1260
1261         case 'W':
1262           if (rts_argv[arg][3] != '\0') {
1263             RTSflags.GranFlags.packBufferSize_internal = decode(rts_argv[arg]+3);
1264           } else {
1265             RTSflags.GranFlags.packBufferSize_internal = GRANSIM_DEFAULT_PACK_BUFFER_SIZE;
1266           }
1267           fprintf(stderr,"Size of GranSim internal pack buffer: %u.\n",
1268                   RTSflags.GranFlags.packBufferSize_internal);
1269           break;
1270                       
1271         case 'X':
1272           switch(rts_argv[arg][3]) {
1273             
1274             case '\0':
1275               RTSflags.GranFlags.DoPrioritySparking = 1;
1276               fprintf(stderr,"Priority Sparking with Normal Priorities.\n");
1277               RTSflags.GranFlags.InversePriorities = rtsFalse; 
1278               RTSflags.GranFlags.RandomPriorities = rtsFalse;
1279               RTSflags.GranFlags.IgnorePriorities = rtsFalse;
1280               break;
1281                         
1282             case 'I':
1283               RTSflags.GranFlags.DoPrioritySparking = 1;
1284               fprintf(stderr,"Priority Sparking with Inverse Priorities.\n");
1285               RTSflags.GranFlags.InversePriorities++; 
1286               break;
1287               
1288             case 'R': 
1289               RTSflags.GranFlags.DoPrioritySparking = 1;
1290               fprintf(stderr,"Priority Sparking with Random Priorities.\n");
1291               RTSflags.GranFlags.RandomPriorities++;
1292               break;
1293               
1294             case 'N':
1295               RTSflags.GranFlags.DoPrioritySparking = 1;
1296               fprintf(stderr,"Priority Sparking with No Priorities.\n");
1297               RTSflags.GranFlags.IgnorePriorities++;
1298               break;
1299               
1300             default:
1301               bad_option( rts_argv[arg] );
1302               break;
1303           }
1304           break;
1305
1306         case '-':
1307           switch(rts_argv[arg][3]) {
1308             
1309             case 'C':
1310               RTSflags.GranFlags.DoAlwaysCreateThreads=rtsFalse;
1311               RTSflags.GranFlags.DoThreadMigration=rtsFalse;
1312               break;
1313
1314             case 'G':
1315               RTSflags.GranFlags.DoGUMMFetching=rtsFalse;
1316               break;
1317               
1318             case 'M':
1319               RTSflags.GranFlags.DoThreadMigration=rtsFalse;
1320               break;
1321
1322             case 'R':
1323               RTSflags.GranFlags.DoFairSchedule=rtsFalse;
1324               break;
1325
1326             case 'T':
1327               RTSflags.GranFlags.DoStealThreadsFirst=rtsFalse;
1328               RTSflags.GranFlags.DoThreadMigration=rtsFalse;
1329               break;
1330
1331             case 'Z':
1332               RTSflags.GranFlags.DoReScheduleOnFetch=rtsFalse;
1333               break;
1334               
1335             case 'N':
1336               RTSflags.GranFlags.PreferSparksOfLocalNodes=rtsFalse;
1337                          break;
1338                          
1339             case 'P':
1340               RTSflags.GranFlags.granSimStats_suppressed=rtsTrue;
1341               break;
1342
1343             case 's':
1344               RTSflags.GranFlags.granSimStats_Sparks=rtsFalse;
1345               break;
1346             
1347             case 'h':
1348               RTSflags.GranFlags.granSimStats_Heap=rtsFalse;
1349               break;
1350             
1351             case 'b':
1352               RTSflags.GranFlags.granSimStats_Binary=rtsFalse;
1353               break;
1354                          
1355             case 'X':
1356               RTSflags.GranFlags.DoPrioritySparking = rtsFalse;
1357               break;
1358
1359             case 'Y':
1360               RTSflags.GranFlags.DoPrioritySparking = rtsFalse;
1361               RTSflags.GranFlags.SparkPriority = rtsFalse;
1362               break;
1363
1364             case 'I':
1365               RTSflags.GranFlags.DoPriorityScheduling = rtsFalse;
1366               break;
1367
1368             case 'e':
1369               RTSflags.GranFlags.RandomSteal = rtsFalse;
1370               break;
1371
1372             default:
1373               bad_option( rts_argv[arg] );
1374               break;
1375           }
1376           break;
1377
1378 #  if defined(GRAN_CHECK) && defined(GRAN)
1379         case 'D':
1380           switch(rts_argv[arg][3]) {
1381             case 'Q':    /* Set pack buffer size (same as 'Q' in GUM) */
1382               if (rts_argv[arg][4] != '\0') {
1383                 RTSflags.GranFlags.packBufferSize = decode(rts_argv[arg]+4);
1384                 fprintf(stderr,"Pack buffer size: %d\n",
1385                         RTSflags.GranFlags.packBufferSize);
1386               } else {
1387                 fprintf(stderr, "setupRtsFlags: missing size of PackBuffer (for -Q)\n");
1388                 error = rtsTrue;
1389               }
1390               break;
1391
1392             case 'e':       /* event trace */
1393               fprintf(stderr,"Printing event trace.\n");
1394               RTSflags.GranFlags.event_trace=rtsTrue;
1395               break;
1396               
1397             case 'f':
1398               fprintf(stderr,"Printing forwarding of FETCHNODES.\n");
1399               RTSflags.GranFlags.debug |= 0x2; /* print fwd messages */
1400               break;
1401
1402             case 'z':
1403               fprintf(stderr,"Check for blocked on fetch.\n");
1404               RTSflags.GranFlags.debug |= 0x4; /* debug non-reschedule-on-fetch */
1405               break;
1406               
1407             case 't':
1408               fprintf(stderr,"Check for TSO asleep on fetch.\n");
1409               RTSflags.GranFlags.debug |= 0x10; /* debug TSO asleep for fetch  */
1410               break;
1411
1412             case 'E':
1413               fprintf(stderr,"Printing event statistics.\n");
1414               RTSflags.GranFlags.debug |= 0x20; /* print event statistics   */
1415               break;
1416               
1417             case 'F':
1418               fprintf(stderr,"Prohibiting forward.\n");
1419               RTSflags.GranFlags.NoForward = rtsTrue; /* prohibit forwarding   */
1420               break;
1421               
1422             case 'm':
1423               fprintf(stderr,"Printing fetch misses.\n");
1424               RTSflags.GranFlags.PrintFetchMisses = rtsTrue; /* prohibit forwarding   */
1425               break;
1426
1427             case 'd':
1428               fprintf(stderr,"Debug mode.\n");
1429               RTSflags.GranFlags.debug |= 0x40; 
1430                             break;
1431
1432             case 'D':
1433               fprintf(stderr,"Severe debug mode.\n");
1434               RTSflags.GranFlags.debug |= 0x80; 
1435               break;
1436               
1437             case 'q':
1438               fprintf(stderr,"FULL event trace.\n");
1439               RTSflags.GranFlags.event_trace_all =rtsTrue;
1440               break;
1441
1442             case 'G':
1443               fprintf(stderr,"Debugging packet fetching.\n");
1444               RTSflags.GranFlags.debug |= 0x100; 
1445               break;
1446               
1447             case 'n':
1448               fprintf(stderr,"Ignore events till end of time slice\n");
1449               RTSflags.GranFlags.debug |= 0x200; 
1450               IgnoreEvents = rtsTrue;
1451               break;
1452
1453             case 'S':
1454               fprintf(stderr,"Check that spark queues are sorted.\n");
1455               RTSflags.GranFlags.debug |= 0x400; 
1456               break;
1457
1458             case 'H':
1459               fprintf(stderr,"Print heap allocation messages (RBH).\n");
1460               RTSflags.GranFlags.debug |= 0x800; 
1461               break;
1462
1463             case 'p':
1464               fprintf(stderr,"Debug breadth-first pruning.\n");
1465               RTSflags.GranFlags.debug |= 0x1000; 
1466               break;
1467               
1468             case 'r':
1469               fprintf(stderr,"Debug random stealing.\n");
1470               RTSflags.GranFlags.debug |= 0x2000; 
1471               break;
1472
1473             case 'B':
1474               fprintf(stderr,"Debug busyness.\n");
1475               RTSflags.GranFlags.debug |= 0x4000; 
1476               break;
1477
1478             case 'P':
1479               fprintf(stderr,"Debug pack buffer handling.\n");
1480               RTSflags.GranFlags.debug |= 0x8000; 
1481               break;
1482
1483             case 's':
1484               fprintf(stderr,"Debug spark-queue manipulations.\n");
1485               RTSflags.GranFlags.debug |= 0x10000; 
1486               break;
1487               
1488             case ':':
1489               fprintf(stderr,"Debug GrAnSim Light.\n");
1490               RTSflags.GranFlags.debug |= 0x20000; 
1491               break;
1492               
1493             case '\0':
1494               RTSflags.GranFlags.debug = 1;
1495               break;
1496
1497             default:
1498               bad_option( rts_argv[arg] );
1499               break;
1500           }
1501           break;
1502 #  endif  /* GRAN_CHECK */
1503       default:
1504         bad_option( rts_argv[arg] );
1505         break;
1506      }
1507 }      
1508 #endif /* GRAN */
1509 \end{code}
1510
1511 %************************************************************************
1512 %*                                                                      *
1513 \subsection{Profiling RTS Arguments}
1514 %*                                                                      *
1515 %************************************************************************
1516
1517 \begin{code}
1518 I_ MaxResidency = 0;     /* in words; for stats only */
1519 I_ ResidencySamples = 0; /* for stats only */
1520
1521 void
1522 initSM(void)
1523 {
1524     RTSflags.GcFlags.minAllocAreaSize
1525       = (I_) (RTSflags.GcFlags.heapSize * RTSflags.GcFlags.pcFreeHeap / 100);
1526     /*
1527         This needs to be here, in case the user changed some of these
1528         values with a "hook".
1529     */
1530 }
1531 \end{code}
1532
1533 %************************************************************************
1534 %*                                                                      *
1535 \subsection{Utility bits}
1536 %*                                                                      *
1537 %************************************************************************
1538
1539 \begin{code}
1540 static FILE *           /* return NULL on error */
1541 open_stats_file (
1542     I_ arg,
1543     int argc, char *argv[],
1544     int rts_argc, char *rts_argv[],
1545     const char *FILENAME_FMT)
1546 {
1547     FILE *f = NULL;
1548
1549     if (strequal(rts_argv[arg]+2, "stderr")) /* use real stderr */
1550         f = stderr;
1551     else if (rts_argv[arg][2] != '\0')      /* stats file specified */
1552         f = fopen(rts_argv[arg]+2,"w");
1553     else {
1554         char stats_filename[STATS_FILENAME_MAXLEN]; /* default <program>.<ext> */
1555         sprintf(stats_filename, FILENAME_FMT, argv[0]);
1556         f = fopen(stats_filename,"w");
1557     }
1558     if (f == NULL) {
1559         fprintf(stderr, "Can't open stats file %s\n", rts_argv[arg]+2);
1560     } else {
1561         /* Write argv and rtsv into start of stats file */
1562         I_ count;
1563         for(count = 0; count < argc; count++)
1564             fprintf(f, "%s ", argv[count]);
1565         fprintf(f, "+RTS ");
1566         for(count = 0; count < rts_argc; count++)
1567             fprintf(f, "%s ", rts_argv[count]);
1568         fprintf(f, "\n");
1569     }
1570
1571     return(f);
1572 }
1573
1574 static I_
1575 decode(const char *s)
1576 {
1577     I_ c;
1578     StgDouble m;
1579
1580     if (!*s)
1581         return 0;
1582
1583     m = atof(s);
1584     c = s[strlen(s)-1];
1585
1586     if (c == 'g' || c == 'G')
1587         m *= 1000*1000*1000;    /* UNchecked! */
1588     else if (c == 'm' || c == 'M')
1589         m *= 1000*1000;                 /* We do not use powers of 2 (1024) */
1590     else if (c == 'k' || c == 'K')      /* to avoid possible bad effects on */
1591         m *= 1000;                      /* a direct-mapped cache.           */ 
1592     else if (c == 'w' || c == 'W')
1593         m *= sizeof(W_);
1594
1595     return (I_)m;
1596 }
1597
1598 static void
1599 bad_option(const char *s)
1600 {
1601   fflush(stdout);
1602   fprintf(stderr, "initSM: Bad RTS option: %s\n", s);
1603   EXIT(EXIT_FAILURE);
1604 }               
1605 \end{code}