Basic heap profile support without -prof
authorSimon Marlow <simonmar@microsoft.com>
Fri, 27 Apr 2007 12:01:13 +0000 (12:01 +0000)
committerSimon Marlow <simonmar@microsoft.com>
Fri, 27 Apr 2007 12:01:13 +0000 (12:01 +0000)
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.

12 files changed:
includes/InfoTables.h
includes/RtsFlags.h
rts/Arena.c
rts/Makefile
rts/ProfHeap.c
rts/Profiling.h
rts/Proftimer.c
rts/RtsFlags.c
rts/RtsStartup.c
rts/RtsUtils.c
rts/Schedule.c
rts/Timer.c

index 77171f1..67bd97b 100644 (file)
@@ -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*
  */
index f7f79b6..4bfe276 100644 (file)
@@ -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') */
index b2b5ce2..fcdc6cc 100644 (file)
@@ -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);
 }
index 6bf4271..184a844 100644 (file)
@@ -35,7 +35,7 @@ WAYS=$(GhcLibWays) $(GhcRTSWays)
 
 ifneq "$(findstring debug, $(way))" ""
 GhcRtsHcOpts=
-GhcRtsCcOpts=-g
+GhcRtsCcOpts=-g -O0
 endif
 
 # -----------------------------------------------------------------------------
index ea71e20..dfa0067 100644 (file)
@@ -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 */
-
index edfc1b2..8961da9 100644 (file)
 
 #include <stdio.h>
 
-#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
 
index ce20c49..32e5c56 100644 (file)
@@ -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 */
index 58b69af..1cf7700 100644 (file)
@@ -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<chars>      Maximum length of a cost-centre stack in a heap profile",
 "                 (default: 25)",
 "",
-"  -i<sec>        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<break-down> Debugging Heap residency profile",
-"                 (output file <program>.hp)",
-"     break-down: L = closure label (default)",
-"                 T = closure type (constructor, thunk etc.)",
+"  -hT      Heap residency profile (output file <program>.hp)",
 #endif
+"  -i<sec>  Time between heap samples (seconds, default: 0.1)",
 "",
 #if defined(TICKY_TICKY)
 "  -r<file>  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;
index 85b1c02..1d0fec5 100644 (file)
@@ -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
index 7048e94..94c357e 100644 (file)
@@ -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
index 3d87003..6063fcd 100644 (file)
 #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++) {
index 493fe3d..05d1fec 100644 (file)
@@ -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);
 }