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