-/* -----------------------------------------------------------------------------
+/* ----------------------------------------------------------------------------
*
* (c) The GHC Team, 1998-2003
*
* Support for heap profiling
*
- * ---------------------------------------------------------------------------*/
-
-#if defined(DEBUG) && !defined(PROFILING)
-#define DEBUG_HEAP_PROF
-#else
-#undef DEBUG_HEAP_PROF
-#endif
-
-#if defined(PROFILING) || defined(DEBUG_HEAP_PROF)
+ * --------------------------------------------------------------------------*/
#include "PosixSource.h"
#include "Rts.h"
+
#include "RtsUtils.h"
-#include "RtsFlags.h"
#include "Profiling.h"
-#include "Storage.h"
#include "ProfHeap.h"
#include "Stats.h"
#include "Hash.h"
#include "Printer.h"
#include <string.h>
-#include <stdlib.h>
-#include <math.h>
/* -----------------------------------------------------------------------------
* era stores the current time period. It is the same as the
static void dumpCensus( Census *census );
-/* -----------------------------------------------------------------------------
- Closure Type Profiling;
-
- PROBABLY TOTALLY OUT OF DATE -- ToDo (SDM)
- -------------------------------------------------------------------------- */
-
-#ifdef DEBUG_HEAP_PROF
-static char *type_names[] = {
- "INVALID_OBJECT"
- , "CONSTR"
- , "CONSTR_INTLIKE"
- , "CONSTR_CHARLIKE"
- , "CONSTR_STATIC"
- , "CONSTR_NOCAF_STATIC"
-
- , "FUN"
- , "FUN_STATIC"
-
- , "THUNK"
- , "THUNK_STATIC"
- , "THUNK_SELECTOR"
-
- , "BCO"
- , "AP_STACK"
- , "AP"
-
- , "PAP"
-
- , "IND"
- , "IND_OLDGEN"
- , "IND_PERM"
- , "IND_OLDGEN_PERM"
- , "IND_STATIC"
-
- , "RET_BCO"
- , "RET_SMALL"
- , "RET_VEC_SMALL"
- , "RET_BIG"
- , "RET_VEC_BIG"
- , "RET_DYN"
- , "UPDATE_FRAME"
- , "CATCH_FRAME"
- , "STOP_FRAME"
-
- , "BLACKHOLE"
- , "MVAR"
-
- , "ARR_WORDS"
-
- , "MUT_ARR_PTRS_CLEAN"
- , "MUT_ARR_PTRS_DIRTY"
- , "MUT_ARR_PTRS_FROZEN"
- , "MUT_VAR_CLEAN"
- , "MUT_VAR_DIRTY"
-
- , "WEAK"
-
- , "TSO"
-
- , "BLOCKED_FETCH"
- , "FETCH_ME"
-
- , "EVACUATED"
-};
+static rtsBool closureSatisfiesConstraints( StgClosure* p );
-#endif /* DEBUG_HEAP_PROF */
-
-/* -----------------------------------------------------------------------------
+/* ----------------------------------------------------------------------------
* Find the "closure identity", which is a unique pointer reresenting
* the band to which this closure's heap space is attributed in the
* heap profile.
* ------------------------------------------------------------------------- */
-STATIC_INLINE void *
+static void *
closureIdentity( StgClosure *p )
{
switch (RtsFlags.ProfFlags.doHeapProfile) {
case HEAP_BY_MOD:
return p->header.prof.ccs->cc->module;
case HEAP_BY_DESCR:
- return get_itbl(p)->prof.closure_desc;
+ return GET_PROF_DESC(get_itbl(p));
case HEAP_BY_TYPE:
- return get_itbl(p)->prof.closure_type;
+ return GET_PROF_TYPE(get_itbl(p));
case HEAP_BY_RETAINER:
// AFAIK, the only closures in the heap which might not have a
// valid retainer set are DEAD_WEAK closures.
else
return NULL;
-#else // DEBUG
- case HEAP_BY_INFOPTR:
- return (void *)((StgClosure *)p)->header.info;
+#else
case HEAP_BY_CLOSURE_TYPE:
- return type_names[get_itbl(p)->type];
+ {
+ StgInfoTable *info;
+ info = get_itbl(p);
+ switch (info->type) {
+ case CONSTR:
+ case CONSTR_1_0:
+ case CONSTR_0_1:
+ case CONSTR_2_0:
+ case CONSTR_1_1:
+ case CONSTR_0_2:
+ case CONSTR_STATIC:
+ case CONSTR_NOCAF_STATIC:
+ return GET_CON_DESC(itbl_to_con_itbl(info));
+ default:
+ return closure_type_names[info->type];
+ }
+ }
#endif
default:
/* --------------------------------------------------------------------------
* Initialize censuses[era];
* ----------------------------------------------------------------------- */
+
STATIC_INLINE void
initEra(Census *census)
{
census->drag_total = 0;
}
+STATIC_INLINE void
+freeEra(Census *census)
+{
+ if (RtsFlags.ProfFlags.bioSelector != NULL)
+ // when bioSelector==NULL, these are freed in heapCensus()
+ {
+ arenaFree(census->arena);
+ freeHashTable(census->hash, NULL);
+ }
+}
+
/* --------------------------------------------------------------------------
* Increases era by 1 and initialize census[era].
* Reallocates gi[] and increases its size if needed.
* ----------------------------------------------------------------------- */
+
static void
nextEra( void )
{
initEra( &censuses[era] );
}
-/* -----------------------------------------------------------------------------
- * DEBUG heap profiling, by info table
- * -------------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------------
+ * Heap profiling by info table
+ * ------------------------------------------------------------------------- */
-#ifdef DEBUG_HEAP_PROF
+#if !defined(PROFILING)
FILE *hp_file;
static char *hp_filename;
-void initProfiling1( void )
+void initProfiling1 (void)
{
}
-void initProfiling2( void )
+void freeProfiling (void)
{
+}
+
+void initProfiling2 (void)
+{
+ char *prog;
+
+ prog = stgMallocBytes(strlen(prog_name) + 1, "initProfiling2");
+ strcpy(prog, prog_name);
+#ifdef mingw32_HOST_OS
+ // on Windows, drop the .exe suffix if there is one
+ {
+ char *suff;
+ suff = strrchr(prog,'.');
+ if (suff != NULL && !strcmp(suff,".exe")) {
+ *suff = '\0';
+ }
+ }
+#endif
+
if (RtsFlags.ProfFlags.doHeapProfile) {
/* Initialise the log file name */
- hp_filename = stgMallocBytes(strlen(prog_name) + 6, "hpFileName");
- sprintf(hp_filename, "%s.hp", prog_name);
+ hp_filename = stgMallocBytes(strlen(prog) + 6, "hpFileName");
+ sprintf(hp_filename, "%s.hp", prog);
/* open the log file */
if ((hp_file = fopen(hp_filename, "w")) == NULL) {
}
}
+ stgFree(prog);
+
initHeapProfiling();
}
{
endHeapProfiling();
}
-#endif /* DEBUG_HEAP_PROF */
+#endif /* !PROFILING */
static void
printSample(rtsBool beginSample, StgDouble sampleValue)
{
StgDouble fractionalPart, integralPart;
fractionalPart = modf(sampleValue, &integralPart);
- fprintf(hp_file, "%s %d.%02d\n",
+ fprintf(hp_file, "%s %" FMT_Word64 ".%02" FMT_Word64 "\n",
(beginSample ? "BEGIN_SAMPLE" : "END_SAMPLE"),
- (int)integralPart, (int)(fractionalPart * 100));
+ (StgWord64)integralPart, (StgWord64)(fractionalPart * 100));
}
/* --------------------------------------------------------------------------
era = 0;
}
- { // max_era = 2^LDV_SHIFT
- nat p;
- max_era = 1;
- for (p = 0; p < LDV_SHIFT; p++)
- max_era *= 2;
- }
+ // max_era = 2^LDV_SHIFT
+ max_era = 1 << LDV_SHIFT;
n_censuses = 32;
censuses = stgMallocBytes(sizeof(Census) * n_censuses, "initHeapProfiling");
printSample(rtsTrue, 0);
printSample(rtsFalse, 0);
-#ifdef DEBUG_HEAP_PROF
- DEBUG_LoadSymbols(prog_name);
-#endif
-
#ifdef PROFILING
if (doingRetainerProfiling()) {
initRetainerProfiling();
}
#endif
+#ifdef PROFILING
+ if (doingLDVProfiling()) {
+ nat t;
+ for (t = 1; t <= era; t++) {
+ freeEra( &censuses[t] );
+ }
+ } else {
+ freeEra( &censuses[0] );
+ }
+#else
+ freeEra( &censuses[0] );
+#endif
+
+ stgFree(censuses);
+
seconds = mut_user_time();
printSample(rtsTrue, seconds);
printSample(rtsFalse, seconds);
p += buf_append(p, ccs->cc->module, buf_end);
p += buf_append(p, ".CAF", buf_end);
} else {
+ p += buf_append(p, ccs->cc->label, buf_end);
if (ccs->prevStack != NULL && ccs->prevStack != CCS_MAIN) {
p += buf_append(p, "/", buf_end);
}
- p += buf_append(p, ccs->cc->label, buf_end);
}
if (p >= buf_end) {
}
fprintf(fp, "%s", buf);
}
-#endif /* PROFILING */
rtsBool
strMatchesSelector( char* str, char* sel )
}
}
+#endif /* PROFILING */
+
/* -----------------------------------------------------------------------------
* Figure out whether a closure should be counted in this census, by
* testing against all the specified constraints.
* -------------------------------------------------------------------------- */
-rtsBool
+static rtsBool
closureSatisfiesConstraints( StgClosure* p )
{
-#ifdef DEBUG_HEAP_PROF
+#if !defined(PROFILING)
(void)p; /* keep gcc -Wall happy */
return rtsTrue;
#else
}
if (RtsFlags.ProfFlags.descrSelector) {
- b = strMatchesSelector( (get_itbl((StgClosure *)p))->prof.closure_desc,
+ b = strMatchesSelector( (GET_PROF_DESC(get_itbl((StgClosure *)p))),
RtsFlags.ProfFlags.descrSelector );
if (!b) return rtsFalse;
}
if (RtsFlags.ProfFlags.typeSelector) {
- b = strMatchesSelector( (get_itbl((StgClosure *)p))->prof.closure_type,
+ b = strMatchesSelector( (GET_PROF_TYPE(get_itbl((StgClosure *)p))),
RtsFlags.ProfFlags.typeSelector );
if (!b) return rtsFalse;
}
if (count == 0) continue;
-#ifdef DEBUG_HEAP_PROF
+#if !defined(PROFILING)
switch (RtsFlags.ProfFlags.doHeapProfile) {
- case HEAP_BY_INFOPTR:
- fprintf(hp_file, "%s", lookupGHCName(ctr->identity));
- break;
case HEAP_BY_CLOSURE_TYPE:
fprintf(hp_file, "%s", (char *)ctr->identity);
break;
#ifdef PROFILING
switch (RtsFlags.ProfFlags.doHeapProfile) {
case HEAP_BY_CCS:
- fprint_ccs(hp_file, (CostCentreStack *)ctr->identity, 25);
+ fprint_ccs(hp_file, (CostCentreStack *)ctr->identity, RtsFlags.ProfFlags.ccsLength);
break;
case HEAP_BY_MOD:
case HEAP_BY_DESCR:
case CONSTR:
case FUN:
case IND_PERM:
- case IND_OLDGEN:
- case IND_OLDGEN_PERM:
- case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
case BLACKHOLE:
- case CONSTR_INTLIKE:
- case CONSTR_CHARLIKE:
+ case BLOCKING_QUEUE:
case FUN_1_0:
case FUN_0_1:
case FUN_1_1:
size = bco_sizeW((StgBCO *)p);
break;
- case MVAR:
+ case MVAR_CLEAN:
+ case MVAR_DIRTY:
case WEAK:
- case STABLE_NAME:
+ case PRIM:
+ case MUT_PRIM:
case MUT_VAR_CLEAN:
case MUT_VAR_DIRTY:
prim = rtsTrue;
case ARR_WORDS:
prim = rtsTrue;
- size = arr_words_sizeW(stgCast(StgArrWords*,p));
+ size = arr_words_sizeW((StgArrWords*)p);
break;
case MUT_ARR_PTRS_CLEAN:
case TSO:
prim = rtsTrue;
-#ifdef DEBUG_HEAP_PROF
- size = tso_sizeW((StgTSO *)p);
- break;
-#else
+#ifdef PROFILING
if (RtsFlags.ProfFlags.includeTSOs) {
- size = tso_sizeW((StgTSO *)p);
+ size = sizeofW(StgTSO);
break;
} else {
// Skip this TSO and move on to the next object
- p += tso_sizeW((StgTSO *)p);
+ p += sizeofW(StgTSO);
continue;
}
+#else
+ size = sizeofW(StgTSO);
+ break;
#endif
- case TREC_HEADER:
+ case STACK:
prim = rtsTrue;
- size = sizeofW(StgTRecHeader);
+#ifdef PROFILING
+ if (RtsFlags.ProfFlags.includeTSOs) {
+ size = stack_sizeW((StgStack*)p);
+ break;
+ } else {
+ // Skip this TSO and move on to the next object
+ p += stack_sizeW((StgStack*)p);
+ continue;
+ }
+#else
+ size = stack_sizeW((StgStack*)p);
break;
+#endif
- case TVAR_WAIT_QUEUE:
- prim = rtsTrue;
- size = sizeofW(StgTVarWaitQueue);
- break;
-
- case TVAR:
- prim = rtsTrue;
- size = sizeofW(StgTVar);
- break;
-
- case TREC_CHUNK:
+ case TREC_CHUNK:
prim = rtsTrue;
size = sizeofW(StgTRecChunk);
break;
identity = NULL;
-#ifdef DEBUG_HEAP_PROF
- real_size = size;
-#else
+#ifdef PROFILING
// subtract the profiling overhead
real_size = size - sizeofW(StgProfHeader);
+#else
+ real_size = size;
#endif
if (closureSatisfiesConstraints((StgClosure*)p)) {
void
heapCensus( void )
{
- nat g, s;
+ nat g;
Census *census;
census = &censuses[era];
#endif
// Traverse the heap, collecting the census info
-
- // First the small_alloc_list: we have to fix the free pointer at
- // the end by calling tidyAllocatedLists() first.
- tidyAllocateLists();
- heapCensusChain( census, small_alloc_list );
-
- // Now traverse the heap in each generation/step.
- if (RtsFlags.GcFlags.generations == 1) {
- heapCensusChain( census, g0s0->blocks );
- } else {
- for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
- for (s = 0; s < generations[g].n_steps; s++) {
- heapCensusChain( census, generations[g].steps[s].blocks );
- // Are we interested in large objects? might be
- // confusing to include the stack in a heap profile.
- heapCensusChain( census, generations[g].steps[s].large_objects );
- }
- }
+ for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
+ heapCensusChain( census, generations[g].blocks );
+ // Are we interested in large objects? might be
+ // confusing to include the stack in a heap profile.
+ heapCensusChain( census, generations[g].large_objects );
}
// dump out the census info
// future restriction by biography.
#ifdef PROFILING
if (RtsFlags.ProfFlags.bioSelector == NULL)
-#endif
{
freeHashTable( census->hash, NULL/* don't free the elements */ );
arenaFree( census->arena );
census->hash = NULL;
census->arena = NULL;
}
+#endif
// we're into the next time period now
nextEra();
#endif
}
-#endif /* PROFILING || DEBUG_HEAP_PROF */
-