% % (c) The GRASP/AQUA Project, Glasgow University, 1995 % \section{Runtime-system runtime flags} Everything to do with RTS runtime flags, including RTS parameters that can be set by them, either directly or indirectly. @rtsFlags.lh@ defines the data structure that holds all of them. \begin{code} #include "rtsdefs.h" struct RTS_FLAGS RTSflags; /* actually declare the data structure */ struct ALL_FLAGS AllFlags; /* some fwd decls */ static I_ decode(const char *); static void bad_option(const char *); static FILE * open_stats_file (I_ arg, int argc, char *argv[], int rts_argc, char *rts_argv[], const char *FILENAME_FMT); /* extern decls */ long strtol PROTO((const char *, char **, int)); \end{code} %************************************************************************ %* * \subsection{Initial default values for @RTSFlags@} %* * %************************************************************************ \begin{code} void initRtsFlagsDefaults (STG_NO_ARGS) { RTSflags.GcFlags.statsFile = NULL; RTSflags.GcFlags.giveStats = NO_GC_STATS; RTSflags.GcFlags.stksSize = 0x10002; /* 2^16 = 16Kwords = 64Kbytes */ RTSflags.GcFlags.heapSize = 0x100002; /* 2^20 = 1Mwords = 4Mbytes */ RTSflags.GcFlags.allocAreaSize = 0x4002; /* 2^14 = 16Kwords = 64Kbytes; plus 2 cache-friendly words */ RTSflags.GcFlags.allocAreaSizeGiven = rtsFalse; RTSflags.GcFlags.specifiedOldGenSize= 0; /* means: use all heap available */ RTSflags.GcFlags.pcFreeHeap = 3; /* 3% */ /* minAllocAreaSize is derived; set in initSM, after we know pcFreeHeap and heapSize */ RTSflags.GcFlags.force2s = rtsFalse; RTSflags.GcFlags.forceGC = rtsFalse; RTSflags.GcFlags.forcingInterval = 5000000; /* 5MB (or words?) */ RTSflags.GcFlags.ringBell = rtsFalse; RTSflags.GcFlags.trace = 0; /* not turned on */ RTSflags.GcFlags.lazyBlackHoling = rtsTrue; RTSflags.GcFlags.doSelectorsAtGC = rtsTrue; RTSflags.GcFlags.squeezeUpdFrames = rtsTrue; #if defined(PROFILING) || defined(PAR) RTSflags.CcFlags.doCostCentres = 0; RTSflags.CcFlags.sortBy = SORTCC_TIME; /* "ctxtSwitchTicks", "profilerTicks", & "msecsPerTick" are derived info, so they are set after ctxtSwitchTime has been determined. */ #endif /* PROFILING or PAR */ #ifdef PROFILING RTSflags.ProfFlags.doHeapProfile = rtsFalse; #endif /* PROFILING */ #ifdef CONCURRENT RTSflags.ConcFlags.ctxtSwitchTime = CS_MIN_MILLISECS; /* In milliseconds */ RTSflags.ConcFlags.maxThreads = 32; RTSflags.ConcFlags.stkChunkSize = 1024; RTSflags.ConcFlags.maxLocalSparks = 500; #endif /* CONCURRENT */ #ifdef PAR RTSflags.ParFlags.parallelStats = rtsFalse; RTSflags.ParFlags.granSimStats = rtsFalse; RTSflags.ParFlags.granSimStats_Binary = rtsFalse; RTSflags.ParFlags.outputDisabled = rtsFalse; RTSflags.ParFlags.packBufferSize = 1024; #endif /* PAR */ #ifdef TICKY_TICKY RTSflags.TickyFlags.showTickyStats = rtsFalse; RTSflags.TickyFlags.tickyFile = NULL; AllFlags.doUpdEntryCounts = rtsTrue; /*ToDo:move? */ #endif } \end{code} %************************************************************************ %* * \subsection{Usage message for runtime-system (RTS) flags} %* * %************************************************************************ \begin{code} static const char * usage_text[] = { "", "Usage: [+RTS | -RTS ] ... --RTS ", "", " +RTS Indicates run time system options follow", " -RTS Indicates program arguments follow", " --RTS Indicates that ALL subsequent arguments will be given to the", " program (including any of these RTS flags)", "", "The following run time system options are available:", "", " -? -f Prints this message and exits; the program is not executed", "", " -K Sets the stack size (default 64k) Egs: -K32k -K512k", " -H Sets the heap size (default 4M) -H512k -H16M", " -s Summary GC statistics (default file: .stat)", " -S Detailed GC statistics (with -Sstderr going to stderr)", "", #if defined(GCap) " -M% Sets minimum size of alloc area as % of heap (default 3%)", " -A Fixes size of alloc area, overriding any minimum (-A gives 64k)", " -G Fixes size of major generation (default is dynamic threshold)", " -F2s Forces program compiled for Appel gc to use 2s collection", #else # if defined(GCgn) " -A Specifies size of alloc area (default 64k)", " -G Fixes size of major generation (default is available heap)", " -F2s Forces program compiled for Gen gc to use 2s collection", # else " -M% Minimum % of heap which must be available (default 3%)", " -A Fixes size of heap area allocated between GCs (-A gives 64k)", # endif #endif " -j Forces major GC at every bytes allocated", #if defined(GCdu) " -u Fixes residency threshold at which mode switches (range 0.0..0.95)", #endif "", " -N No black-holing during GC (for use when a signal handler is present)", " -Z Don't squeeze out update frames on stack overflow", " -B Sound the bell at the start of each (major) garbage collection", #if defined(PROFILING) || defined(PAR) "", " -p Produce cost centre time profile (output file .prof)", " sort: T = time (default), A = alloc, C = cost centre label", " -P Produce serial time profile (output file .time)", " and a -p profile with detailed caf/enter/tick/alloc info", # if defined(PROFILING) "", " -h Heap residency profile (output file .hp)", " break-down: C = cost centre (default), M = module, G = group", " D = closure description, Y = type description", " T, = time closure created", " ints: no. of interval bands plotted (default 18)", " start: seconds after which intervals start (default 0.0)", " A subset of closures may be selected by the attached cost centre using:", " -c{mod:lab,mod:lab...}, specific module:label cost centre(s)", " -m{mod,mod...} all cost centres from the specified modules(s)", " -g{grp,grp...} all cost centres from the specified group(s)", " Selections can also be made by description, type, kind and age:", " -d{des,des...} closures with specified closure descriptions", " -y{typ,typ...} closures with specified type descriptions", " -k{knd,knd...} closures of the specified kinds", " -a closures which survived complete intervals", " The selection logic used is summarised as follows:", " ([-c] or [-m] or [-g]) and ([-d] or [-y] or [-k]) and [-a]", " where an option is true if not specified", # endif "", " -z set hash table for (C, M, G, D or Y)", "", " -i Number of seconds in a profiling interval (default 1.0):", " heap profile (-h) and/or serial time profile (-P) frequency", #endif /* PROFILING or PAR */ "", #if defined(TICKY_TICKY) " -r Produce reduction profiling statistics (with -rstderr for stderr)", "", #endif " -T Trace garbage collection execution (debugging)", #ifdef CONCURRENT "", # ifdef PAR " -N Use PVMish processors in parallel (default: 2)", /* NB: the -N is implemented by the driver!! */ # endif " -C Context-switch interval in seconds", " (0 or no argument means switch as often as possible)", " the default is .01 sec; resolution is .01 sec", " -e Size of spark pools (default 100)", # ifdef PAR " -q Enable activity profile (output files in ~/*.gr)", " -qb Enable binary activity profile (output file /tmp/.gb)", " -Q Set pack-buffer size (default: 1024)", # else " -q[v] Enable quasi-parallel profile (output file .qp)", # endif " -t Set maximum number of advisory threads per PE (default 32)", " -o Set stack chunk size (default 1024)", # ifdef PAR " -d Turn on PVM-ish debugging", " -O Disable output for performance measurement", # endif /* PAR */ #endif /* CONCURRENT */ "", "Other RTS options may be available for programs compiled a different way.", "The GHC User's Guide has full details.", "", 0 }; \end{code} %************************************************************************ %* * \subsection{Processing command-line arguments to set @RTSFlags@} %* * %************************************************************************ \begin{code} #define RTS 1 #define PGM 0 #ifndef atof extern double atof(); /* no proto because some machines use const and some do not */ #endif static __inline__ rtsBool strequal(const char *a, const char * b) { return(strcmp(a, b) == 0); } void setupRtsFlags(int *argc, char *argv[], int *rts_argc, char *rts_argv[]) { rtsBool error = rtsFalse; I_ mode; I_ arg, total_arg; char *last_slash; /* Remove directory from argv[0] -- default files in current directory */ if ((last_slash = (char *) strrchr(argv[0], '/')) != NULL) strcpy(argv[0], last_slash+1); /* Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts */ /* argv[0] must be PGM argument -- leave in argv */ total_arg = *argc; arg = 1; *argc = 1; *rts_argc = 0; for (mode = PGM; arg < total_arg && ! strequal("--RTS", argv[arg]); arg++) { if (strequal("+RTS", argv[arg])) { mode = RTS; } else if (strequal("-RTS", argv[arg])) { mode = PGM; } else if (mode == RTS && *rts_argc < MAX_RTS_ARGS-1) { rts_argv[(*rts_argc)++] = argv[arg]; } else if (mode == PGM) { argv[(*argc)++] = argv[arg]; } else { fflush(stdout); fprintf(stderr, "setupRtsFlags: Too many RTS arguments (max %d)\n", MAX_RTS_ARGS-1); EXIT(EXIT_FAILURE); } } if (arg < total_arg) { /* arg must be --RTS; process remaining program arguments */ while (++arg < total_arg) { argv[(*argc)++] = argv[arg]; } } argv[*argc] = (char *) 0; rts_argv[*rts_argc] = (char *) 0; /* Process RTS (rts_argv) part: mainly to determine statsfile */ for (arg = 0; arg < *rts_argc; arg++) { if (rts_argv[arg][0] != '-') { fflush(stdout); fprintf(stderr, "setupRtsFlags: Unexpected RTS argument: %s\n", rts_argv[arg]); error = rtsTrue; } else { switch(rts_argv[arg][1]) { /* process: general args, then PROFILING-only ones, then CONCURRENT-only, PARallel-only, GRAN-only, TICKY-only (same order as defined in RtsFlags.lh); within those groups, mostly in case-insensitive alphabetical order. */ #ifdef TICKY_TICKY # define TICKY_BUILD_ONLY(x) x #else # define TICKY_BUILD_ONLY(x) \ fprintf(stderr, "setupRtsFlags: GHC not built for: ticky-ticky stats\n"); \ error = rtsTrue; #endif #if (defined(PROFILING) || defined(PAR)) # define COST_CENTRE_USING_BUILD_ONLY(x) x #else # define COST_CENTRE_USING_BUILD_ONLY(x) \ fprintf(stderr, "setupRtsFlags: GHC not built for: -prof or -parallel\n"); \ error = rtsTrue; #endif #ifdef PROFILING # define PROFILING_BUILD_ONLY(x) #else # define PROFILING_BUILD_ONLY(x) \ fprintf(stderr, "setupRtsFlags: GHC not built for: -prof\n"); \ error = rtsTrue; #endif #ifdef CONCURRENT # define CONCURRENT_BUILD_ONLY(x) #else # define CONCURRENT_BUILD_ONLY(x) \ fprintf(stderr, "setupRtsFlags: GHC not built for: -concurrent\n"); \ error = rtsTrue; #endif #ifdef PAR # define PAR_BUILD_ONLY(x) #else # define PAR_BUILD_ONLY(x) \ fprintf(stderr, "setupRtsFlags: GHC not built for: -parallel\n"); \ error = rtsTrue; #endif #ifdef GRAN # define GRAN_BUILD_ONLY(x) #else # define GRAN_BUILD_ONLY(x) \ fprintf(stderr, "setupRtsFlags: GHC not built for: -gransim\n"); \ error = rtsTrue; #endif /* =========== GENERAL ========================== */ case '?': case 'f': error = rtsTrue; break; case 'A': RTSflags.GcFlags.allocAreaSize = decode(rts_argv[arg]+2) / sizeof(W_); RTSflags.GcFlags.allocAreaSizeGiven = rtsTrue; break; case 'B': RTSflags.GcFlags.ringBell = rtsTrue; break; case 'F': if (strequal(rts_argv[arg]+2, "2s")) { RTSflags.GcFlags.force2s = rtsTrue; } else { bad_option( rts_argv[arg] ); } break; case 'G': RTSflags.GcFlags.specifiedOldGenSize = decode(rts_argv[arg]+2) / sizeof(W_); break; case 'K': RTSflags.GcFlags.stksSize = decode(rts_argv[arg]+2) / sizeof(W_); if (RTSflags.GcFlags.stksSize == 0) bad_option( rts_argv[arg] ); break; case 'H': RTSflags.GcFlags.heapSize = decode(rts_argv[arg]+2) / sizeof(W_); /* user give size in *bytes* but "heapSize" is in *words* */ if (RTSflags.GcFlags.heapSize <= 0) bad_option(rts_argv[arg]); break; case 'j': /* force GC option */ RTSflags.GcFlags.forceGC = rtsTrue; if (rts_argv[arg][2]) { RTSflags.GcFlags.forcingInterval = decode(rts_argv[arg]+2) / sizeof(W_); } break; case 'M': RTSflags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2); if (RTSflags.GcFlags.pcFreeHeap < 0 || RTSflags.GcFlags.pcFreeHeap > 100) bad_option( rts_argv[arg] ); break; case 'N': RTSflags.GcFlags.lazyBlackHoling = rtsFalse; break; case 'n': RTSflags.GcFlags.doSelectorsAtGC = rtsFalse; break; case 'S': /* NB: no difference at present ! */ case 's': RTSflags.GcFlags.giveStats ++; /* will be VERBOSE_GC_STATS */ #ifdef PAR /* Opening all those files would almost certainly fail... */ RTSflags.ParFlags.parallelStats = rtsTrue; RTSflags.GcFlags.statsFile = stderr; /* temporary; ToDo: rm */ #else RTSflags.GcFlags.statsFile = open_stats_file(arg, *argc, argv, *rts_argc, rts_argv, STAT_FILENAME_FMT); if (RTSflags.GcFlags.statsFile == NULL) error = rtsTrue; #endif break; case 'T': if (rts_argv[arg][2] != '\0') RTSflags.GcFlags.trace = (W_) strtol(rts_argv[arg]+2, (char **)NULL, 0); else RTSflags.GcFlags.trace = 1; /* slightly weird; why, really? */ break; case 'Z': RTSflags.GcFlags.squeezeUpdFrames = rtsFalse; break; /* =========== PROFILING ========================== */ case 'P': /* detailed cost centre profiling (time/alloc) */ COST_CENTRE_USING_BUILD_ONLY( RTSflags.CcFlags.doCostCentres++; ) case 'p': /* cost centre profiling (time/alloc) */ COST_CENTRE_USING_BUILD_ONLY( { char ch; RTSflags.CcFlags.doCostCentres++; for (ch = 2; rts_argv[arg][ch]; ch++) { switch (rts_argv[arg][2]) { case SORTCC_LABEL: case SORTCC_TIME: case SORTCC_ALLOC: RTSflags.CcFlags.sortBy = rts_argv[arg][ch]; break; default: fprintf(stderr, "Invalid profiling sort option %s\n", rts_argv[arg]); error = 1; }}} ) break; case 'i': /* serial profiling -- initial timer interval */ COST_CENTRE_USING_BUILD_ONLY( interval_ticks = (I_) ((atof(rts_argv[arg]+2) * TICK_FREQUENCY)); if (interval_ticks <= 0) interval_ticks = 1; ) break; case 'h': /* serial heap profile */ PROFILING_BUILD_ONLY( switch (rts_argv[arg][2]) { case '\0': case CCchar: RTSflags.ProfFlags.doHeapProfile = HEAP_BY_CC; break; case MODchar: RTSflags.ProfFlags.doHeapProfile = HEAP_BY_MOD; break; case GRPchar: RTSflags.ProfFlags.doHeapProfile = HEAP_BY_GRP; break; case DESCRchar: RTSflags.ProfFlags.doHeapProfile = HEAP_BY_DESCR; break; case TYPEchar: RTSflags.ProfFlags.doHeapProfile = HEAP_BY_TYPE; break; case TIMEchar: RTSflags.ProfFlags.doHeapProfile = HEAP_BY_TIME; if (rts_argv[arg][3]) { char *start_str = strchr(rts_argv[arg]+3, ','); I_ intervals; if (start_str) *start_str = '\0'; if ((intervals = decode(rts_argv[arg]+3)) != 0) { time_intervals = (hash_t) intervals; /* ToDo: and what if it *is* zero intervals??? */ } if (start_str) { earlier_ticks = (I_)((atof(start_str + 1) * TICK_FREQUENCY)); } } break; default: fprintf(stderr, "Invalid heap profile option: %s\n", rts_argv[arg]); error = 1; } ) break; case 'z': /* size of index tables */ PROFILING_BUILD_ONLY( switch (rts_argv[arg][2]) { case CCchar: max_cc_no = (hash_t) decode(rts_argv[arg]+3); if (max_cc_no == 0) { fprintf(stderr, "Bad number of cost centres %s\n", rts_argv[arg]); error = 1; } break; case MODchar: max_mod_no = (hash_t) decode(rts_argv[arg]+3); if (max_mod_no == 0) { fprintf(stderr, "Bad number of modules %s\n", rts_argv[arg]); error = 1; } break; case GRPchar: max_grp_no = (hash_t) decode(rts_argv[arg]+3); if (max_grp_no == 0) { fprintf(stderr, "Bad number of groups %s\n", rts_argv[arg]); error = 1; } break; case DESCRchar: max_descr_no = (hash_t) decode(rts_argv[arg]+3); if (max_descr_no == 0) { fprintf(stderr, "Bad number of closure descriptions %s\n", rts_argv[arg]); error = 1; } break; case TYPEchar: max_type_no = (hash_t) decode(rts_argv[arg]+3); if (max_type_no == 0) { fprintf(stderr, "Bad number of type descriptions %s\n", rts_argv[arg]); error = 1; } break; default: fprintf(stderr, "Invalid index table size option: %s\n", rts_argv[arg]); error = 1; } ) break; case 'c': /* cost centre label select */ case 'm': /* cost centre module select */ case 'g': /* cost centre group select */ case 'd': /* closure descr select */ case 'y': /* closure type select */ case 'k': /* closure kind select */ PROFILING_BUILD_ONLY( left = strchr(rts_argv[arg], '{'); right = strrchr(rts_argv[arg], '}'); if (! left || ! right || strrchr(rts_argv[arg], '{') != left || strchr(rts_argv[arg], '}') != right) { fprintf(stderr, "Invalid heap profiling selection bracketing\n %s\n", rts_argv[arg]); error = 1; } else { *right = '\0'; switch (rts_argv[arg][1]) { case 'c': /* cost centre label select */ select_cc = left + 1; break; case 'm': /* cost centre module select */ select_mod = left + 1; break; case 'g': /* cost centre group select */ select_grp = left + 1; break; case 'd': /* closure descr select */ select_descr = left + 1; break; case 't': /* closure type select */ select_type = left + 1; break; case 'k': /* closure kind select */ select_kind = left + 1; break; } } ) break; /* =========== CONCURRENT ========================= */ case 'C': /* context switch interval */ CONCURRENT_BUILD_ONLY ( if (rts_argv[arg][2] == '\0') RTSflags.ConcFlags.ctxtSwitchTime = 0; else { I_ cst; /* tmp */ /* Convert to milliseconds */ cst = (I_) ((atof(rts_argv[arg]+2) * 1000)); cst = (cst / CS_MIN_MILLISECS) * CS_MIN_MILLISECS; if (cst < CS_MIN_MILLISECS) cst = CS_MIN_MILLISECS; RTSflags.ConcFlags.ctxtSwitchTime = cst; } ) break; case 't': CONCURRENT_BUILD_ONLY( if (rts_argv[arg][2] != '\0') { RTSflags.ConcFlags.maxThreads = strtol(rts_argv[arg]+2, (char **) NULL, 10); } else { fprintf(stderr, "setupRtsFlags: missing size for -t\n"); error = rtsTrue; } ) break; case 'o': CONCURRENT_BUILD_ONLY ( if (rts_argv[arg][2] != '\0') { I_ size = decode(rts_argv[arg]+2); if (size < MIN_STKO_CHUNK_SIZE) size = MIN_STKO_CHUNK_SIZE; RTSflags.ConcFlags.stkChunkSize = size; } else { fprintf(stderr, "setupRtsFlags: missing size for -o\n"); error = rtsTrue; } ) break; /* =========== PARALLEL =========================== */ case 'e': CONCURRENT_BUILD_ONLY( if (rts_argv[arg][2] != '\0') { /* otherwise, stick w/ the default */ RTSflags.ConcFlags.maxLocalSparks = strtol(rts_argv[arg]+2, (char **) NULL, 10); if (RTSflags.ConcFlags.maxLocalSparks <= 0) { fprintf(stderr, "setupRtsFlags: bad value for -e\n"); error = rtsTrue; } } ) break; case 'O': PAR_BUILD_ONLY( RTSflags.ParFlags.outputDisabled = rtsTrue; ) break; case 'q': /* activity profile option */ PAR_BUILD_ONLY( if (rts_argv[arg][2] == 'b') RTSflags.ParFlags.granSimStats_Binary = rtsTrue; else RTSflags.ParFlags.granSimStats = rtsTrue; ) break; #if 0 /* or??? */ case 'q': /* quasi-parallel profile option */ GRAN_BUILD_ONLY ( if (rts_argv[arg][2] == 'v') do_qp_prof = 2; else do_qp_prof++; ) break; #endif /* 0??? */ case 'Q': /* Set pack buffer size */ PAR_BUILD_ONLY( if (rts_argv[arg][2] != '\0') { RTSflags.ParFlags.packBufferSize = decode(rts_argv[arg]+2); } else { fprintf(stderr, "setupRtsFlags: missing size of PackBuffer (for -Q)\n"); error = rtsTrue; } ) break; /* =========== GRAN =============================== */ case 'b': GRAN_BUILD_ONLY( process_gran_option(); ) break; /* =========== TICKY ============================== */ case 'r': /* Basic profiling stats */ TICKY_BUILD_ONLY( RTSflags.TickyFlags.showTickyStats = rtsTrue; RTSflags.TickyFlags.tickyFile = open_stats_file(arg, *argc, argv, *rts_argc, rts_argv, TICKY_FILENAME_FMT); if (RTSflags.TickyFlags.tickyFile == NULL) error = rtsTrue; ) break; /* =========== OH DEAR ============================ */ default: fprintf(stderr, "setupRtsFlags: Unknown RTS option: %s\n",rts_argv[arg]); error = rtsTrue; break; } } } if (error) { const char **p; fflush(stdout); for (p = usage_text; *p; p++) fprintf(stderr, "%s\n", *p); EXIT(EXIT_FAILURE); } } #ifdef GRAN static void process_gran_option() { if (rts_argv[arg][2] != '\0') { /* Should we emulate hbcpp */ if(strequal((rts_argv[arg]+2),"roken")) { ++DoAlwaysCreateThreads; strcpy(rts_argv[arg]+2,"oring"); } /* or a ridiculously idealised simulator */ if(strequal((rts_argv[arg]+2),"oring")) { gran_latency = gran_fetchtime = gran_additional_latency = gran_gunblocktime = gran_lunblocktime = gran_threadcreatetime = gran_threadqueuetime = gran_threadscheduletime = gran_threaddescheduletime = gran_threadcontextswitchtime = 0; gran_mpacktime = gran_munpacktime = 0; gran_arith_cost = gran_float_cost = gran_load_cost = gran_store_cost = gran_branch_cost = 0; gran_heapalloc_cost = 1; /* ++DoFairSchedule; */ ++DoStealThreadsFirst; ++DoThreadMigration; RTSflags.ParFlags.granSimStats = rtsTrue; } /* or a ridiculously idealised simulator */ if(strequal((rts_argv[arg]+2),"onzo")) { gran_latency = gran_fetchtime = gran_additional_latency = gran_gunblocktime = gran_lunblocktime = gran_threadcreatetime = gran_threadqueuetime = gran_threadscheduletime = gran_threaddescheduletime = gran_threadcontextswitchtime = 0; gran_mpacktime = gran_munpacktime = 0; /* Keep default values for these gran_arith_cost = gran_float_cost = gran_load_cost = gran_store_cost = gran_branch_cost = 0; */ gran_heapalloc_cost = 1; /* ++DoFairSchedule; */ /* -b-R */ /* ++DoStealThreadsFirst; */ /* -b-T */ ++DoReScheduleOnFetch; /* -bZ */ ++DoThreadMigration; /* -bM */ RTSflags.ParFlags.granSimStats = rtsTrue; /* -bP */ # if defined(GRAN_CHECK) && defined(GRAN) debug = 0x20; /* print event statistics */ # endif } /* Communication and task creation cost parameters */ else switch(rts_argv[arg][2]) { case 'l': if (rts_argv[arg][3] != '\0') { gran_gunblocktime = gran_latency = decode(rts_argv[arg]+3); gran_fetchtime = 2* gran_latency; } else gran_latency = LATENCY; break; case 'a': if (rts_argv[arg][3] != '\0') gran_additional_latency = decode(rts_argv[arg]+3); else gran_additional_latency = ADDITIONAL_LATENCY; break; case 'm': if (rts_argv[arg][3] != '\0') gran_mpacktime = decode(rts_argv[arg]+3); else gran_mpacktime = MSGPACKTIME; break; case 'x': if (rts_argv[arg][3] != '\0') gran_mtidytime = decode(rts_argv[arg]+3); else gran_mtidytime = 0; break; case 'r': if (rts_argv[arg][3] != '\0') gran_munpacktime = decode(rts_argv[arg]+3); else gran_munpacktime = MSGUNPACKTIME; break; case 'f': if (rts_argv[arg][3] != '\0') gran_fetchtime = decode(rts_argv[arg]+3); else gran_fetchtime = FETCHTIME; break; case 'n': if (rts_argv[arg][3] != '\0') gran_gunblocktime = decode(rts_argv[arg]+3); else gran_gunblocktime = GLOBALUNBLOCKTIME; break; case 'u': if (rts_argv[arg][3] != '\0') gran_lunblocktime = decode(rts_argv[arg]+3); else gran_lunblocktime = LOCALUNBLOCKTIME; break; /* Thread-related metrics */ case 't': if (rts_argv[arg][3] != '\0') gran_threadcreatetime = decode(rts_argv[arg]+3); else gran_threadcreatetime = THREADCREATETIME; break; case 'q': if (rts_argv[arg][3] != '\0') gran_threadqueuetime = decode(rts_argv[arg]+3); else gran_threadqueuetime = THREADQUEUETIME; break; case 'c': if (rts_argv[arg][3] != '\0') gran_threadscheduletime = decode(rts_argv[arg]+3); else gran_threadscheduletime = THREADSCHEDULETIME; gran_threadcontextswitchtime = gran_threadscheduletime + gran_threaddescheduletime; break; case 'd': if (rts_argv[arg][3] != '\0') gran_threaddescheduletime = decode(rts_argv[arg]+3); else gran_threaddescheduletime = THREADDESCHEDULETIME; gran_threadcontextswitchtime = gran_threadscheduletime + gran_threaddescheduletime; break; /* Instruction Cost Metrics */ case 'A': if (rts_argv[arg][3] != '\0') gran_arith_cost = decode(rts_argv[arg]+3); else gran_arith_cost = ARITH_COST; break; case 'F': if (rts_argv[arg][3] != '\0') gran_float_cost = decode(rts_argv[arg]+3); else gran_float_cost = FLOAT_COST; break; case 'B': if (rts_argv[arg][3] != '\0') gran_branch_cost = decode(rts_argv[arg]+3); else gran_branch_cost = BRANCH_COST; break; case 'L': if (rts_argv[arg][3] != '\0') gran_load_cost = decode(rts_argv[arg]+3); else gran_load_cost = LOAD_COST; break; case 'S': if (rts_argv[arg][3] != '\0') gran_store_cost = decode(rts_argv[arg]+3); else gran_store_cost = STORE_COST; break; case 'H': if (rts_argv[arg][3] != '\0') gran_heapalloc_cost = decode(rts_argv[arg]+3); else gran_heapalloc_cost = 0; break; case 'y': if (rts_argv[arg][3] != '\0') FetchStrategy = decode(rts_argv[arg]+3); else FetchStrategy = 4; /* default: fetch everything */ break; /* General Parameters */ case 'p': if (rts_argv[arg][3] != '\0') { max_proc = decode(rts_argv[arg]+3); if(max_proc > MAX_PROC || max_proc < 1) { fprintf(stderr,"setupRtsFlags: no more than %u processors allowed\n", MAX_PROC); error = rtsTrue; } } else max_proc = MAX_PROC; break; case 'C': ++DoAlwaysCreateThreads; ++DoThreadMigration; break; case 'G': ++DoGUMMFetching; break; case 'M': ++DoThreadMigration; break; case 'R': ++DoFairSchedule; break; case 'T': ++DoStealThreadsFirst; ++DoThreadMigration; break; case 'Z': ++DoReScheduleOnFetch; break; case 'z': ++SimplifiedFetch; break; case 'N': ++PreferSparksOfLocalNodes; break; case 'b': RTSflags.ParFlags.granSimStats_Binary = rtsTrue; break; case 'P': RTSflags.ParFlags.granSimStats = rtsTrue; break; case 's': ++do_sp_profile; break; case '-': switch(rts_argv[arg][3]) { case 'C': DoAlwaysCreateThreads=0; DoThreadMigration=0; break; case 'G': DoGUMMFetching=0; break; case 'M': DoThreadMigration=0; break; case 'R': DoFairSchedule=0; break; case 'T': DoStealThreadsFirst=0; DoThreadMigration=0; break; case 'Z': DoReScheduleOnFetch=0; break; case 'N': PreferSparksOfLocalNodes=0; break; case 'P': RTSflags.ParFlags.granSimStats = rtsFalse; no_gr_profile=1; break; case 's': do_sp_profile=0; break; case 'b': RTSflags.ParFlags.granSimStats_Binary = rtsFalse; break; default: bad_option( rts_argv[arg] ); break; } break; # if defined(GRAN_CHECK) && defined(GRAN) case 'D': switch(rts_argv[arg][3]) { case 'e': /* event trace */ fprintf(stderr,"Printing event trace.\n"); ++event_trace; break; case 'f': fprintf(stderr,"Printing forwarding of FETCHNODES.\n"); debug |= 0x2; /* print fwd messages */ break; case 'z': fprintf(stderr,"Check for blocked on fetch.\n"); debug |= 0x4; /* debug non-reschedule-on-fetch */ break; case 't': fprintf(stderr,"Check for TSO asleep on fetch.\n"); debug |= 0x10; /* debug TSO asleep for fetch */ break; case 'E': fprintf(stderr,"Printing event statistics.\n"); debug |= 0x20; /* print event statistics */ break; case 'F': fprintf(stderr,"Prohibiting forward.\n"); NoForward = 1; /* prohibit forwarding */ break; case 'm': fprintf(stderr,"Printing fetch misses.\n"); PrintFetchMisses = 1; /* prohibit forwarding */ break; case 'd': fprintf(stderr,"Debug mode.\n"); debug |= 0x40; break; case 'D': fprintf(stderr,"Severe debug mode.\n"); debug |= 0x80; break; case '\0': debug = 1; break; default: bad_option( rts_argv[arg] ); break; } break; # endif default: bad_option( rts_argv[arg] ); break; } } do_gr_sim++; RTSflags.ConcFlags.ctxtSwitchTime = 0; } #endif /* GRAN */ \end{code} %************************************************************************ %* * \subsection{Profiling RTS Arguments} %* * %************************************************************************ \begin{code} I_ MaxResidency = 0; /* in words; for stats only */ I_ ResidencySamples = 0; /* for stats only */ void initSM(void) { RTSflags.GcFlags.minAllocAreaSize = (I_) (RTSflags.GcFlags.heapSize * RTSflags.GcFlags.pcFreeHeap / 100); /* This needs to be here, in case the user changed some of these values with a "hook". */ } \end{code} %************************************************************************ %* * \subsection{Utility bits} %* * %************************************************************************ \begin{code} static FILE * /* return NULL on error */ open_stats_file ( I_ arg, int argc, char *argv[], int rts_argc, char *rts_argv[], const char *FILENAME_FMT) { FILE *f = NULL; if (strequal(rts_argv[arg]+2, "stderr")) /* use real stderr */ f = stderr; else if (rts_argv[arg][2] != '\0') /* stats file specified */ f = fopen(rts_argv[arg]+2,"w"); else { char stats_filename[STATS_FILENAME_MAXLEN]; /* default . */ sprintf(stats_filename, FILENAME_FMT, argv[0]); f = fopen(stats_filename,"w"); } if (f == NULL) { fprintf(stderr, "Can't open stats file %s\n", rts_argv[arg]+2); } else { /* Write argv and rtsv into start of stats file */ I_ count; for(count = 0; count < argc; count++) fprintf(f, "%s ", argv[count]); fprintf(f, "+RTS "); for(count = 0; count < rts_argc; count++) fprintf(f, "%s ", rts_argv[count]); fprintf(f, "\n"); } return(f); } static I_ decode(const char *s) { I_ c; StgDouble m; if (!*s) return 0; m = atof(s); c = s[strlen(s)-1]; if (c == 'g' || c == 'G') m *= 1000*1000*1000; /* UNchecked! */ else if (c == 'm' || c == 'M') m *= 1000*1000; /* We do not use powers of 2 (1024) */ else if (c == 'k' || c == 'K') /* to avoid possible bad effects on */ m *= 1000; /* a direct-mapped cache. */ else if (c == 'w' || c == 'W') m *= sizeof(W_); return (I_)m; } static void bad_option(const char *s) { fflush(stdout); fprintf(stderr, "initSM: Bad RTS option: %s\n", s); EXIT(EXIT_FAILURE); } \end{code}