#include "ProfHeap.h"
#include "Stats.h"
#include "Hash.h"
-#include "StrHash.h"
#include "RetainerProfile.h"
#include "LdvProfile.h"
#include "Arena.h"
* 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;
/* -----------------------------------------------------------------------------
, "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"
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
if (RtsFlags.ProfFlags.bioSelector == NULL) {
censuses[t].void_total += (int)size;
censuses[era].void_total -= (int)size;
+ ASSERT(censuses[t].void_total < censuses[t].not_used);
} else {
id = closureIdentity(c);
ctr = lookupHashTable(censuses[t].hash, (StgWord)id);
"nextEra");
}
}
-#endif // PROFILING
+#endif /* PROFILING */
initEra( &censuses[era] );
}
fractionalPart = modf(sampleValue, &integralPart);
fprintf(hp_file, "%s %d.%02d\n",
(beginSample ? "BEGIN_SAMPLE" : "END_SAMPLE"),
- (int)integralPart, (int)(fractionalPart * 100 + 0.5));
+ (int)integralPart, (int)(fractionalPart * 100));
}
/* --------------------------------------------------------------------------
#ifdef PROFILING
if (doingLDVProfiling() && doingRetainerProfiling()) {
errorBelch("cannot mix -hb and -hr");
- stg_exit(1);
+ stg_exit(EXIT_FAILURE);
}
#endif
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) {
return;
}
- fprintf(fp, "(%d)", ccs->ccsID);
+ fprintf(fp, "(%ld)", ccs->ccsID);
p = buf;
buf_end = buf + max_length + 1;
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 )
int void_total, drag_total;
// Now we compute void_total and drag_total for each census
+ // After the program has finished, the void_total field of
+ // each census contains the count of words that were *created*
+ // in this era and were eventually void. Conversely, if a
+ // void closure was destroyed in this era, it will be
+ // represented by a negative count of words in void_total.
+ //
+ // To get the count of live words that are void at each
+ // census, just propagate the void_total count forwards:
+
void_total = 0;
drag_total = 0;
for (t = 1; t < era; t++) { // note: start at 1, not 0
drag_total += censuses[t].drag_total;
censuses[t].void_total = void_total;
censuses[t].drag_total = drag_total;
+
ASSERT( censuses[t].void_total <= censuses[t].not_used );
+ // should be true because: void_total is the count of
+ // live words that are void at this census, which *must*
+ // be less than the number of live words that have not
+ // been used yet.
+
ASSERT( censuses[t].drag_total <= censuses[t].used );
+ // similar reasoning as above.
}
return;
#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, "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
- fprintf(hp_file, "\t%d\n", count * sizeof(W_));
+ fprintf(hp_file, "\t%lu\n", (unsigned long)count * sizeof(W_));
}
printSample(rtsFalse, census->time);
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:
case SE_CAF_BLACKHOLE:
case SE_BLACKHOLE:
case BLACKHOLE:
- case BLACKHOLE_BQ:
case CONSTR_INTLIKE:
case CONSTR_CHARLIKE:
case FUN_1_0:
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:
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);
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;
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;
}
#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;
// 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++) {