[project @ 1999-09-13 08:14:00 by simonmar]
[ghc-hetmet.git] / ghc / rts / RtsFlags.c
1 /* -----------------------------------------------------------------------------
2  * $Id: RtsFlags.c,v 1.17 1999/09/13 08:14:00 simonmar Exp $
3  *
4  * (c) The AQUA Project, Glasgow University, 1994-1997
5  * (c) The GHC Team, 1998-1999
6  *
7  * Functions for parsing the argument list.
8  *
9  * ---------------------------------------------------------------------------*/
10
11 #include "Rts.h"
12 #include "RtsFlags.h"
13 #include "RtsUtils.h"
14 #include "BlockAlloc.h"
15 #include "ProfRts.h"
16 #include "Itimer.h"
17
18 #if defined(PROFILING) 
19 #include "Itimer.h"
20 #endif
21
22 #if HAVE_STDLIB_H
23 #include <stdlib.h>
24 #endif
25
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #endif
29
30 extern struct RTS_FLAGS RtsFlags;
31
32 /*
33  * Split argument lists
34  */
35 int     prog_argc; /* an "int" so as to match normal "argc" */
36 char  **prog_argv = NULL;
37 int     rts_argc;  /* ditto */
38 char   *rts_argv[MAX_RTS_ARGS];
39
40 /*
41  * constants, used later 
42  */
43 #define RTS 1
44 #define PGM 0
45
46 /* -----------------------------------------------------------------------------
47    Static function decls
48    -------------------------------------------------------------------------- */
49
50 static FILE *           /* return NULL on error */
51 open_stats_file (
52     I_ arg,
53     int argc, char *argv[],
54     int rts_argc, char *rts_argv[],
55     const char *FILENAME_FMT);
56
57 static I_ decode(const char *s);
58 static void bad_option(const char *s);
59
60 /* -----------------------------------------------------------------------------
61  * Command-line option parsing routines.
62  * ---------------------------------------------------------------------------*/
63
64 void initRtsFlagsDefaults(void)
65 {
66     RtsFlags.GcFlags.statsFile          = NULL;
67     RtsFlags.GcFlags.giveStats          = NO_GC_STATS;
68
69     RtsFlags.GcFlags.maxStkSize         = (1024 * 1024) / sizeof(W_);
70     RtsFlags.GcFlags.initialStkSize     = 1024 / sizeof(W_);
71
72     RtsFlags.GcFlags.minAllocAreaSize   = (256 * 1024)        / BLOCK_SIZE;
73     RtsFlags.GcFlags.minOldGenSize      = (1024 * 1024)       / BLOCK_SIZE;
74     RtsFlags.GcFlags.maxHeapSize        = (64  * 1024 * 1024) / BLOCK_SIZE;
75     RtsFlags.GcFlags.heapSizeSuggestion = 0;    /* none */
76     RtsFlags.GcFlags.pcFreeHeap         = 3;    /* 3% */
77     RtsFlags.GcFlags.oldGenFactor       = 2;
78     RtsFlags.GcFlags.generations        = 2;
79     RtsFlags.GcFlags.steps              = 2;
80
81     RtsFlags.GcFlags.forceGC            = rtsFalse;
82     RtsFlags.GcFlags.forcingInterval    = 5000000; /* 5MB (or words?) */
83     RtsFlags.GcFlags.ringBell           = rtsFalse;
84
85     RtsFlags.GcFlags.squeezeUpdFrames   = rtsTrue;
86
87 #if defined(PROFILING) || defined(PAR)
88     RtsFlags.CcFlags.doCostCentres      = 0;
89     RtsFlags.CcFlags.sortBy             = SORTCC_TIME;
90 #endif /* PROFILING or PAR */
91
92 #ifdef PROFILING
93     RtsFlags.ProfFlags.doHeapProfile = rtsFalse;
94
95     RtsFlags.ProfFlags.ccSelector    = NULL;
96     RtsFlags.ProfFlags.modSelector   = NULL;
97     RtsFlags.ProfFlags.grpSelector   = NULL;
98     RtsFlags.ProfFlags.descrSelector = NULL;
99     RtsFlags.ProfFlags.typeSelector  = NULL;
100     RtsFlags.ProfFlags.kindSelector  = NULL;
101 #elif defined(DEBUG)
102     RtsFlags.ProfFlags.doHeapProfile = rtsFalse;
103 #endif
104
105     RtsFlags.ConcFlags.ctxtSwitchTime   = CS_MIN_MILLISECS;  /* In milliseconds */
106 #ifdef PAR
107     RtsFlags.ParFlags.parallelStats     = rtsFalse;
108     RtsFlags.ParFlags.granSimStats      = rtsFalse;
109     RtsFlags.ParFlags.granSimStats_Binary = rtsFalse;
110
111     RtsFlags.ParFlags.outputDisabled    = rtsFalse;
112
113     RtsFlags.ParFlags.packBufferSize    = 1024;
114     RtsFlags.ParFlags.maxLocalSparks    = 4096;
115 #endif /* PAR */
116
117 #ifdef GRAN
118     RtsFlags.GranFlags.granSimStats     = rtsFalse;
119     RtsFlags.GranFlags.granSimStats_suppressed  = rtsFalse;
120     RtsFlags.GranFlags.granSimStats_Binary = rtsFalse;
121     RtsFlags.GranFlags.granSimStats_Sparks = rtsFalse;
122     RtsFlags.GranFlags.granSimStats_Heap = rtsFalse;
123     RtsFlags.GranFlags.labelling        = rtsFalse;
124     RtsFlags.GranFlags.packBufferSize   = 1024;
125     RtsFlags.GranFlags.packBufferSize_internal = GRANSIM_DEFAULT_PACK_BUFFER_SIZE;
126
127     RtsFlags.GranFlags.proc  = MAX_PROC;
128     RtsFlags.GranFlags.max_fishes = MAX_FISHES;
129     RtsFlags.GranFlags.time_slice = GRAN_TIME_SLICE;
130     RtsFlags.GranFlags.Light = rtsFalse;
131
132     RtsFlags.GranFlags.gran_latency =             LATENCY;          
133     RtsFlags.GranFlags.gran_additional_latency =  ADDITIONAL_LATENCY; 
134     RtsFlags.GranFlags.gran_fetchtime =           FETCHTIME; 
135     RtsFlags.GranFlags.gran_lunblocktime =        LOCALUNBLOCKTIME; 
136     RtsFlags.GranFlags.gran_gunblocktime =        GLOBALUNBLOCKTIME;
137     RtsFlags.GranFlags.gran_mpacktime =           MSGPACKTIME;      
138     RtsFlags.GranFlags.gran_munpacktime =         MSGUNPACKTIME;
139     RtsFlags.GranFlags.gran_mtidytime =           MSGTIDYTIME;
140
141     RtsFlags.GranFlags.gran_threadcreatetime =         THREADCREATETIME;
142     RtsFlags.GranFlags.gran_threadqueuetime =          THREADQUEUETIME;
143     RtsFlags.GranFlags.gran_threaddescheduletime =     THREADDESCHEDULETIME;
144     RtsFlags.GranFlags.gran_threadscheduletime =       THREADSCHEDULETIME;
145     RtsFlags.GranFlags.gran_threadcontextswitchtime =  THREADCONTEXTSWITCHTIME;
146
147     RtsFlags.GranFlags.gran_arith_cost =         ARITH_COST;       
148     RtsFlags.GranFlags.gran_branch_cost =        BRANCH_COST; 
149     RtsFlags.GranFlags.gran_load_cost =          LOAD_COST;        
150     RtsFlags.GranFlags.gran_store_cost =         STORE_COST; 
151     RtsFlags.GranFlags.gran_float_cost =         FLOAT_COST;       
152
153     RtsFlags.GranFlags.gran_heapalloc_cost =     HEAPALLOC_COST;
154
155     RtsFlags.GranFlags.gran_pri_spark_overhead = PRI_SPARK_OVERHEAD;        
156     RtsFlags.GranFlags.gran_pri_sched_overhead = PRI_SCHED_OVERHEAD;        
157
158     RtsFlags.GranFlags.DoFairSchedule = rtsFalse;             
159     RtsFlags.GranFlags.DoReScheduleOnFetch = rtsFalse;        
160     RtsFlags.GranFlags.DoStealThreadsFirst = rtsFalse;        
161     RtsFlags.GranFlags.SimplifiedFetch = rtsFalse;            
162     RtsFlags.GranFlags.DoAlwaysCreateThreads = rtsFalse;      
163     RtsFlags.GranFlags.DoGUMMFetching = rtsFalse;             
164     RtsFlags.GranFlags.DoThreadMigration = rtsFalse;          
165     RtsFlags.GranFlags.FetchStrategy = 2;                     
166     RtsFlags.GranFlags.PreferSparksOfLocalNodes = rtsFalse;   
167     RtsFlags.GranFlags.DoPrioritySparking = rtsFalse;         
168     RtsFlags.GranFlags.DoPriorityScheduling = rtsFalse;       
169     RtsFlags.GranFlags.SparkPriority = 0;
170     RtsFlags.GranFlags.SparkPriority2 = 0; 
171     RtsFlags.GranFlags.RandomPriorities = rtsFalse;           
172     RtsFlags.GranFlags.InversePriorities = rtsFalse;          
173     RtsFlags.GranFlags.IgnorePriorities = rtsFalse;           
174     RtsFlags.GranFlags.ThunksToPack = 0;                      
175     RtsFlags.GranFlags.RandomSteal = rtsTrue;
176     RtsFlags.GranFlags.NoForward = rtsFalse;
177     RtsFlags.GranFlags.PrintFetchMisses = rtsFalse;
178
179     RtsFlags.GranFlags.debug = 0x0;
180     RtsFlags.GranFlags.event_trace = rtsFalse;
181     RtsFlags.GranFlags.event_trace_all = rtsFalse;
182 #endif
183
184 #ifdef TICKY_TICKY
185     RtsFlags.TickyFlags.showTickyStats   = rtsFalse;
186     RtsFlags.TickyFlags.tickyFile        = NULL;
187 #endif
188 }
189
190 static const char *
191 usage_text[] = {
192 "",
193 "Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
194 "",
195 "   +RTS    Indicates run time system options follow",
196 "   -RTS    Indicates program arguments follow",
197 "  --RTS    Indicates that ALL subsequent arguments will be given to the",
198 "           program (including any of these RTS flags)",
199 "",
200 "The following run time system options are available:",
201 "",
202 "  -? -f    Prints this message and exits; the program is not executed",
203 "",
204 "  -K<size> Sets the maximum stack size (default 1M)  Egs: -K32k   -K512k",
205 "  -k<size> Sets the initial thread stack size (default 1k)  Egs: -K4k   -K2m",
206 "",
207 "  -A<size> Sets the minimum allocation area size (default 256k) Egs: -A1m -A10k",
208 "  -M<size> Sets the maximum heap size (default 64M)  Egs: -M256k -M1G",
209 "  -H<size> Sets the minimum heap size (default 0M)   Egs: -H24m  -H1G",
210 "  -m<n>%   Minimum % of heap which must be available (default 3%)",
211 "  -G<n>    Number of generations (default: 2)",
212 "  -T<n>    Number of steps in younger generations (default: 2)",
213 "  -s<file> Summary GC statistics   (default file: <program>.stat)",
214 "  -S<file> Detailed GC statistics  (with -Sstderr going to stderr)",
215 "",
216 "",
217 "  -Z       Don't squeeze out update frames on stack overflow",
218 "  -B       Sound the bell at the start of each garbage collection",
219 #if defined(PROFILING) || defined(PAR)
220 "",
221 "  -p<sort> Produce cost centre time profile  (output file <program>.prof)",
222 "             sort: T = time (default), A = alloc, C = cost centre label",
223 "  -P<sort> Produce serial time profile (output file <program>.time)",
224 "             and a -p profile with detailed tick/alloc info",
225 # if defined(PROFILING)
226 "",
227 "  -h<break-down> Heap residency profile      (output file <program>.hp)",
228 "     break-down: C = cost centre (default), M = module, G = group",
229 "                 D = closure description, Y = type description",
230 "                 T<ints>,<start> = time closure created",
231 "                    ints:  no. of interval bands plotted (default 18)",
232 "                    start: seconds after which intervals start (default 0.0)",
233 "  A subset of closures may be selected by the attached cost centre using:",
234 "    -c{mod:lab,mod:lab...}, specific module:label cost centre(s)",
235 "    -m{mod,mod...} all cost centres from the specified modules(s)",
236 "    -g{grp,grp...} all cost centres from the specified group(s)",
237 "  Selections can also be made by description, type, kind and age:",
238 "    -d{des,des...} closures with specified closure descriptions",
239 "    -y{typ,typ...} closures with specified type descriptions",
240 "    -k{knd,knd...} closures of the specified kinds",
241 "    -a<age>        closures which survived <age> complete intervals",
242 "  The selection logic used is summarised as follows:",
243 "    ([-c] or [-m] or [-g]) and ([-d] or [-y] or [-k]) and [-a]",
244 "    where an option is true if not specified",
245 # endif
246 "",
247 "  -z<tbl><size>  set hash table <size> for <tbl> (C, M, G, D or Y)",
248 "",
249 "  -i<secs> Number of seconds in a profiling interval (default 1.0):",
250 "           heap profile (-h) and/or serial time profile (-P) frequency",
251 #endif /* PROFILING or PAR */
252 #if !defined(PROFILING) && defined(DEBUG)
253 "",
254 "  -h<break-down> Debugging Heap residency profile",
255 "                 (output file <program>.hp)",
256 "     break-down: L = closure label (default)",
257 "                 T = closure type (constructor, thunk etc.)",
258 #endif
259 "",
260 #if defined(TICKY_TICKY)
261 "  -r<file>  Produce reduction profiling statistics (with -rstderr for stderr)",
262 "",
263 #endif
264 # ifdef PAR
265 "  -N<n>     Use <n> PVMish processors in parallel (default: 2)",
266 /* NB: the -N<n> is implemented by the driver!! */
267 # endif
268 "  -C<secs>  Context-switch interval in seconds",
269 "                (0 or no argument means switch as often as possible)",
270 "                the default is .01 sec; resolution is .01 sec",
271 # ifdef PAR
272 "  -q        Enable activity profile (output files in ~/<program>*.gr)",
273 "  -qb       Enable binary activity profile (output file /tmp/<program>.gb)",
274 "  -Q<size>  Set pack-buffer size (default: 1024)",
275 # endif
276 # ifdef PAR
277 "  -d        Turn on PVM-ish debugging",
278 "  -O        Disable output for performance measurement",
279 # endif /* PAR */
280 # ifdef GRAN  /* ToDo: fill in decent Docu here */
281 "  -b...     All GranSim options start with -b; see GranSim User's Guide for details",
282 # endif
283 "",
284 "Other RTS options may be available for programs compiled a different way.",
285 "The GHC User's Guide has full details.",
286 "",
287 0
288 };
289
290 static __inline__ rtsBool
291 strequal(const char *a, const char * b)
292 {
293     return(strcmp(a, b) == 0);
294 }
295
296 void
297 setupRtsFlags(int *argc, char *argv[], int *rts_argc, char *rts_argv[])
298 {
299     rtsBool error = rtsFalse;
300     I_ mode;
301     I_ arg, total_arg;
302     char *last_slash;
303
304     /* Remove directory from argv[0] -- default files in current directory */
305
306     if ((last_slash = (char *) strrchr(argv[0], '/')) != NULL)
307         strcpy(argv[0], last_slash+1);
308
309     /* Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts */
310     /*   argv[0] must be PGM argument -- leave in argv                 */
311
312     total_arg = *argc;
313     arg = 1;
314
315     *argc = 1;
316     *rts_argc = 0;
317
318     for (mode = PGM; arg < total_arg && ! strequal("--RTS", argv[arg]); arg++) {
319         if (strequal("+RTS", argv[arg])) {
320             mode = RTS;
321         }
322         else if (strequal("-RTS", argv[arg])) {
323             mode = PGM;
324         }
325         else if (mode == RTS && *rts_argc < MAX_RTS_ARGS-1) {
326             rts_argv[(*rts_argc)++] = argv[arg];
327         }
328         else if (mode == PGM) {
329             argv[(*argc)++] = argv[arg];
330         }
331         else {
332           barf("too many RTS arguments (max %d)", MAX_RTS_ARGS-1);
333         }
334     }
335     if (arg < total_arg) {
336         /* arg must be --RTS; process remaining program arguments */
337         while (++arg < total_arg) {
338             argv[(*argc)++] = argv[arg];
339         }
340     }
341     argv[*argc] = (char *) 0;
342     rts_argv[*rts_argc] = (char *) 0;
343
344     /* Process RTS (rts_argv) part: mainly to determine statsfile */
345
346     for (arg = 0; arg < *rts_argc; arg++) {
347         if (rts_argv[arg][0] != '-') {
348             fflush(stdout);
349             fprintf(stderr, "setupRtsFlags: Unexpected RTS argument: %s\n",
350                     rts_argv[arg]);
351             error = rtsTrue;
352
353         } else {
354             switch(rts_argv[arg][1]) {
355
356               /* process: general args, then PROFILING-only ones,
357                  then CONCURRENT-only, PARallel-only, GRAN-only,
358                  TICKY-only (same order as defined in RtsFlags.lh);
359                  within those groups, mostly in case-insensitive
360                  alphabetical order.
361               */
362
363 #ifdef TICKY_TICKY
364 # define TICKY_BUILD_ONLY(x) x
365 #else
366 # define TICKY_BUILD_ONLY(x) \
367 fprintf(stderr, "setupRtsFlags: GHC not built for: ticky-ticky stats\n"); \
368 error = rtsTrue;
369 #endif
370
371 #if defined(PROFILING) 
372 # define COST_CENTRE_USING_BUILD_ONLY(x) x
373 #else
374 # define COST_CENTRE_USING_BUILD_ONLY(x) \
375 fprintf(stderr, "setupRtsFlags: GHC not built for: -prof or -parallel\n"); \
376 error = rtsTrue;
377 #endif
378
379 #ifdef PROFILING
380 # define PROFILING_BUILD_ONLY(x)   x
381 #else
382 # define PROFILING_BUILD_ONLY(x) \
383 fprintf(stderr, "setupRtsFlags: GHC not built for: -prof\n"); \
384 error = rtsTrue;
385 #endif
386
387 #ifdef PAR
388 # define PAR_BUILD_ONLY(x)      x
389 #else
390 # define PAR_BUILD_ONLY(x) \
391 fprintf(stderr, "setupRtsFlags: GHC not built for: -parallel\n"); \
392 error = rtsTrue;
393 #endif
394
395 #ifdef GRAN
396 # define GRAN_BUILD_ONLY(x)     x
397 #else
398 # define GRAN_BUILD_ONLY(x) \
399 fprintf(stderr, "setupRtsFlags: GHC not built for: -gransim\n"); \
400 error = rtsTrue;
401 #endif
402
403               /* =========== GENERAL ========================== */
404               case '?':
405               case 'f':
406                 error = rtsTrue;
407                 break;
408
409               case 'A':
410                 RtsFlags.GcFlags.minAllocAreaSize
411                   = decode(rts_argv[arg]+2) / BLOCK_SIZE;
412                 if (RtsFlags.GcFlags.minAllocAreaSize <= 0) {
413                   bad_option(rts_argv[arg]);
414                 }
415                 break;
416
417               case 'B':
418                 RtsFlags.GcFlags.ringBell = rtsTrue;
419                 break;
420
421               case 'F':
422                 RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
423               
424                 if (RtsFlags.GcFlags.oldGenFactor < 0)
425                   bad_option( rts_argv[arg] );
426                 break;
427               
428 #ifdef DEBUG
429               case 'D':
430                 /* hack warning: interpret the flags as a binary number */
431                 { 
432                    I_ n = decode(rts_argv[arg]+2);
433                    if (n     &1) RtsFlags.DebugFlags.scheduler   = rtsTrue;
434                    if ((n>>1)&1) RtsFlags.DebugFlags.evaluator   = rtsTrue;
435                    if ((n>>2)&1) RtsFlags.DebugFlags.codegen     = rtsTrue;
436                    if ((n>>3)&1) RtsFlags.DebugFlags.weak        = rtsTrue;
437                    if ((n>>4)&1) RtsFlags.DebugFlags.gccafs      = rtsTrue;
438                    if ((n>>5)&1) RtsFlags.DebugFlags.gc          = rtsTrue;
439                    if ((n>>6)&1) RtsFlags.DebugFlags.block_alloc = rtsTrue;
440                    if ((n>>7)&1) RtsFlags.DebugFlags.sanity      = rtsTrue;
441                    if ((n>>8)&1) RtsFlags.DebugFlags.stable      = rtsTrue;
442                    if ((n>>9)&1) RtsFlags.DebugFlags.prof        = rtsTrue;
443                 }
444                 break;
445 #endif
446
447               case 'K':
448                 RtsFlags.GcFlags.maxStkSize = 
449                   decode(rts_argv[arg]+2) / sizeof(W_);
450
451                 if (RtsFlags.GcFlags.maxStkSize == 0) 
452                   bad_option( rts_argv[arg] );
453                 break;
454
455               case 'k':
456                 RtsFlags.GcFlags.initialStkSize = 
457                   decode(rts_argv[arg]+2) / sizeof(W_);
458
459                 if (RtsFlags.GcFlags.initialStkSize == 0) 
460                   bad_option( rts_argv[arg] );
461                 break;
462
463               case 'M':
464                 RtsFlags.GcFlags.maxHeapSize = 
465                   decode(rts_argv[arg]+2) / BLOCK_SIZE;
466                 /* user give size in *bytes* but "maxHeapSize" is in *blocks* */
467
468                 if (RtsFlags.GcFlags.maxHeapSize <= 0) {
469                   bad_option(rts_argv[arg]);
470                 }
471                 break;
472
473               case 'm':
474                 RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
475
476                 if (RtsFlags.GcFlags.pcFreeHeap < 0 || 
477                     RtsFlags.GcFlags.pcFreeHeap > 100)
478                   bad_option( rts_argv[arg] );
479                 break;
480
481               case 'G':
482                 RtsFlags.GcFlags.generations = decode(rts_argv[arg]+2);
483                 if (RtsFlags.GcFlags.generations < 1) {
484                   bad_option(rts_argv[arg]);
485                 }
486                 break;
487
488               case 'T':
489                 RtsFlags.GcFlags.steps = decode(rts_argv[arg]+2);
490                 if (RtsFlags.GcFlags.steps < 1) {
491                   bad_option(rts_argv[arg]);
492                 }
493                 break;
494
495               case 'H':
496                 RtsFlags.GcFlags.heapSizeSuggestion = 
497                   decode(rts_argv[arg]+2) / BLOCK_SIZE;
498
499                 if (RtsFlags.GcFlags.heapSizeSuggestion <= 0) {
500                   bad_option(rts_argv[arg]);
501                 }
502                 break;
503
504               case 'j': /* force GC option */
505                 RtsFlags.GcFlags.forceGC = rtsTrue;
506                 if (rts_argv[arg][2]) {
507                     RtsFlags.GcFlags.forcingInterval
508                         = decode(rts_argv[arg]+2) / sizeof(W_);
509                 }
510                 break;
511
512               case 'S':
513                 RtsFlags.GcFlags.giveStats ++;
514
515               case 's':
516                 RtsFlags.GcFlags.giveStats ++;
517 #ifdef PAR
518                 /* Opening all those files would almost certainly fail... */
519                 RtsFlags.ParFlags.parallelStats = rtsTrue;
520                 RtsFlags.GcFlags.statsFile = stderr; /* temporary; ToDo: rm */
521 #else
522                 RtsFlags.GcFlags.statsFile
523                   = open_stats_file(arg, *argc, argv,
524                         *rts_argc, rts_argv, STAT_FILENAME_FMT);
525
526                 if (RtsFlags.GcFlags.statsFile == NULL) error = rtsTrue;
527 #endif
528                 break;
529
530               case 'Z':
531                 RtsFlags.GcFlags.squeezeUpdFrames = rtsFalse;
532                 break;
533
534               /* =========== PROFILING ========================== */
535
536               case 'P': /* detailed cost centre profiling (time/alloc) */
537                 COST_CENTRE_USING_BUILD_ONLY(
538                 RtsFlags.CcFlags.doCostCentres++;
539                 )
540               case 'p': /* cost centre profiling (time/alloc) */
541                 COST_CENTRE_USING_BUILD_ONLY(
542                 RtsFlags.CcFlags.doCostCentres++;
543
544                 switch (rts_argv[arg][2]) {
545                   case SORTCC_LABEL:
546                   case SORTCC_TIME:
547                   case SORTCC_ALLOC:
548                         RtsFlags.CcFlags.sortBy = rts_argv[arg][2];
549                     break;
550                   default:
551                         RtsFlags.CcFlags.sortBy = SORTCC_TIME;
552                     break;
553                 }
554                 ) break;
555
556               case 'i': /* serial profiling -- initial timer interval */
557                 COST_CENTRE_USING_BUILD_ONLY(
558                 interval_ticks = (I_) ((atof(rts_argv[arg]+2) * TICK_FREQUENCY));
559                 if (interval_ticks <= 0)
560                     interval_ticks = 1;
561                 ) break;
562
563               case 'h': /* serial heap profile */
564 #if !defined(PROFILING) && defined(DEBUG)
565                 switch (rts_argv[arg][2]) {
566                   case '\0':
567                   case 'L':
568                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_INFOPTR;
569                     break;
570                   case 'T':
571                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
572                     break;
573                   default:
574                     fprintf(stderr, "Invalid heap profile option: %s\n",
575                             rts_argv[arg]);
576                     error = rtsTrue;
577                 }
578 #else
579                 PROFILING_BUILD_ONLY(
580                 switch (rts_argv[arg][2]) {
581                   case '\0':
582                   case CCchar:
583                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CC;
584                     break;
585                   case MODchar:
586                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
587                     break;
588                   case GRPchar:
589                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_GRP;
590                     break;
591                   case DESCRchar:
592                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
593                     break;
594                   case TYPEchar:
595                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
596                     break;
597                   case TIMEchar:
598                     RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TIME;
599                     if (rts_argv[arg][3]) {
600                         char *start_str = strchr(rts_argv[arg]+3, ',');
601                         I_ intervals;
602                         if (start_str) *start_str = '\0';
603
604                         if ((intervals = decode(rts_argv[arg]+3)) != 0) {
605                             time_intervals = (hash_t) intervals;
606                             /* ToDo: and what if it *is* zero intervals??? */
607                         }
608                         if (start_str) {
609                             earlier_ticks = (I_)((atof(start_str + 1) * TICK_FREQUENCY));
610                         }
611                     }
612                     break;
613                   default:
614                     fprintf(stderr, "Invalid heap profile option: %s\n",
615                             rts_argv[arg]);
616                     error = rtsTrue;
617                 }
618                 ) 
619 #endif
620                 break;
621
622               case 'z': /* size of index tables */
623                 PROFILING_BUILD_ONLY(
624                 switch (rts_argv[arg][2]) {
625                   case CCchar:
626                     max_cc_no = (hash_t) decode(rts_argv[arg]+3);
627                     if (max_cc_no == 0) {
628                         fprintf(stderr, "Bad number of cost centres %s\n", rts_argv[arg]);
629                         error = rtsTrue;
630                     }
631                     break;
632                   case MODchar:
633                     max_mod_no = (hash_t) decode(rts_argv[arg]+3);
634                     if (max_mod_no == 0) {
635                         fprintf(stderr, "Bad number of modules %s\n", rts_argv[arg]);
636                         error = rtsTrue;
637                     }
638                     break;
639                   case GRPchar:
640                     max_grp_no = (hash_t) decode(rts_argv[arg]+3);
641                     if (max_grp_no == 0) {
642                         fprintf(stderr, "Bad number of groups %s\n", rts_argv[arg]);
643                         error = rtsTrue;
644                     }
645                     break;
646                   case DESCRchar:
647                     max_descr_no = (hash_t) decode(rts_argv[arg]+3);
648                     if (max_descr_no == 0) {
649                         fprintf(stderr, "Bad number of closure descriptions %s\n", rts_argv[arg]);
650                         error = rtsTrue;
651                     }
652                     break;
653                   case TYPEchar:
654                     max_type_no = (hash_t) decode(rts_argv[arg]+3);
655                     if (max_type_no == 0) {
656                         fprintf(stderr, "Bad number of type descriptions %s\n", rts_argv[arg]);
657                         error = rtsTrue;
658                     }
659                     break;
660                   default:
661                     fprintf(stderr, "Invalid index table size option: %s\n",
662                             rts_argv[arg]);
663                     error = rtsTrue;
664                 }
665                 ) break;
666
667               case 'c': /* cost centre label select */
668               case 'g': /* cost centre group select */
669               case 'd': /* closure descr select */
670               case 'y': /* closure type select */
671                 PROFILING_BUILD_ONLY(
672                 {char *left  = strchr(rts_argv[arg], '{');
673                  char *right = strrchr(rts_argv[arg], '}');
674
675                 if (! left || ! right ||
676                         strrchr(rts_argv[arg], '{') != left ||
677                          strchr(rts_argv[arg], '}') != right) {
678                     fprintf(stderr, "Invalid heap profiling selection bracketing\n   %s\n", rts_argv[arg]);
679                     error = rtsTrue;
680                 } else {
681                     *right = '\0';
682                     switch (rts_argv[arg][1]) {
683                       case 'c': /* cost centre label select */
684                         RtsFlags.ProfFlags.ccSelector = left + 1;
685                         break;
686                       case 'm': /* cost centre module select */
687                         RtsFlags.ProfFlags.modSelector = left + 1;
688                         break;
689                       case 'g': /* cost centre group select */
690                         RtsFlags.ProfFlags.grpSelector = left + 1;
691                         break;
692                       case 'd': /* closure descr select */
693                         RtsFlags.ProfFlags.descrSelector = left + 1;
694                         break;
695                       case 'y': /* closure type select */
696                         RtsFlags.ProfFlags.typeSelector = left + 1;
697                         break;
698                       case 'k': /* closure kind select */
699                         RtsFlags.ProfFlags.kindSelector = left + 1;
700                         break;
701                     }
702                 }}
703                 ) break;
704
705               /* =========== CONCURRENT ========================= */
706               case 'C': /* context switch interval */
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               /* =========== PARALLEL =========================== */
723               case 'e':
724                 PAR_BUILD_ONLY(
725                 if (rts_argv[arg][2] != '\0') { /* otherwise, stick w/ the default */
726
727                     RtsFlags.ParFlags.maxLocalSparks
728                       = strtol(rts_argv[arg]+2, (char **) NULL, 10);
729
730                     if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
731                         fprintf(stderr, "setupRtsFlags: bad value for -e\n");
732                         error = rtsTrue;
733                     }
734                 }
735                 ) break;
736
737               case 'O':
738                 PAR_BUILD_ONLY(
739                 RtsFlags.ParFlags.outputDisabled = rtsTrue;
740                 ) break;
741
742               case 'q': /* activity profile option */
743                 PAR_BUILD_ONLY(
744                 if (rts_argv[arg][2] == 'b')
745                     RtsFlags.ParFlags.granSimStats_Binary = rtsTrue;
746                 else
747                     RtsFlags.ParFlags.granSimStats = rtsTrue;
748                 ) break;
749
750 #if 0 /* or??? */
751               case 'q': /* quasi-parallel profile option */
752                 GRAN_BUILD_ONLY (
753                 if (rts_argv[arg][2] == 'v')
754                     do_qp_prof = 2;
755                 else
756                     do_qp_prof++;
757                 ) break;
758 #endif /* 0??? */
759
760               case 'Q': /* Set pack buffer size */
761                 PAR_BUILD_ONLY(
762                 if (rts_argv[arg][2] != '\0') {
763                     RtsFlags.ParFlags.packBufferSize = decode(rts_argv[arg]+2);
764                 } else {
765                     fprintf(stderr, "setupRtsFlags: missing size of PackBuffer (for -Q)\n");
766                     error = rtsTrue;
767                 }
768                 ) break;
769
770               /* =========== GRAN =============================== */
771
772               case 'b':
773                 GRAN_BUILD_ONLY(
774                 process_gran_option(arg, rts_argc, rts_argv, &error);
775                 ) break;
776
777               /* =========== TICKY ============================== */
778
779               case 'r': /* Basic profiling stats */
780                 TICKY_BUILD_ONLY(
781
782                 RtsFlags.TickyFlags.showTickyStats = rtsTrue;
783                 RtsFlags.TickyFlags.tickyFile
784                   = open_stats_file(arg, *argc, argv,
785                         *rts_argc, rts_argv, TICKY_FILENAME_FMT);
786
787                 if (RtsFlags.TickyFlags.tickyFile == NULL) error = rtsTrue;
788                 ) break;
789
790               /* =========== OH DEAR ============================ */
791               default:
792                 fprintf(stderr, "setupRtsFlags: Unknown RTS option: %s\n",rts_argv[arg]);
793                 error = rtsTrue;
794                 break;
795             }
796         }
797     }
798     if (error) {
799         const char **p;
800
801         fflush(stdout);
802         for (p = usage_text; *p; p++)
803             fprintf(stderr, "%s\n", *p);
804         stg_exit(EXIT_FAILURE);
805     }
806
807 }
808
809 static FILE *           /* return NULL on error */
810 open_stats_file (
811     I_ arg,
812     int argc, char *argv[],
813     int rts_argc, char *rts_argv[],
814     const char *FILENAME_FMT)
815 {
816     FILE *f = NULL;
817
818     if (strequal(rts_argv[arg]+2, "stderr")) /* use real stderr */
819         f = stderr;
820     else if (rts_argv[arg][2] != '\0')      /* stats file specified */
821         f = fopen(rts_argv[arg]+2,"w");
822     else {
823         char stats_filename[STATS_FILENAME_MAXLEN]; /* default <program>.<ext> */
824         sprintf(stats_filename, FILENAME_FMT, argv[0]);
825         f = fopen(stats_filename,"w");
826     }
827     if (f == NULL) {
828         fprintf(stderr, "Can't open stats file %s\n", rts_argv[arg]+2);
829     } else {
830         /* Write argv and rtsv into start of stats file */
831         I_ count;
832         for(count = 0; count < argc; count++)
833             fprintf(f, "%s ", argv[count]);
834         fprintf(f, "+RTS ");
835         for(count = 0; count < rts_argc; count++)
836             fprintf(f, "%s ", rts_argv[count]);
837         fprintf(f, "\n");
838     }
839
840     return(f);
841 }
842
843 static I_
844 decode(const char *s)
845 {
846     I_ c;
847     StgDouble m;
848
849     if (!*s)
850         return 0;
851
852     m = atof(s);
853     c = s[strlen(s)-1];
854
855     if (c == 'g' || c == 'G')
856         m *= 1000*1000*1000;    /* UNchecked! */
857     else if (c == 'm' || c == 'M')
858         m *= 1000*1000;                 /* We do not use powers of 2 (1024) */
859     else if (c == 'k' || c == 'K')      /* to avoid possible bad effects on */
860         m *= 1000;                      /* a direct-mapped cache.           */ 
861     else if (c == 'w' || c == 'W')
862         m *= sizeof(W_);
863
864     return (I_)m;
865 }
866
867 static void
868 bad_option(const char *s)
869 {
870   fflush(stdout);
871   fprintf(stderr, "initSM: Bad RTS option: %s\n", s);
872   stg_exit(EXIT_FAILURE);
873 }