From cbeb99efd4a117de5b028341dc41bc8f50717383 Mon Sep 17 00:00:00 2001 From: Simon Marlow Date: Fri, 27 Apr 2007 12:01:13 +0000 Subject: [PATCH] Basic heap profile support without -prof Now that constructor info tables contain the name of the constructor, we can generate useful heap profiles without requiring the whole program and libraries to be compiled with -prof. So now, "+RTS -hT" generates a heap profile for any program, dividing the profile by constructor. It wouldn't be hard to add support for grouping constructors by module, or to restrict the profile to certain constructors/modules/packages. This means that for the first time we can get heap profiles for GHCi, which was previously impossible because the byte-code interpreter and linker don't work with -prof. --- includes/InfoTables.h | 10 +++ includes/RtsFlags.h | 3 +- rts/Arena.c | 6 +- rts/Makefile | 2 +- rts/ProfHeap.c | 220 ++++++++++++++++++++++++++----------------------- rts/Profiling.h | 10 +-- rts/Proftimer.c | 6 +- rts/RtsFlags.c | 28 ++----- rts/RtsStartup.c | 11 +-- rts/RtsUtils.c | 2 - rts/Schedule.c | 47 ++++------- rts/Timer.c | 5 -- 12 files changed, 166 insertions(+), 184 deletions(-) diff --git a/includes/InfoTables.h b/includes/InfoTables.h index 77171f1..67bd97b 100644 --- a/includes/InfoTables.h +++ b/includes/InfoTables.h @@ -412,6 +412,16 @@ typedef struct _StgConInfoTable { #endif /* + * GET_CON_DESC(info) + * info must be a StgConInfoTable*. + */ +#ifdef TABLES_NEXT_TO_CODE +#define GET_CON_DESC(info) ((char *)((StgWord)((info)+1) + (info->con_desc))) +#else +#define GET_CON_DESC(info) ((info)->con_desc) +#endif + +/* * GET_FUN_SRT(info) * info must be a StgFunInfoTable* */ diff --git a/includes/RtsFlags.h b/includes/RtsFlags.h index f7f79b6..4bfe276 100644 --- a/includes/RtsFlags.h +++ b/includes/RtsFlags.h @@ -86,8 +86,7 @@ struct PROFILING_FLAGS { # define HEAP_BY_RETAINER 6 # define HEAP_BY_LDV 7 -# define HEAP_BY_INFOPTR 1 /* DEBUG only */ -# define HEAP_BY_CLOSURE_TYPE 2 /* DEBUG only */ +# define HEAP_BY_CLOSURE_TYPE 8 nat profileInterval; /* delta between samples (in ms) */ nat profileIntervalTicks; /* delta between samples (in 'ticks') */ diff --git a/rts/Arena.c b/rts/Arena.c index b2b5ce2..fcdc6cc 100644 --- a/rts/Arena.c +++ b/rts/Arena.c @@ -42,7 +42,7 @@ newArena( void ) Arena *arena; arena = stgMallocBytes(sizeof(Arena), "newArena"); - arena->current = allocBlock(); + arena->current = allocBlock_lock(); arena->current->link = NULL; arena->free = arena->current->start; arena->lim = arena->current->start + BLOCK_SIZE_W; @@ -81,7 +81,7 @@ arenaAlloc( Arena *arena, size_t size ) } else { // allocate a fresh block... req_blocks = (lnat)BLOCK_ROUND_UP(size) / BLOCK_SIZE; - bd = allocGroup(req_blocks); + bd = allocGroup_lock(req_blocks); arena_blocks += req_blocks; bd->gen_no = 0; @@ -106,7 +106,7 @@ arenaFree( Arena *arena ) next = bd->link; arena_blocks -= bd->blocks; ASSERT(arena_blocks >= 0); - freeGroup(bd); + freeGroup_lock(bd); } stgFree(arena); } diff --git a/rts/Makefile b/rts/Makefile index 6bf4271..184a844 100644 --- a/rts/Makefile +++ b/rts/Makefile @@ -35,7 +35,7 @@ WAYS=$(GhcLibWays) $(GhcRTSWays) ifneq "$(findstring debug, $(way))" "" GhcRtsHcOpts= -GhcRtsCcOpts=-g +GhcRtsCcOpts=-g -O0 endif # ----------------------------------------------------------------------------- diff --git a/rts/ProfHeap.c b/rts/ProfHeap.c index ea71e20..dfa0067 100644 --- a/rts/ProfHeap.c +++ b/rts/ProfHeap.c @@ -1,18 +1,10 @@ -/* ----------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- * * (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" @@ -103,70 +95,86 @@ static void aggregateCensusInfo( void ); 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_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_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" -}; - -#endif /* DEBUG_HEAP_PROF */ - -/* ----------------------------------------------------------------------------- + "INVALID_OBJECT", + "CONSTR", + "CONSTR_1_0", + "CONSTR_0_1", + "CONSTR_2_0", + "CONSTR_1_1", + "CONSTR_0_2", + "CONSTR_STATIC", + "CONSTR_NOCAF_STATIC", + "FUN", + "FUN_1_0", + "FUN_0_1", + "FUN_2_0", + "FUN_1_1", + "FUN_0_2", + "FUN_STATIC", + "THUNK", + "THUNK_1_0", + "THUNK_0_1", + "THUNK_2_0", + "THUNK_1_1", + "THUNK_0_2", + "THUNK_STATIC", + "THUNK_SELECTOR", + "BCO", + "AP", + "PAP", + "AP_STACK", + "IND", + "IND_OLDGEN", + "IND_PERM", + "IND_OLDGEN_PERM", + "IND_STATIC", + "RET_BCO", + "RET_SMALL", + "RET_BIG", + "RET_DYN", + "RET_FUN", + "UPDATE_FRAME", + "CATCH_FRAME", + "STOP_FRAME", + "CAF_BLACKHOLE", + "BLACKHOLE", + "SE_BLACKHOLE", + "SE_CAF_BLACKHOLE", + "MVAR", + "ARR_WORDS", + "MUT_ARR_PTRS_CLEAN", + "MUT_ARR_PTRS_DIRTY", + "MUT_ARR_PTRS_FROZEN0", + "MUT_ARR_PTRS_FROZEN", + "MUT_VAR_CLEAN", + "MUT_VAR_DIRTY", + "WEAK", + "STABLE_NAME", + "TSO", + "BLOCKED_FETCH", + "FETCH_ME", + "FETCH_ME_BQ", + "RBH", + "EVACUATED", + "REMOTE_REF", + "TVAR_WATCH_QUEUE", + "INVARIANT_CHECK_QUEUE", + "ATOMIC_INVARIANT", + "TVAR", + "TREC_CHUNK", + "TREC_HEADER", + "ATOMICALLY_FRAME", + "CATCH_RETRY_FRAME", + "CATCH_STM_FRAME", + "N_CLOSURE_TYPES" + }; + +/* ---------------------------------------------------------------------------- * 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. @@ -193,11 +201,26 @@ closureIdentity( StgClosure *p ) 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: + printf("",strlen(GET_CON_DESC(itbl_to_con_itbl(info)))); + return GET_CON_DESC(itbl_to_con_itbl(info)); + default: + return type_names[info->type]; + } + } #endif default: @@ -300,6 +323,7 @@ LDV_recordDead( StgClosure *c, nat size ) /* -------------------------------------------------------------------------- * Initialize censuses[era]; * ----------------------------------------------------------------------- */ + STATIC_INLINE void initEra(Census *census) { @@ -325,6 +349,7 @@ freeEra(Census *census) * Increases era by 1 and initialize census[era]. * Reallocates gi[] and increases its size if needed. * ----------------------------------------------------------------------- */ + static void nextEra( void ) { @@ -348,23 +373,23 @@ nextEra( void ) initEra( &censuses[era] ); } -/* ----------------------------------------------------------------------------- - * DEBUG heap profiling, by info table - * -------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------- + * Heap profiling by info table + * ------------------------------------------------------------------------- */ -#ifdef DEBUG_HEAP_PROF +#if !defined(PROFILNG) FILE *hp_file; static char *hp_filename; -void initProfiling1( void ) +void initProfiling1 (void) { } -void freeProfiling1( void ) +void freeProfiling1 (void) { } -void initProfiling2( void ) +void initProfiling2 (void) { if (RtsFlags.ProfFlags.doHeapProfile) { /* Initialise the log file name */ @@ -387,7 +412,7 @@ void endProfiling( void ) { endHeapProfiling(); } -#endif /* DEBUG_HEAP_PROF */ +#endif /* !PROFILING */ static void printSample(rtsBool beginSample, StgDouble sampleValue) @@ -463,10 +488,6 @@ initHeapProfiling(void) printSample(rtsTrue, 0); printSample(rtsFalse, 0); -#ifdef DEBUG_HEAP_PROF - DEBUG_LoadSymbols(prog_name); -#endif - #ifdef PROFILING if (doingRetainerProfiling()) { initRetainerProfiling(); @@ -603,7 +624,7 @@ strMatchesSelector( char* str, char* sel ) rtsBool closureSatisfiesConstraints( StgClosure* p ) { -#ifdef DEBUG_HEAP_PROF +#if !defined(PROFILING) (void)p; /* keep gcc -Wall happy */ return rtsTrue; #else @@ -808,11 +829,8 @@ dumpCensus( Census *census ) 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; @@ -984,10 +1002,7 @@ heapCensusChain( Census *census, bdescr *bd ) 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); break; @@ -996,6 +1011,9 @@ heapCensusChain( Census *census, bdescr *bd ) p += tso_sizeW((StgTSO *)p); continue; } +#else + size = tso_sizeW((StgTSO *)p); + break; #endif case TREC_HEADER: @@ -1034,11 +1052,11 @@ heapCensusChain( Census *census, bdescr *bd ) 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)) { @@ -1158,13 +1176,13 @@ heapCensus( void ) // 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(); @@ -1174,5 +1192,3 @@ heapCensus( void ) #endif } -#endif /* PROFILING || DEBUG_HEAP_PROF */ - diff --git a/rts/Profiling.h b/rts/Profiling.h index edfc1b2..8961da9 100644 --- a/rts/Profiling.h +++ b/rts/Profiling.h @@ -11,15 +11,13 @@ #include -#if defined(PROFILING) || defined(DEBUG) -void initProfiling1 ( void ); -void freeProfiling1 ( void ); -void initProfiling2 ( void ); -void endProfiling ( void ); +void initProfiling1 (void); +void freeProfiling1 (void); +void initProfiling2 (void); +void endProfiling (void); extern FILE *prof_file; extern FILE *hp_file; -#endif #ifdef PROFILING diff --git a/rts/Proftimer.c b/rts/Proftimer.c index ce20c49..32e5c56 100644 --- a/rts/Proftimer.c +++ b/rts/Proftimer.c @@ -6,8 +6,6 @@ * * ---------------------------------------------------------------------------*/ -#if defined (PROFILING) - #include "PosixSource.h" #include "Rts.h" @@ -66,9 +64,11 @@ initProfTimer( void ) void handleProfTick(void) { +#ifdef PROFILING if (do_prof_ticks) { CCCS->time_ticks++; } +#endif if (do_heap_prof_ticks) { ticks_to_heap_profile--; @@ -78,5 +78,3 @@ handleProfTick(void) } } } - -#endif /* PROFILING */ diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c index 58b69af..1cf7700 100644 --- a/rts/RtsFlags.c +++ b/rts/RtsFlags.c @@ -172,9 +172,10 @@ void initRtsFlagsDefaults(void) RtsFlags.CcFlags.doCostCentres = 0; #endif /* PROFILING or PAR */ -#ifdef PROFILING RtsFlags.ProfFlags.doHeapProfile = rtsFalse; RtsFlags.ProfFlags.profileInterval = 100; + +#ifdef PROFILING RtsFlags.ProfFlags.includeTSOs = rtsFalse; RtsFlags.ProfFlags.showCCSOnException = rtsFalse; RtsFlags.ProfFlags.maxRetainerSetSize = 8; @@ -186,9 +187,6 @@ void initRtsFlagsDefaults(void) RtsFlags.ProfFlags.ccsSelector = NULL; RtsFlags.ProfFlags.retainerSelector = NULL; RtsFlags.ProfFlags.bioSelector = NULL; - -#elif defined(DEBUG) - RtsFlags.ProfFlags.doHeapProfile = rtsFalse; #endif RtsFlags.MiscFlags.tickInterval = 50; /* In milliseconds */ @@ -382,20 +380,17 @@ usage_text[] = { " -L Maximum length of a cost-centre stack in a heap profile", " (default: 25)", "", -" -i Time between heap samples (seconds, default: 0.1)", -"", " -xt Include threads (TSOs) in a heap profile", "", " -xc Show current cost centre stack on raising an exception", +"", # endif #endif /* PROFILING or PAR */ -#if !defined(PROFILING) && defined(DEBUG) +#if !defined(PROFILING) "", -" -h Debugging Heap residency profile", -" (output file .hp)", -" break-down: L = closure label (default)", -" T = closure type (constructor, thunk etc.)", +" -hT Heap residency profile (output file .hp)", #endif +" -i Time between heap samples (seconds, default: 0.1)", "", #if defined(TICKY_TICKY) " -r Produce ticky-ticky statistics (with -rstderr for stderr)", @@ -936,12 +931,9 @@ error = rtsTrue; } ) break; case 'h': /* serial heap profile */ -#if !defined(PROFILING) && defined(DEBUG) +#if !defined(PROFILING) switch (rts_argv[arg][2]) { case '\0': - case 'L': - RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_INFOPTR; - break; case 'T': RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE; break; @@ -1057,7 +1049,6 @@ error = rtsTrue; #endif /* PROFILING */ break; -#if defined(PROFILING) case 'i': /* heap sample interval */ if (rts_argv[arg][2] == '\0') { /* use default */ @@ -1069,7 +1060,6 @@ error = rtsTrue; RtsFlags.ProfFlags.profileInterval = cst; } break; -#endif /* =========== CONCURRENT ========================= */ case 'C': /* context switch interval */ @@ -1251,13 +1241,11 @@ error = rtsTrue; RtsFlags.MiscFlags.tickInterval); } -#ifdef PROFILING if (RtsFlags.ProfFlags.profileInterval > 0) { RtsFlags.MiscFlags.tickInterval = stg_min(RtsFlags.ProfFlags.profileInterval, RtsFlags.MiscFlags.tickInterval); } -#endif if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) { RtsFlags.ConcFlags.ctxtSwitchTicks = @@ -1267,10 +1255,8 @@ error = rtsTrue; RtsFlags.ConcFlags.ctxtSwitchTicks = 0; } -#ifdef PROFILING RtsFlags.ProfFlags.profileIntervalTicks = RtsFlags.ProfFlags.profileInterval / RtsFlags.MiscFlags.tickInterval; -#endif if (error) { const char **p; diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c index 85b1c02..1d0fec5 100644 --- a/rts/RtsStartup.c +++ b/rts/RtsStartup.c @@ -38,8 +38,9 @@ #include "FrontPanel.h" #endif -#if defined(PROFILING) || defined(DEBUG) # include "Profiling.h" + +#if defined(PROFILING) # include "ProfHeap.h" # include "RetainerProfile.h" #endif @@ -244,9 +245,7 @@ hs_init(int *argc, char **argv[]) initThreadLabelTable(); #endif -#if defined(PROFILING) || defined(DEBUG) initProfiling1(); -#endif /* start the virtual timer 'subsystem'. */ startTimer(); @@ -353,11 +352,9 @@ hs_add_root(void (*init_root)(void)) startupHpc(); -#if defined(PROFILING) || defined(DEBUG) // This must be done after module initialisation. // ToDo: make this work in the presence of multiple hs_add_root()s. initProfiling2(); -#endif } /* ----------------------------------------------------------------------------- @@ -455,9 +452,7 @@ hs_exit(void) /* free the stable pointer table */ exitStablePtrTable(); -#if defined(PROFILING) || defined(DEBUG) freeProfiling1(); -#endif #if defined(DEBUG) /* free the thread label table */ @@ -477,9 +472,7 @@ hs_exit(void) reportCCSProfiling(); #endif -#if defined(PROFILING) || defined(DEBUG) endProfiling(); -#endif #ifdef PROFILING // Originally, this was in report_ccs_profiling(). Now, retainer diff --git a/rts/RtsUtils.c b/rts/RtsUtils.c index 7048e94..94c357e 100644 --- a/rts/RtsUtils.c +++ b/rts/RtsUtils.c @@ -316,7 +316,6 @@ resetGenSymZh(void) /* it's your funeral */ Get the current time as a string. Used in profiling reports. -------------------------------------------------------------------------- */ -#if defined(PROFILING) || defined(DEBUG) || defined(PAR) || defined(GRAN) char * time_str(void) { @@ -335,7 +334,6 @@ time_str(void) } return nowstr; } -#endif /* ----------------------------------------------------------------------------- * Reset a file handle to blocking mode. We do this for the standard diff --git a/rts/Schedule.c b/rts/Schedule.c index 3d87003..6063fcd 100644 --- a/rts/Schedule.c +++ b/rts/Schedule.c @@ -28,10 +28,8 @@ #include "ThreadLabels.h" #include "LdvProfile.h" #include "Updates.h" -#ifdef PROFILING #include "Proftimer.h" #include "ProfHeap.h" -#endif #if defined(GRAN) || defined(PARALLEL_HASKELL) # include "GranSimRts.h" # include "GranSim.h" @@ -216,7 +214,7 @@ static rtsBool scheduleHandleYield( Capability *cap, StgTSO *t, static void scheduleHandleThreadBlocked( StgTSO *t ); static rtsBool scheduleHandleThreadFinished( Capability *cap, Task *task, StgTSO *t ); -static rtsBool scheduleDoHeapProfile(rtsBool ready_to_gc); +static rtsBool scheduleNeedHeapProfile(rtsBool ready_to_gc); static Capability *scheduleDoGC(Capability *cap, Task *task, rtsBool force_major); @@ -572,9 +570,7 @@ run_thread: debugTrace(DEBUG_sched, "-->> running thread %ld %s ...", (long)t->id, whatNext_strs[t->what_next]); -#if defined(PROFILING) startHeapProfTimer(); -#endif // Check for exceptions blocked on this thread maybePerformBlockedException (cap, t); @@ -667,8 +663,8 @@ run_thread: // ---------------------------------------------------------------------- // Costs for the scheduler are assigned to CCS_SYSTEM -#if defined(PROFILING) stopHeapProfTimer(); +#if defined(PROFILING) CCCS = CCS_SYSTEM; #endif @@ -705,8 +701,7 @@ run_thread: barf("schedule: invalid thread return code %d", (int)ret); } - if (scheduleDoHeapProfile(ready_to_gc)) { ready_to_gc = rtsFalse; } - if (ready_to_gc) { + if (ready_to_gc || scheduleNeedHeapProfile(ready_to_gc)) { cap = scheduleDoGC(cap,task,rtsFalse); } } /* end of while() */ @@ -1920,36 +1915,21 @@ scheduleHandleThreadFinished (Capability *cap STG_UNUSED, Task *task, StgTSO *t) } /* ----------------------------------------------------------------------------- - * Perform a heap census, if PROFILING + * Perform a heap census * -------------------------------------------------------------------------- */ static rtsBool -scheduleDoHeapProfile( rtsBool ready_to_gc STG_UNUSED ) +scheduleNeedHeapProfile( rtsBool ready_to_gc STG_UNUSED ) { -#if defined(PROFILING) // When we have +RTS -i0 and we're heap profiling, do a census at // every GC. This lets us get repeatable runs for debugging. if (performHeapProfile || (RtsFlags.ProfFlags.profileInterval==0 && RtsFlags.ProfFlags.doHeapProfile && ready_to_gc)) { - - // checking black holes is necessary before GC, otherwise - // there may be threads that are unreachable except by the - // blackhole queue, which the GC will consider to be - // deadlocked. - scheduleCheckBlackHoles(&MainCapability); - - debugTrace(DEBUG_sched, "garbage collecting before heap census"); - GarbageCollect(rtsTrue); - - debugTrace(DEBUG_sched, "performing heap census"); - heapCensus(); - - performHeapProfile = rtsFalse; - return rtsTrue; // true <=> we already GC'd + return rtsTrue; + } else { + return rtsFalse; } -#endif - return rtsFalse; } /* ----------------------------------------------------------------------------- @@ -1960,6 +1940,7 @@ static Capability * scheduleDoGC (Capability *cap, Task *task USED_IF_THREADS, rtsBool force_major) { StgTSO *t; + rtsBool heap_census; #ifdef THREADED_RTS static volatile StgWord waiting_for_gc; rtsBool was_waiting; @@ -2067,6 +2048,8 @@ scheduleDoGC (Capability *cap, Task *task USED_IF_THREADS, rtsBool force_major) deleteAllThreads(&capabilities[0]); sched_state = SCHED_SHUTTING_DOWN; } + + heap_census = scheduleNeedHeapProfile(rtsTrue); /* everybody back, start the GC. * Could do it in this thread, or signal a condition var @@ -2076,8 +2059,14 @@ scheduleDoGC (Capability *cap, Task *task USED_IF_THREADS, rtsBool force_major) #if defined(THREADED_RTS) debugTrace(DEBUG_sched, "doing GC"); #endif - GarbageCollect(force_major); + GarbageCollect(force_major || heap_census); + if (heap_census) { + debugTrace(DEBUG_sched, "performing heap census"); + heapCensus(); + performHeapProfile = rtsFalse; + } + #if defined(THREADED_RTS) // release our stash of capabilities. for (i = 0; i < n_capabilities; i++) { diff --git a/rts/Timer.c b/rts/Timer.c index 493fe3d..05d1fec 100644 --- a/rts/Timer.c +++ b/rts/Timer.c @@ -42,9 +42,7 @@ static void handle_tick(int unused STG_UNUSED) { -#ifdef PROFILING handleProfTick(); -#endif if (RtsFlags.ConcFlags.ctxtSwitchTicks > 0) { ticks_to_ctxt_switch--; if (ticks_to_ctxt_switch <= 0) { @@ -86,10 +84,7 @@ handle_tick(int unused STG_UNUSED) void startTimer(void) { -#ifdef PROFILING initProfTimer(); -#endif - startTicker(RtsFlags.MiscFlags.tickInterval, handle_tick); } -- 1.7.10.4