X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FProfHeap.c;h=a50f2f0ac76f2ad3c507f969ab48ccd4ca494cc7;hb=beb5737b7ee42c4e9373a505e7d957206d69a30e;hp=19beb9cba633f477c633658b2186691eb4deb75f;hpb=cffcb52b7b7518db39d64394270392d06215cf90;p=ghc-hetmet.git diff --git a/ghc/rts/ProfHeap.c b/ghc/rts/ProfHeap.c index 19beb9c..a50f2f0 100644 --- a/ghc/rts/ProfHeap.c +++ b/ghc/rts/ProfHeap.c @@ -1,5 +1,4 @@ /* ----------------------------------------------------------------------------- - * $Id: ProfHeap.c,v 1.47 2003/08/22 22:24:12 sof Exp $ * * (c) The GHC Team, 1998-2003 * @@ -24,7 +23,6 @@ #include "ProfHeap.h" #include "Stats.h" #include "Hash.h" -#include "StrHash.h" #include "RetainerProfile.h" #include "LdvProfile.h" #include "Arena.h" @@ -32,6 +30,7 @@ #include #include +#include /* ----------------------------------------------------------------------------- * era stores the current time period. It is the same as the @@ -46,7 +45,7 @@ * When era reaches max_era, the profiling stops because a closure can * store only up to (max_era - 1) as its creation or last use time. * -------------------------------------------------------------------------- */ -nat era; +unsigned int era; static nat max_era; /* ----------------------------------------------------------------------------- @@ -72,7 +71,7 @@ typedef struct _counter { struct _counter *next; } counter; -static inline void +STATIC_INLINE void initLDVCtr( counter *ctr ) { ctr->c.ldv.prim = 0; @@ -150,17 +149,17 @@ static char *type_names[] = { , "STOP_FRAME" , "BLACKHOLE" - , "BLACKHOLE_BQ" , "MVAR" , "ARR_WORDS" - , "MUT_ARR_PTRS" + , "MUT_ARR_PTRS_CLEAN" + , "MUT_ARR_PTRS_DIRTY" , "MUT_ARR_PTRS_FROZEN" - , "MUT_VAR" + , "MUT_VAR_CLEAN" + , "MUT_VAR_DIRTY" , "WEAK" - , "FOREIGN" , "TSO" @@ -177,7 +176,7 @@ static char *type_names[] = { * the band to which this closure's heap space is attributed in the * heap profile. * ------------------------------------------------------------------------- */ -static inline void * +STATIC_INLINE void * closureIdentity( StgClosure *p ) { switch (RtsFlags.ProfFlags.doHeapProfile) { @@ -215,20 +214,20 @@ closureIdentity( StgClosure *p ) * Profiling type predicates * ----------------------------------------------------------------------- */ #ifdef PROFILING -static inline rtsBool +STATIC_INLINE rtsBool doingLDVProfiling( void ) { return (RtsFlags.ProfFlags.doHeapProfile == HEAP_BY_LDV || RtsFlags.ProfFlags.bioSelector != NULL); } -static inline rtsBool +STATIC_INLINE rtsBool doingRetainerProfiling( void ) { return (RtsFlags.ProfFlags.doHeapProfile == HEAP_BY_RETAINER || RtsFlags.ProfFlags.retainerSelector != NULL); } -#endif // PROFILING +#endif /* PROFILING */ // Precesses a closure 'c' being destroyed whose size is 'size'. // Make sure that LDV_recordDead() is not invoked on 'inherently used' closures @@ -249,6 +248,7 @@ LDV_recordDead( StgClosure *c, nat size ) if (era > 0 && closureSatisfiesConstraints(c)) { size -= sizeofW(StgProfHeader); + ASSERT(LDVW(c) != 0); if ((LDVW((c)) & LDV_STATE_MASK) == LDV_STATE_CREATE) { t = (LDVW((c)) & LDV_CREATE_MASK) >> LDV_SHIFT; if (t < era) { @@ -304,7 +304,7 @@ LDV_recordDead( StgClosure *c, nat size ) /* -------------------------------------------------------------------------- * Initialize censuses[era]; * ----------------------------------------------------------------------- */ -static inline void +STATIC_INLINE void initEra(Census *census) { census->hash = allocHashTable(); @@ -330,7 +330,7 @@ nextEra( void ) era++; if (era == max_era) { - prog_belch("maximum number of censuses reached; use +RTS -i to reduce"); + errorBelch("maximum number of censuses reached; use +RTS -i to reduce"); stg_exit(EXIT_FAILURE); } @@ -340,7 +340,7 @@ nextEra( void ) "nextEra"); } } -#endif // PROFILING +#endif /* PROFILING */ initEra( &censuses[era] ); } @@ -351,6 +351,7 @@ nextEra( void ) #ifdef DEBUG_HEAP_PROF FILE *hp_file; +static char *hp_filename; void initProfiling1( void ) { @@ -358,6 +359,20 @@ void initProfiling1( void ) void initProfiling2( void ) { + if (RtsFlags.ProfFlags.doHeapProfile) { + /* Initialise the log file name */ + hp_filename = stgMallocBytes(strlen(prog_name) + 6, "hpFileName"); + sprintf(hp_filename, "%s.hp", prog_name); + + /* open the log file */ + if ((hp_file = fopen(hp_filename, "w")) == NULL) { + debugBelch("Can't open profiling report file %s\n", + hp_filename); + RtsFlags.ProfFlags.doHeapProfile = 0; + return; + } + } + initHeapProfiling(); } @@ -367,6 +382,16 @@ void endProfiling( void ) } #endif /* DEBUG_HEAP_PROF */ +static void +printSample(rtsBool beginSample, StgDouble sampleValue) +{ + StgDouble fractionalPart, integralPart; + fractionalPart = modf(sampleValue, &integralPart); + fprintf(hp_file, "%s %d.%02d\n", + (beginSample ? "BEGIN_SAMPLE" : "END_SAMPLE"), + (int)integralPart, (int)(fractionalPart * 100)); +} + /* -------------------------------------------------------------------------- * Initialize the heap profilier * ----------------------------------------------------------------------- */ @@ -379,8 +404,8 @@ initHeapProfiling(void) #ifdef PROFILING if (doingLDVProfiling() && doingRetainerProfiling()) { - prog_belch("cannot mix -hb and -hr"); - stg_exit(1); + errorBelch("cannot mix -hb and -hr"); + stg_exit(EXIT_FAILURE); } #endif @@ -407,6 +432,7 @@ initHeapProfiling(void) initEra( &censuses[era] ); + /* initProfilingLogFile(); */ fprintf(hp_file, "JOB \"%s", prog_name); #ifdef PROFILING @@ -414,10 +440,9 @@ initHeapProfiling(void) int count; for(count = 1; count < prog_argc; count++) fprintf(hp_file, " %s", prog_argv[count]); - fprintf(hp_file, " +RTS "); + fprintf(hp_file, " +RTS"); for(count = 0; count < rts_argc; count++) - fprintf(hp_file, "%s ", rts_argv[count]); - fprintf(hp_file, "\n"); + fprintf(hp_file, " %s", rts_argv[count]); } #endif /* PROFILING */ @@ -428,8 +453,8 @@ initHeapProfiling(void) fprintf(hp_file, "SAMPLE_UNIT \"seconds\"\n"); fprintf(hp_file, "VALUE_UNIT \"bytes\"\n"); - fprintf(hp_file, "BEGIN_SAMPLE 0.00\n"); - fprintf(hp_file, "END_SAMPLE 0.00\n"); + printSample(rtsTrue, 0); + printSample(rtsFalse, 0); #ifdef DEBUG_HEAP_PROF DEBUG_LoadSymbols(prog_name); @@ -471,8 +496,8 @@ endHeapProfiling(void) #endif seconds = mut_user_time(); - fprintf(hp_file, "BEGIN_SAMPLE %0.2f\n", seconds); - fprintf(hp_file, "END_SAMPLE %0.2f\n", seconds); + printSample(rtsTrue, seconds); + printSample(rtsFalse, seconds); fclose(hp_file); } @@ -495,8 +520,6 @@ static void fprint_ccs(FILE *fp, CostCentreStack *ccs, nat max_length) { char buf[max_length+1], *p, *buf_end; - nat next_offset = 0; - nat written; // MAIN on its own gets printed as "MAIN", otherwise we ignore MAIN. if (ccs == CCS_MAIN) { @@ -504,7 +527,7 @@ fprint_ccs(FILE *fp, CostCentreStack *ccs, nat max_length) return; } - fprintf(fp, "(%d)", ccs->ccsID); + fprintf(fp, "(%ld)", ccs->ccsID); p = buf; buf_end = buf + max_length + 1; @@ -528,19 +551,17 @@ fprint_ccs(FILE *fp, CostCentreStack *ccs, nat max_length) if (p >= buf_end) { sprintf(buf+max_length-4, "..."); break; - } else { - next_offset += written; } } fprintf(fp, "%s", buf); } -#endif // PROFILING +#endif /* PROFILING */ rtsBool strMatchesSelector( char* str, char* sel ) { char* p; - // fprintf(stderr, "str_matches_selector %s %s\n", str, sel); + // debugBelch("str_matches_selector %s %s\n", str, sel); while (1) { // Compare str against wherever we've got to in sel. p = str; @@ -568,6 +589,7 @@ rtsBool closureSatisfiesConstraints( StgClosure* p ) { #ifdef DEBUG_HEAP_PROF + (void)p; /* keep gcc -Wall happy */ return rtsTrue; #else rtsBool b; @@ -668,8 +690,8 @@ aggregateCensusInfo( void ) // totals *must* be zero. ASSERT(c->c.ldv.void_total == 0 && c->c.ldv.drag_total == 0); - // fprintCCS(stderr,c->identity); - // fprintf(stderr," census=%d void_total=%d drag_total=%d\n", + // debugCCS(c->identity); + // debugBelch(" census=%d void_total=%d drag_total=%d\n", // t, c->c.ldv.void_total, c->c.ldv.drag_total); } else { d->c.ldv.void_total += c->c.ldv.void_total; @@ -714,20 +736,20 @@ dumpCensus( Census *census ) counter *ctr; int count; - fprintf(hp_file, "BEGIN_SAMPLE %0.2f\n", census->time); + printSample(rtsTrue, census->time); #ifdef PROFILING if (RtsFlags.ProfFlags.doHeapProfile == HEAP_BY_LDV) { - fprintf(hp_file, "VOID\t%u\n", census->void_total * sizeof(W_)); - fprintf(hp_file, "LAG\t%u\n", - (census->not_used - census->void_total) * sizeof(W_)); - fprintf(hp_file, "USE\t%u\n", - (census->used - census->drag_total) * sizeof(W_)); - fprintf(hp_file, "INHERENT_USE\t%u\n", - census->prim * sizeof(W_)); - fprintf(hp_file, "DRAG\t%u\n", census->drag_total * - sizeof(W_)); - fprintf(hp_file, "END_SAMPLE %0.2f\n", census->time); + fprintf(hp_file, "VOID\t%lu\n", (unsigned long)(census->void_total) * sizeof(W_)); + fprintf(hp_file, "LAG\t%lu\n", + (unsigned long)(census->not_used - census->void_total) * sizeof(W_)); + fprintf(hp_file, "USE\t%lu\n", + (unsigned long)(census->used - census->drag_total) * sizeof(W_)); + fprintf(hp_file, "INHERENT_USE\t%lu\n", + (unsigned long)(census->prim) * sizeof(W_)); + fprintf(hp_file, "DRAG\t%lu\n", + (unsigned long)(census->drag_total) * sizeof(W_)); + printSample(rtsFalse, census->time); return; } #endif @@ -804,10 +826,10 @@ dumpCensus( Census *census ) } #endif - fprintf(hp_file, "\t%d\n", count * sizeof(W_)); + fprintf(hp_file, "\t%lu\n", (unsigned long)count * sizeof(W_)); } - fprintf(hp_file, "END_SAMPLE %0.2f\n", census->time); + printSample(rtsFalse, census->time); } /* ----------------------------------------------------------------------------- @@ -825,6 +847,15 @@ heapCensusChain( Census *census, bdescr *bd ) rtsBool prim; for (; bd != NULL; bd = bd->link) { + + // HACK: ignore pinned blocks, because they contain gaps. + // It's not clear exactly what we'd like to do here, since we + // can't tell which objects in the block are actually alive. + // Perhaps the whole block should be counted as SYSTEM memory. + if (bd->flags & BF_PINNED) { + continue; + } + p = bd->start; while (p < bd->free) { info = get_itbl((StgClosure *)p); @@ -832,9 +863,24 @@ heapCensusChain( Census *census, bdescr *bd ) switch (info->type) { + case THUNK: + size = thunk_sizeW_fromITBL(info); + break; + + case THUNK_1_1: + case THUNK_0_2: + case THUNK_2_0: + size = sizeofW(StgThunkHeader) + 2; + break; + + case THUNK_1_0: + case THUNK_0_1: + case THUNK_SELECTOR: + size = sizeofW(StgThunkHeader) + 1; + break; + case CONSTR: case FUN: - case THUNK: case IND_PERM: case IND_OLDGEN: case IND_OLDGEN_PERM: @@ -842,7 +888,6 @@ heapCensusChain( Census *census, bdescr *bd ) case SE_CAF_BLACKHOLE: case SE_BLACKHOLE: case BLACKHOLE: - case BLACKHOLE_BQ: case CONSTR_INTLIKE: case CONSTR_CHARLIKE: case FUN_1_0: @@ -850,9 +895,6 @@ heapCensusChain( Census *census, bdescr *bd ) case FUN_1_1: case FUN_0_2: case FUN_2_0: - case THUNK_1_1: - case THUNK_0_2: - case THUNK_2_0: case CONSTR_1_0: case CONSTR_0_1: case CONSTR_1_1: @@ -860,7 +902,18 @@ heapCensusChain( Census *census, bdescr *bd ) case CONSTR_2_0: size = sizeW_fromITBL(info); break; - + + case IND: + // Special case/Delicate Hack: INDs don't normally + // appear, since we're doing this heap census right + // after GC. However, GarbageCollect() also does + // resurrectThreads(), which can update some + // blackholes when it calls raiseAsync() on the + // resurrected threads. So we know that any IND will + // be the size of a BLACKHOLE. + size = BLACKHOLE_sizeW(); + break; + case BCO: prim = rtsTrue; size = bco_sizeW((StgBCO *)p); @@ -868,21 +921,17 @@ heapCensusChain( Census *census, bdescr *bd ) case MVAR: case WEAK: - case FOREIGN: case STABLE_NAME: - case MUT_VAR: - case MUT_CONS: + case MUT_VAR_CLEAN: + case MUT_VAR_DIRTY: prim = rtsTrue; size = sizeW_fromITBL(info); break; - case THUNK_1_0: /* ToDo - shouldn't be here */ - case THUNK_0_1: /* " ditto " */ - case THUNK_SELECTOR: - size = sizeofW(StgHeader) + MIN_UPD_SIZE; + case AP: + size = ap_sizeW((StgAP *)p); break; - case AP: case PAP: size = pap_sizeW((StgPAP *)p); break; @@ -896,8 +945,10 @@ heapCensusChain( Census *census, bdescr *bd ) size = arr_words_sizeW(stgCast(StgArrWords*,p)); break; - case MUT_ARR_PTRS: + case MUT_ARR_PTRS_CLEAN: + case MUT_ARR_PTRS_DIRTY: case MUT_ARR_PTRS_FROZEN: + case MUT_ARR_PTRS_FROZEN0: prim = rtsTrue; size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p); break; @@ -918,8 +969,28 @@ heapCensusChain( Census *census, bdescr *bd ) } #endif + case TREC_HEADER: + prim = rtsTrue; + size = sizeofW(StgTRecHeader); + break; + + case TVAR_WAIT_QUEUE: + prim = rtsTrue; + size = sizeofW(StgTVarWaitQueue); + break; + + case TVAR: + prim = rtsTrue; + size = sizeofW(StgTVar); + break; + + case TREC_CHUNK: + prim = rtsTrue; + size = sizeofW(StgTRecChunk); + break; + default: - barf("heapCensus"); + barf("heapCensus, unknown object: %d", info->type); } identity = NULL; @@ -1021,7 +1092,7 @@ heapCensus( void ) // Now traverse the heap in each generation/step. if (RtsFlags.GcFlags.generations == 1) { - heapCensusChain( census, g0s0->to_blocks ); + heapCensusChain( census, g0s0->blocks ); } else { for (g = 0; g < RtsFlags.GcFlags.generations; g++) { for (s = 0; s < generations[g].n_steps; s++) {