/* Time-stamp: Basic functions for use in either GranSim or GUM. */ #if defined(GRAN) || defined(PAR) /* whole file */ //@menu //* Includes:: //* Variables and constants:: //* Writing to the log-file:: //* Global statistics:: //* Dumping routines:: //@end menu //*/ fool highlight //@node Includes, Variables and constants //@subsection Includes #include "Rts.h" #include "RtsFlags.h" #include "RtsUtils.h" #include "Storage.h" #include "GranSimRts.h" #include "ParallelRts.h" //@node Variables and constants, Writing to the log-file, Includes //@subsection Variables and constants /* Where to write the log file */ FILE *gr_file = NULL; char gr_filename[STATS_FILENAME_MAXLEN]; #if defined(PAR) /* Global statistics */ GlobalParStats globalParStats; #endif #if defined(PAR) StgWord64 startTime = 0; #endif #if defined(PAR) && !defined(DEBUG) // HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCCCCCCCKKKKKKKKKKKK // Definitely the wrong place for info_type in !DEBUG (see Printer.c) -- HWL static char *closure_type_names[] = { "INVALID_OBJECT", /* 0 */ "CONSTR", /* 1 */ "CONSTR_1_0", /* 2 */ "CONSTR_0_1", /* 3 */ "CONSTR_2_0", /* 4 */ "CONSTR_1_1", /* 5 */ "CONSTR_0_2", /* 6 */ "CONSTR_INTLIKE", /* 7 */ "CONSTR_CHARLIKE", /* 8 */ "CONSTR_STATIC", /* 9 */ "CONSTR_NOCAF_STATIC", /* 10 */ "FUN", /* 11 */ "FUN_1_0", /* 12 */ "FUN_0_1", /* 13 */ "FUN_2_0", /* 14 */ "FUN_1_1", /* 15 */ "FUN_0_2", /* 16 */ "FUN_STATIC", /* 17 */ "THUNK", /* 18 */ "THUNK_1_0", /* 19 */ "THUNK_0_1", /* 20 */ "THUNK_2_0", /* 21 */ "THUNK_1_1", /* 22 */ "THUNK_0_2", /* 23 */ "THUNK_STATIC", /* 24 */ "THUNK_SELECTOR", /* 25 */ "BCO", /* 26 */ "AP_UPD", /* 27 */ "PAP", /* 28 */ "IND", /* 29 */ "IND_OLDGEN", /* 30 */ "IND_PERM", /* 31 */ "IND_OLDGEN_PERM", /* 32 */ "IND_STATIC", /* 33 */ "CAF_UNENTERED", /* 34 */ "CAF_ENTERED", /* 35 */ "CAF_BLACKHOLE", /* 36 */ "RET_BCO", /* 37 */ "RET_SMALL", /* 38 */ "RET_VEC_SMALL", /* 39 */ "RET_BIG", /* 40 */ "RET_VEC_BIG", /* 41 */ "RET_DYN", /* 42 */ "UPDATE_FRAME", /* 43 */ "CATCH_FRAME", /* 44 */ "STOP_FRAME", /* 45 */ "SEQ_FRAME", /* 46 */ "BLACKHOLE", /* 47 */ "BLACKHOLE_BQ", /* 48 */ "SE_BLACKHOLE", /* 49 */ "SE_CAF_BLACKHOLE", /* 50 */ "MVAR", /* 51 */ "ARR_WORDS", /* 52 */ "MUT_ARR_PTRS", /* 53 */ "MUT_ARR_PTRS_FROZEN", /* 54 */ "MUT_VAR", /* 55 */ "WEAK", /* 56 */ "FOREIGN", /* 57 */ "STABLE_NAME", /* 58 */ "TSO", /* 59 */ "BLOCKED_FETCH", /* 60 */ "FETCH_ME", /* 61 */ "FETCH_ME_BQ", /* 62 */ "RBH", /* 63 */ "EVACUATED", /* 64 */ "REMOTE_REF", /* 65 */ "N_CLOSURE_TYPES" /* 66 */ }; char * info_type(StgClosure *closure){ return closure_type_names[get_itbl(closure)->type]; } char * info_type_by_ip(StgInfoTable *ip){ return closure_type_names[ip->type]; } void info_hdr_type(StgClosure *closure, char *res){ strcpy(res,closure_type_names[get_itbl(closure)->type]); } #endif //@node Writing to the log-file, Global statistics, Variables and constants //@subsection Writing to the log-file /* Writing to the log-file These routines dump event-based info to the main log-file. The code for writing log files is shared between GranSim and GUM. */ /* * If you're not using GNUC and you're on a 32-bit machine, you're * probably out of luck here. However, since CONCURRENT currently * requires GNUC, I'm not too worried about it. --JSM */ //@cindex init_gr_simulation #if defined(GRAN) void init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv) char *prog_argv[], *rts_argv[]; int prog_argc, rts_argc; { nat i; char *extension = RtsFlags.GranFlags.GranSimStats.Binary ? "gb" : "gr"; if (RtsFlags.GranFlags.GranSimStats.Global) init_gr_stats(); /* init global constants for costs of basic operations */ gran_arith_cost = RtsFlags.GranFlags.Costs.arith_cost; gran_branch_cost = RtsFlags.GranFlags.Costs.branch_cost; gran_load_cost = RtsFlags.GranFlags.Costs.load_cost; gran_store_cost = RtsFlags.GranFlags.Costs.store_cost; gran_float_cost = RtsFlags.GranFlags.Costs.float_cost; if (RtsFlags.GranFlags.GranSimStats.Suppressed) return; if (!RtsFlags.GranFlags.GranSimStats.Full) return; sprintf(gr_filename, GR_FILENAME_FMT, prog_argv[0], extension); if ((gr_file = fopen(gr_filename, "w")) == NULL) { barf("Can't open granularity simulation report file %s\n", gr_filename); } setbuf(gr_file, NULL); /* turn buffering off */ /* write header with program name, options and setup to gr_file */ fputs("Granularity Simulation for ", gr_file); for (i = 0; i < prog_argc; ++i) { fputs(prog_argv[i], gr_file); fputc(' ', gr_file); } if (rts_argc > 0) { fputs("+RTS ", gr_file); for (i = 0; i < rts_argc; ++i) { fputs(rts_argv[i], gr_file); fputc(' ', gr_file); } } fputs("\nStart time: ", gr_file); fputs(time_str(), gr_file); /* defined in RtsUtils.c */ fputc('\n', gr_file); fputs("\n\n--------------------\n\n", gr_file); fputs("General Parameters:\n\n", gr_file); if (RtsFlags.GranFlags.Light) fprintf(gr_file, "GrAnSim-Light\nPEs infinite, %s Scheduler, %sMigrate Threads %s, %s\n", RtsFlags.GranFlags.DoFairSchedule?"Fair":"Unfair", RtsFlags.GranFlags.DoThreadMigration?"":"Don't ", RtsFlags.GranFlags.DoThreadMigration && RtsFlags.GranFlags.DoStealThreadsFirst?" Before Sparks":"", RtsFlags.GranFlags.DoAsyncFetch ? "Asynchronous Fetch" : "Block on Fetch"); else fprintf(gr_file, "PEs %u, %s Scheduler, %sMigrate Threads %s, %s\n", RtsFlags.GranFlags.proc,RtsFlags.GranFlags.DoFairSchedule?"Fair":"Unfair", RtsFlags.GranFlags.DoThreadMigration?"":"Don't ", RtsFlags.GranFlags.DoThreadMigration && RtsFlags.GranFlags.DoStealThreadsFirst?" Before Sparks":"", RtsFlags.GranFlags.DoAsyncFetch ? "Asynchronous Fetch" : "Block on Fetch"); if (RtsFlags.GranFlags.DoBulkFetching) if (RtsFlags.GranFlags.ThunksToPack) fprintf(gr_file, "Bulk Fetching: Fetch %d Thunks in Each Packet (Packet Size = %d closures)\n", RtsFlags.GranFlags.ThunksToPack, RtsFlags.GranFlags.packBufferSize); else fprintf(gr_file, "Bulk Fetching: Fetch as many closures as possible (Packet Size = %d closures)\n", RtsFlags.GranFlags.packBufferSize); else fprintf(gr_file, "Incremental Fetching: Fetch Exactly One Closure in Each Packet\n"); fprintf(gr_file, "Fetch Strategy(%u):If outstanding fetches %s\n", RtsFlags.GranFlags.FetchStrategy, RtsFlags.GranFlags.FetchStrategy==0 ? " block (block-on-fetch)": RtsFlags.GranFlags.FetchStrategy==1 ? "only run runnable threads": RtsFlags.GranFlags.FetchStrategy==2 ? "create threads only from local sparks": RtsFlags.GranFlags.FetchStrategy==3 ? "create threads from local or global sparks": RtsFlags.GranFlags.FetchStrategy==4 ? "create sparks and steal threads if necessary": "unknown"); if (RtsFlags.GranFlags.DoPrioritySparking) fprintf(gr_file, "Priority Sparking (i.e. keep sparks ordered by priority)\n"); if (RtsFlags.GranFlags.DoPriorityScheduling) fprintf(gr_file, "Priority Scheduling (i.e. keep threads ordered by priority)\n"); fprintf(gr_file, "Thread Creation Time %u, Thread Queue Time %u\n", RtsFlags.GranFlags.Costs.threadcreatetime, RtsFlags.GranFlags.Costs.threadqueuetime); fprintf(gr_file, "Thread DeSchedule Time %u, Thread Schedule Time %u\n", RtsFlags.GranFlags.Costs.threaddescheduletime, RtsFlags.GranFlags.Costs.threadscheduletime); fprintf(gr_file, "Thread Context-Switch Time %u\n", RtsFlags.GranFlags.Costs.threadcontextswitchtime); fputs("\n\n--------------------\n\n", gr_file); fputs("Communication Metrics:\n\n", gr_file); fprintf(gr_file, "Latency %u (1st) %u (rest), Fetch %u, Notify %u (Global) %u (Local)\n", RtsFlags.GranFlags.Costs.latency, RtsFlags.GranFlags.Costs.additional_latency, RtsFlags.GranFlags.Costs.fetchtime, RtsFlags.GranFlags.Costs.gunblocktime, RtsFlags.GranFlags.Costs.lunblocktime); fprintf(gr_file, "Message Creation %u (+ %u after send), Message Read %u\n", RtsFlags.GranFlags.Costs.mpacktime, RtsFlags.GranFlags.Costs.mtidytime, RtsFlags.GranFlags.Costs.munpacktime); fputs("\n\n--------------------\n\n", gr_file); fputs("Instruction Metrics:\n\n", gr_file); fprintf(gr_file, "Arith %u, Branch %u, Load %u, Store %u, Float %u, Alloc %u\n", RtsFlags.GranFlags.Costs.arith_cost, RtsFlags.GranFlags.Costs.branch_cost, RtsFlags.GranFlags.Costs.load_cost, RtsFlags.GranFlags.Costs.store_cost, RtsFlags.GranFlags.Costs.float_cost, RtsFlags.GranFlags.Costs.heapalloc_cost); fputs("\n\n++++++++++++++++++++\n\n", gr_file); # if 0 /* binary log files are currently not supported */ if (RtsFlags.GranFlags.GranSimStats.Binary) grputw(sizeof(rtsTime)); # endif return (0); } #elif defined(PAR) void init_gr_stats (void); void init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv) char *prog_argv[], *rts_argv[]; int prog_argc, rts_argc; { nat i; char time_string[TIME_STR_LEN], node_str[NODE_STR_LEN]; char *extension = RtsFlags.ParFlags.ParStats.Binary ? "gb" : "gr"; sprintf(gr_filename, GR_FILENAME_FMT_GUM, prog_argv[0], thisPE, extension); if (!RtsFlags.ParFlags.ParStats.Full) return; if (RtsFlags.ParFlags.ParStats.Global) init_gr_stats(); if ((gr_file = fopen(gr_filename, "w")) == NULL) barf("Can't open activity report file %s\n", gr_filename); setbuf(gr_file, NULL); /* turn buffering off */ /* write header with program name, options and setup to gr_file */ for (i = 0; i < prog_argc; ++i) { fputs(prog_argv[i], gr_file); fputc(' ', gr_file); } if (rts_argc > 0) { fputs("+RTS ", gr_file); for (i = 0; i < rts_argc; ++i) { fputs(rts_argv[i], gr_file); fputc(' ', gr_file); } } fputc('\n', gr_file); /* record the absolute start time to allow synchronisation of log-files */ fputs("Start-Time: ", gr_file); fputs(time_str(), gr_file); fputc('\n', gr_file); ASSERT(startTime==0); // startTime = msTime(); startTime = CURRENT_TIME; showStgWord64(CURRENT_TIME, time_string, rtsFalse/*no commas!*/); fprintf(gr_file, "PE %2u [%s]: TIME\n", thisPE, time_string); # if 0 ngoq Dogh'q' vImuS IF_PAR_DEBUG(verbose, belch("== Start-time: %ld (%s)", startTime, time_string)); if (startTime > LL(1000000000)) { fprintf(gr_file, "PE %2u [%lu%lu]: TIME\n", thisPE, (rtsTime) (startTime / LL(1000000000)), (rtsTime) (startTime % LL(1000000000))); } else { fprintf(gr_file, "PE %2u [%lu]: TIME\n", thisPE, (TIME) startTime); } /* binary log files are currently not supported */ if (RtsFlags.GranFlags.GranSimStats.Binary) grputw(sizeof(rtsTime)); # endif return; } void init_gr_stats (void) { // memset(&globalParStats, '\0', sizeof(GlobalParStats)); globalParStats.tot_mark_GA = globalParStats.tot_rebuild_GA = globalParStats.tot_free_GA = globalParStats.res_mark_GA = globalParStats.res_rebuild_GA = globalParStats.res_free_GA = globalParStats.tot_size_GA = globalParStats.res_size_GA = globalParStats.tot_global = globalParStats.tot_local = 0; globalParStats.cnt_mark_GA = globalParStats.cnt_rebuild_GA = globalParStats.cnt_free_GA = globalParStats.res_free_GA = globalParStats.local_alloc_GA = 0; globalParStats.time_mark_GA = 0.0; globalParStats.time_rebuild_GA = 0.0; globalParStats.time_sparks = 0.0; globalParStats.time_pack = 0.0; globalParStats.res_sp = globalParStats.res_tp = globalParStats.tot_sp = globalParStats.tot_tp = globalParStats.cnt_sp = globalParStats.cnt_tp = globalParStats.emp_sp = globalParStats.emp_tp = 0; globalParStats.tot_packets = globalParStats.tot_packet_size = globalParStats.tot_thunks = globalParStats.res_packet_size = globalParStats.res_thunks = globalParStats.rec_res_packet_size = globalParStats.rec_res_thunks = 0; globalParStats.tot_fish_mess = globalParStats.tot_fetch_mess = globalParStats.tot_resume_mess = globalParStats.tot_schedule_mess = 0; globalParStats.rec_fish_mess = globalParStats.rec_resume_mess = globalParStats.rec_schedule_mess = 0; globalParStats.rec_fetch_mess = 0; #if defined(DIST) globalParStats.tot_reval_mess = 0; globalParStats.rec_reval_mess = 0; #endif globalParStats.tot_threads_created = globalParStats.tot_sparks_created = globalParStats.tot_sparks_ignored = globalParStats.tot_sparks_marked = globalParStats.res_sparks_created = globalParStats.res_sparks_ignored = globalParStats.res_sparks_marked = 0; globalParStats.tot_yields = globalParStats.tot_stackover = globalParStats.tot_heapover = 0; globalParStats.tot_arrs = globalParStats.tot_arr_size = 0; } #endif /* PAR */ //@cindex end_gr_simulation #if defined(GRAN) void end_gr_simulation(void) { char time_string[TIME_STR_LEN]; showStgWord64(CURRENT_TIME, time_string, rtsFalse/*no commas!*/); if (RtsFlags.GranFlags.GranSimStats.Suppressed) return; /* Print event stats */ if (RtsFlags.GranFlags.GranSimStats.Global) { nat i; fprintf(stderr,"Total yields: %d\n", globalGranStats.tot_yields); fprintf(stderr,"Total number of threads created: %d ; per PE:\n", globalGranStats.tot_threads_created); for (i=0; i0) fprintf(stderr," Number of closure queue overflows: %u\n", closure_queue_overflows); */ } } /* RtsFlags.GranFlags.GranSimStats.Global */ # if defined(GRAN_COUNT) # error "GRAN_COUNT not supported; should be parallel ticky profiling, really" fprintf(stderr,"Update count statistics:\n"); fprintf(stderr," Total number of updates: %u\n",nUPDs); fprintf(stderr," Needed to awaken BQ: %u with avg BQ len of: %f\n", nUPDs_BQ,(float)BQ_lens/(float)nUPDs_BQ); fprintf(stderr," Number of PAPs: %u\n",nPAPs); # endif fprintf(stderr, "Simulation finished after @ %s @ cycles. %d sparks created, %d sparks ignored. Check %s for details.\n", time_string, sparksCreated, sparksIgnored, gr_filename); if (RtsFlags.GranFlags.GranSimStats.Full) fclose(gr_file); } #elif defined(PAR) /* Under GUM we print only one line. */ void end_gr_simulation(void) { char time_string[TIME_STR_LEN]; showStgWord64(CURRENT_TIME-startTime, time_string, rtsFalse/*no commas!*/); fprintf(stderr, "Computation finished after @ %s @ ms. %d sparks created, %d sparks ignored. Check %s for details.\n", time_string, sparksCreated, sparksIgnored, gr_filename); if (RtsFlags.ParFlags.ParStats.Full) fclose(gr_file); } #endif /* PAR */ //@node Global statistics, Dumping routines, Writing to the log-file //@subsection Global statistics /* Called at the end of execution */ //@node Dumping routines, , Global statistics //@subsection Dumping routines //@cindex DumpGranEvent void DumpGranEvent(name, tso) GranEventType name; StgTSO *tso; { DumpRawGranEvent(CURRENT_PROC, (PEs)0, name, tso, &stg_END_TSO_QUEUE_closure, (StgInt)0, (StgInt)0); } //@cindex DumpRawGranEvent void DumpRawGranEvent(proc, p, name, tso, node, sparkname, len) PEs proc, p; /* proc ... where it happens; p ... where node lives */ GranEventType name; StgTSO *tso; StgClosure *node; StgInt sparkname, len; { # if defined(GRAN) DumpVeryRawGranEvent(TIME_ON_PROC(proc), proc, p, name, tso, node, sparkname, len); # elif defined(PAR) DumpVeryRawGranEvent(CURRENT_TIME, proc, p, name, tso, node, sparkname, len); # endif } //@cindex DumpVeryRawGranEvent void DumpVeryRawGranEvent(time, proc, p, name, tso, node, sparkname, len) rtsTime time; PEs proc, p; /* proc ... where it happens; p ... where node lives */ GranEventType name; StgTSO *tso; StgClosure *node; StgInt sparkname, len; { FILE *output_file; // DEBUGGING ONLY !!!!!!!!!!!!!!!!!!!!!!!!!1 StgWord id; char time_string[TIME_STR_LEN], node_str[NODE_STR_LEN]; # if defined(GRAN) showStgWord64(time, time_string, rtsFalse/*no commas!*/); # elif defined(PAR) showStgWord64(time, time_string, rtsFalse/*no commas!*/); # endif output_file = gr_file; # if defined(GRAN) if (RtsFlags.GranFlags.GranSimStats.Full) ASSERT(output_file!=NULL); if (RtsFlags.GranFlags.GranSimStats.Suppressed) return; # elif defined(PAR) if (RtsFlags.ParFlags.ParStats.Full) ASSERT(output_file!=NULL); if (RtsFlags.ParFlags.ParStats.Suppressed) return; # endif id = tso == NULL ? -1 : tso->id; if (node==stgCast(StgClosure*,&stg_END_TSO_QUEUE_closure)) strcpy(node_str,"________"); /* "END_TSO_QUEUE"); */ else sprintf(node_str,"0x%-6lx",node); if (name > GR_EVENT_MAX) name = GR_EVENT_MAX; if (BINARY_STATS) barf("binary log files not yet supported"); #if 0 /* ToDo: fix code for writing binary GrAnSim statistics */ switch (name) { case GR_START: case GR_STARTQ: grputw(name); grputw(proc); abort(); /* die please: a single word */ /* doesn't represent long long times */ grputw(TIME_ON_PROC(proc)); grputw((StgWord)node); break; case GR_FETCH: case GR_REPLY: case GR_BLOCK: grputw(name); grputw(proc); abort(); /* die please: a single word */ /* doesn't represent long long times */ grputw(TIME_ON_PROC(proc)); /* this line is bound to */ grputw(id); /* do the wrong thing */ break; default: grputw(name); grputw(proc); abort(); /* die please: a single word */ /* doesn't represent long long times */ grputw(TIME_ON_PROC(proc)); grputw((StgWord)node); } #endif else /* !BINARY_STATS */ switch (name) { case GR_START: case GR_STARTQ: fprintf(output_file,"PE %2u [%s]: %-9s\t%lx\t%s\t[SN %u]\t[sparks %u]\n", proc,time_string,gran_event_names[name], id,node_str,sparkname,len); break; case GR_FETCH: case GR_REPLY: case GR_BLOCK: case GR_STOLEN: case GR_STOLENQ: case GR_STEALING: fprintf(output_file, "PE %2u [%s]: %-9s\t%lx \t%s\t(from %2u)\n", proc, time_string, gran_event_names[name], id,node_str,p); break; case GR_RESUME: case GR_RESUMEQ: case GR_SCHEDULE: case GR_DESCHEDULE: fprintf(output_file,"PE %2u [%s]: %-9s\t%lx \n", proc,time_string,gran_event_names[name],id); break; case GR_ALLOC: fprintf(output_file,"PE %2u [%s]: %-9s\t%lx\t \tallocating %u words\n", proc,time_string,gran_event_names[name],id,len); break; default: fprintf(output_file,"PE %2u [%s]: %-9s\t%lx\t%s\t[sparks %u]\n", proc,time_string,gran_event_names[name],id,node_str,len); } } //@cindex DumpGranInfo void DumpEndEvent(proc, tso, mandatory_thread) PEs proc; StgTSO *tso; rtsBool mandatory_thread; { FILE *output_file; // DEBUGGING ONLY !!!!!!!!!!!!!!!!!!!!!!!!!1 char time_string[TIME_STR_LEN]; # if defined(GRAN) showStgWord64(TIME_ON_PROC(proc), time_string, rtsFalse/*no commas!*/); # elif defined(PAR) showStgWord64(CURRENT_TIME, time_string, rtsFalse/*no commas!*/); # endif output_file = gr_file; ASSERT(output_file!=NULL); #if defined(GRAN) if (RtsFlags.GranFlags.GranSimStats.Suppressed) return; #endif if (BINARY_STATS) { barf("binary log files not yet supported"); #if 0 grputw(GR_END); grputw(proc); abort(); /* die please: a single word doesn't represent long long times */ grputw(CURRENT_TIME); /* this line is bound to fail */ grputw(tso->id); #ifdef PAR grputw(0); grputw(0); grputw(0); grputw(0); grputw(0); grputw(0); grputw(0); grputw(0); grputw(0); grputw(0); grputw(0); grputw(0); #else grputw(tso->gran.sparkname); grputw(tso->gran.startedat); grputw(tso->gran.exported); grputw(tso->gran.basicblocks); grputw(tso->gran.allocs); grputw(tso->gran.exectime); grputw(tso->gran.blocktime); grputw(tso->gran.blockcount); grputw(tso->gran.fetchtime); grputw(tso->gran.fetchcount); grputw(tso->gran.localsparks); grputw(tso->gran.globalsparks); #endif grputw(mandatory_thread); #endif /* 0 */ } else { /* * NB: DumpGranEvent cannot be used because PE may be wrong * (as well as the extra info) */ fprintf(output_file, "PE %2u [%s]: END %lx, SN %u, ST %lu, EXP %s, BB %u, HA %u, RT %u, BT %u (%u), FT %u (%u), LS %u, GS %u, MY %s\n" ,proc ,time_string ,tso->id #if defined(GRAN) ,tso->gran.sparkname ,tso->gran.startedat ,((tso->gran.exported) ? 'T' : 'F') ,tso->gran.basicblocks ,tso->gran.allocs ,tso->gran.exectime ,tso->gran.blocktime ,tso->gran.blockcount ,tso->gran.fetchtime ,tso->gran.fetchcount ,tso->gran.localsparks ,tso->gran.globalsparks #elif defined(PAR) ,tso->par.sparkname ,tso->par.startedat ,(tso->par.exported) ? "T" : "F" ,tso->par.basicblocks ,tso->par.allocs ,tso->par.exectime ,tso->par.blocktime ,tso->par.blockcount ,tso->par.fetchtime ,tso->par.fetchcount ,tso->par.localsparks ,tso->par.globalsparks #endif ,(mandatory_thread ? "T" : "F") ); } } //@cindex DumpTSO void DumpTSO(tso) StgTSO *tso; { FILE *output_file; // DEBUGGING ONLY !!!!!!!!!!!!!!!!!!!!!!!!!1 output_file = gr_file; ASSERT(output_file!=NULL); fprintf(stderr,"TSO 0x%lx, NAME 0x%lx, ID %u, LINK 0x%lx, TYPE %s\n" ,tso #if defined(GRAN) ,tso->gran.sparkname #elif defined(PAR) ,tso->par.sparkname #endif ,tso->id ,tso->link ,/*tso->state==T_MAIN?"MAIN": TSO_TYPE(tso)==T_FAIL?"FAIL": TSO_TYPE(tso)==T_REQUIRED?"REQUIRED": TSO_TYPE(tso)==T_ADVISORY?"ADVISORY": */ "???" ); fprintf(output_file,"TSO %lx: SN %u, ST %u, GBL %c, BB %u, HA %u, RT %u, BT %u (%u), FT %u (%u) LS %u, GS %u\n" ,tso->id #if defined(GRAN) ,tso->gran.sparkname ,tso->gran.startedat ,tso->gran.exported?'T':'F' ,tso->gran.basicblocks ,tso->gran.allocs ,tso->gran.exectime ,tso->gran.blocktime ,tso->gran.blockcount ,tso->gran.fetchtime ,tso->gran.fetchcount ,tso->gran.localsparks ,tso->gran.globalsparks #elif defined(PAR) ,tso->par.sparkname ,tso->par.startedat ,tso->par.exported?'T':'F' ,tso->par.basicblocks ,tso->par.allocs ,tso->par.exectime ,tso->par.blocktime ,tso->par.blockcount ,tso->par.fetchtime ,tso->par.fetchcount ,tso->par.localsparks ,tso->par.globalsparks #endif ); } #if 0 /* ToDo: fix binary output of log files, and support new log file format. */ /* Output a terminate event and an 8-byte time. */ //@cindex grterminate void grterminate(v) rtsTime v; { if (!BINARY_STATS) barf("grterminate: binary statistics not enabled\n"); # if defined(GRAN) if (RtsFlags.GranFlags.GranSimStats.Suppressed) return; # endif DumpGranEvent(GR_TERMINATE, stgCast(StgTSO*,&stg_END_TSO_QUEUE_closure)); if (sizeof(rtsTime) == 4) { putc('\0', gr_file); putc('\0', gr_file); putc('\0', gr_file); putc('\0', gr_file); } else { putc(v >> 56l, gr_file); putc((v >> 48l) & 0xffl, gr_file); putc((v >> 40l) & 0xffl, gr_file); putc((v >> 32l) & 0xffl, gr_file); } putc((v >> 24l) & 0xffl, gr_file); putc((v >> 16l) & 0xffl, gr_file); putc((v >> 8l) & 0xffl, gr_file); putc(v & 0xffl, gr_file); } /* Length-coded output: first 3 bits contain length coding 00x 1 byte 01x 2 bytes 10x 4 bytes 110 8 bytes 111 5 or 9 bytes */ //@cindex grputw void grputw(v) rtsTime v; { if (!BINARY_STATS) barf("grputw: binary statistics not enabled\n"); # if defined(GRAN) if (RtsFlags.GranFlags.GranSimStats.Suppressed) return; # endif if (v <= 0x3fl) { /* length v = 1 byte */ fputc(v & 0x3f, gr_file); } else if (v <= 0x3fffl) { /* length v = 2 byte */ fputc((v >> 8l) | 0x40l, gr_file); fputc(v & 0xffl, gr_file); } else if (v <= 0x3fffffffl) { /* length v = 4 byte */ fputc((v >> 24l) | 0x80l, gr_file); fputc((v >> 16l) & 0xffl, gr_file); fputc((v >> 8l) & 0xffl, gr_file); fputc(v & 0xffl, gr_file); } else if (sizeof(TIME) == 4) { fputc(0x70, gr_file); fputc((v >> 24l) & 0xffl, gr_file); fputc((v >> 16l) & 0xffl, gr_file); fputc((v >> 8l) & 0xffl, gr_file); fputc(v & 0xffl, gr_file); } else { if (v <= 0x3fffffffffffffl) putc((v >> 56l) | 0x60l, gr_file); else { putc(0x70, gr_file); putc((v >> 56l) & 0xffl, gr_file); } putc((v >> 48l) & 0xffl, gr_file); putc((v >> 40l) & 0xffl, gr_file); putc((v >> 32l) & 0xffl, gr_file); putc((v >> 24l) & 0xffl, gr_file); putc((v >> 16l) & 0xffl, gr_file); putc((v >> 8l) & 0xffl, gr_file); putc(v & 0xffl, gr_file); } } #endif /* 0 */ /* extracting specific info out of a closure; used in packing (GranSim, GUM) */ //@cindex get_closure_info StgInfoTable* get_closure_info(StgClosure* node, nat *size, nat *ptrs, nat *nonptrs, nat *vhs, char *info_hdr_ty) { StgInfoTable *info; ASSERT(LOOKS_LIKE_COOL_CLOSURE(node)); info = get_itbl(node); /* the switch shouldn't be necessary, really; just use default case */ switch (info->type) { case RBH: { StgInfoTable *rip = REVERT_INFOPTR(info); // closure to revert to *size = sizeW_fromITBL(rip); *ptrs = (nat) (rip->layout.payload.ptrs); *nonptrs = (nat) (rip->layout.payload.nptrs); *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); #if 0 /* DEBUG */ info_hdr_type(node, info_hdr_ty); #else strcpy(info_hdr_ty, "RBH"); #endif return rip; // NB: we return the reverted info ptr for a RBH!!!!!! } #if defined(PAR) /* Closures specific to GUM */ case FETCH_ME: *size = sizeofW(StgFetchMe); *ptrs = (nat)0; *nonptrs = (nat)0; *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); #if 0 /* DEBUG */ info_hdr_type(node, info_hdr_ty); #else strcpy(info_hdr_ty, "FETCH_ME"); #endif return info; #ifdef DIST case REMOTE_REF: //same as for FETCH_ME... *size = sizeofW(StgFetchMe); *ptrs = (nat)0; *nonptrs = (nat)0; *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); #if 0 /* DEBUG */ info_hdr_type(node, info_hdr_ty); #else strcpy(info_hdr_ty, "REMOTE_REF"); #endif return info; #endif /* DIST */ case FETCH_ME_BQ: *size = sizeofW(StgFetchMeBlockingQueue); *ptrs = (nat)0; *nonptrs = (nat)0; *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); #if 0 /* DEBUG */ info_hdr_type(node, info_hdr_ty); #else strcpy(info_hdr_ty, "FETCH_ME_BQ"); #endif return info; case BLOCKED_FETCH: *size = sizeofW(StgBlockedFetch); *ptrs = (nat)0; *nonptrs = (nat)0; *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); #if 0 /* DEBUG */ info_hdr_type(node, info_hdr_ty); #else strcpy(info_hdr_ty, "BLOCKED_FETCH"); #endif return info; #endif /* PAR */ /* these magic constants are outrageous!! why does the ITBL lie about it? */ case THUNK_SELECTOR: *size = THUNK_SELECTOR_sizeW(); *ptrs = 1; *nonptrs = MIN_UPD_SIZE-*ptrs; // weird *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); return info; case ARR_WORDS: /* ToDo: check whether this can be merged with the default case */ *size = arr_words_sizeW((StgArrWords *)node); *ptrs = 0; *nonptrs = arr_words_words(((StgArrWords *)node)); *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); return info; case PAP: /* ToDo: check whether this can be merged with the default case */ *size = pap_sizeW((StgPAP *)node); *ptrs = 0; *nonptrs = 0; *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); return info; case AP_UPD: /* ToDo: check whether this can be merged with the default case */ *size = AP_sizeW(((StgAP_UPD *)node)->n_args); *ptrs = 0; *nonptrs = 0; *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); return info; default: *size = sizeW_fromITBL(info); *ptrs = (nat) (info->layout.payload.ptrs); *nonptrs = (nat) (info->layout.payload.nptrs); *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); #if 0 /* DEBUG */ info_hdr_type(node, info_hdr_ty); #else strcpy(info_hdr_ty, "UNKNOWN"); #endif return info; } } //@cindex IS_BLACK_HOLE rtsBool IS_BLACK_HOLE(StgClosure* node) { // StgInfoTable *info; ASSERT(LOOKS_LIKE_COOL_CLOSURE(node)); switch (get_itbl(node)->type) { case BLACKHOLE: case BLACKHOLE_BQ: case RBH: case FETCH_ME: case FETCH_ME_BQ: return rtsTrue; default: return rtsFalse; } //return ((info->type == BLACKHOLE || info->type == RBH) ? rtsTrue : rtsFalse); } //@cindex IS_INDIRECTION StgClosure * IS_INDIRECTION(StgClosure* node) { StgInfoTable *info; ASSERT(LOOKS_LIKE_COOL_CLOSURE(node)); info = get_itbl(node); switch (info->type) { case IND: case IND_OLDGEN: case IND_PERM: case IND_OLDGEN_PERM: case IND_STATIC: /* relies on indirectee being at same place for all these closure types */ return (((StgInd*)node) -> indirectee); #if 0 case EVACUATED: // counting as ind to use in GC routines, too // could use the same code as above (evacuee is at same pos as indirectee) return (((StgEvacuated *)node) -> evacuee); #endif default: return NULL; } } //@cindex unwindInd StgClosure * UNWIND_IND (StgClosure *closure) { StgClosure *next; while ((next = IS_INDIRECTION((StgClosure *)closure)) != NULL) closure = next; ASSERT(next==(StgClosure *)NULL); ASSERT(LOOKS_LIKE_COOL_CLOSURE(closure)); return closure; } #endif /* GRAN || PAR whole file */