[project @ 1999-09-15 13:46:28 by simonmar]
authorsimonmar <unknown>
Wed, 15 Sep 1999 13:46:29 +0000 (13:46 +0000)
committersimonmar <unknown>
Wed, 15 Sep 1999 13:46:29 +0000 (13:46 +0000)
Cost-centre heap profiling and symbol table heap profiling are now
merged into one file: ProfHeap.c.

ghc/rts/DebugProf.c [deleted file]
ghc/rts/DebugProf.h [deleted file]
ghc/rts/ProfHeap.c [new file with mode: 0644]
ghc/rts/ProfHeap.h [new file with mode: 0644]

diff --git a/ghc/rts/DebugProf.c b/ghc/rts/DebugProf.c
deleted file mode 100644 (file)
index 7d32656..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: DebugProf.c,v 1.7 1999/09/15 13:45:16 simonmar Exp $
- *
- * (c) The GHC Team 1998-1999
- *
- * Simple Heap Profiling
- *
- * ---------------------------------------------------------------------------*/
-
-#include "Rts.h"
-#include "Printer.h"
-#include "BlockAlloc.h"
-#include "DebugProf.h"
-#include "RtsFlags.h"
-#include "RtsUtils.h"
-#include "Stats.h"
-
-#if defined(DEBUG) && ! defined(PROFILING)
-
-char prof_filename[128];
-FILE *prof_file;
-
-static void clear_table_data(void);
-static void fprint_data(FILE *fp);
-
-/* -----------------------------------------------------------------------------
-   The profiler itself
-   -------------------------------------------------------------------------- */
-
-void
-heapCensus(bdescr *bd)
-{
-    StgPtr p;
-    const StgInfoTable *info;
-    StgDouble time;
-    nat size;
-    
-    /* usertime() isn't very accurate, since it includes garbage
-     * collection time.  We really want elapsed_mutator_time or
-     * something.  ToDo.
-     */
-    time = usertime();
-    fprintf(prof_file, "BEGIN_SAMPLE %0.2f\n", time);
-
-    while (bd != NULL) {
-       p = bd->start;
-       while (p < bd->free) {
-           info = get_itbl((StgClosure *)p);
-
-           switch (info->type) {
-           case BCO:
-               size = bco_sizeW((StgBCO *)p);
-               break;
-
-           case FUN:
-           case THUNK:
-           case CONSTR:
-           case IND_PERM:
-           case IND_OLDGEN_PERM:
-           case BLACKHOLE:
-           case BLACKHOLE_BQ:
-           case WEAK:
-           case FOREIGN:
-           case MVAR:
-           case MUT_VAR:
-           case CONSTR_INTLIKE:
-           case CONSTR_CHARLIKE:
-           case CONSTR_STATIC:
-           case CONSTR_NOCAF_STATIC:
-           case THUNK_STATIC:
-           case FUN_STATIC:
-           case IND_STATIC:
-               size = sizeW_fromITBL(info);
-               break;
-
-           case THUNK_SELECTOR:
-               size = sizeofW(StgHeader) + MIN_UPD_SIZE;
-               break;
-
-           case IND:
-           case IND_OLDGEN:
-               size = sizeofW(StgInd);
-               break;
-
-           case AP_UPD: /* we can treat this as being the same as a PAP */
-           case PAP:
-               size = pap_sizeW((StgPAP *)p);
-               break;
-
-           case ARR_WORDS:
-               size = arr_words_sizeW(stgCast(StgArrWords*,p));
-               break;
-
-           case MUT_ARR_PTRS:
-           case MUT_ARR_PTRS_FROZEN:
-               size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
-               break;
-
-           case TSO:
-               size = tso_sizeW((StgTSO *)p);
-               break;
-
-           default:
-               barf("heapCensus");
-           }
-           switch (RtsFlags.ProfFlags.doHeapProfile) {
-           case HEAP_BY_INFOPTR:
-             add_data((void *)(*p), size * sizeof(W_));
-             break;
-           case HEAP_BY_CLOSURE_TYPE:
-             closure_types[info->type] += size * sizeof(W_);
-             break;
-           }
-           p += size;
-       }
-       bd = bd->link;
-    }
-
-    switch (RtsFlags.ProfFlags.doHeapProfile) {
-    case HEAP_BY_INFOPTR:
-      fprint_data(prof_file);
-      break;
-    case HEAP_BY_CLOSURE_TYPE:
-      fprint_closure_types(prof_file);
-      break;
-    }
-    
-    fprintf(prof_file, "END_SAMPLE %0.2f\n", time);
-}    
-
-#endif
-
diff --git a/ghc/rts/DebugProf.h b/ghc/rts/DebugProf.h
deleted file mode 100644 (file)
index a224595..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* -----------------------------------------------------------------------------
- * $Id: DebugProf.h,v 1.3 1999/09/15 13:45:16 simonmar Exp $
- *
- * (c) The GHC Team 1998
- *
- * Simple Heap Profiling
- *
- * ---------------------------------------------------------------------------*/
-
-#if !defined(PROFILING) && defined(DEBUG)
-
-extern void heapCensus(bdescr *bd);
-
-#endif
diff --git a/ghc/rts/ProfHeap.c b/ghc/rts/ProfHeap.c
new file mode 100644 (file)
index 0000000..2f28e58
--- /dev/null
@@ -0,0 +1,464 @@
+/* -----------------------------------------------------------------------------
+ * $Id: ProfHeap.c,v 1.1 1999/09/15 13:46:28 simonmar Exp $
+ *
+ * (c) The GHC Team, 1998-1999
+ *
+ * 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 "Rts.h"
+#include "RtsUtils.h"
+#include "RtsFlags.h"
+#include "ProfRts.h"
+#include "Storage.h"
+#include "ProfHeap.h"
+#include "Stats.h"
+#include "ProfRts.h"
+#ifdef DEBUG_HEAP_PROF
+#include "Printer.h"
+static void initSymbolHash(void);
+static void clear_table_data(void);
+static void fprint_data(FILE *fp);
+#endif
+
+char prof_filename[128];       /* urk */
+FILE *prof_file;
+
+nat
+initHeapProfiling(void)
+{
+    if (! RtsFlags.ProfFlags.doHeapProfile) {
+        return 0;
+    }
+
+    sprintf(prof_filename, "%.124s.hp", prog_argv[0]);
+
+    prof_file = fopen(prof_filename, "w");
+    if (prof_file == NULL) {
+       fprintf(stderr, "Can't open heap profiling log file %s\n",
+               prof_filename);
+       return 1;
+    }
+
+    fprintf(prof_file, "JOB \"%s\"\n", prog_argv[0]);
+    fprintf(prof_file, "DATE \"%s\"\n", time_str());
+
+    fprintf(prof_file, "SAMPLE_UNIT \"seconds\"\n");
+    fprintf(prof_file, "VALUE_UNIT \"bytes\"\n");
+
+    fprintf(prof_file, "BEGIN_SAMPLE 0.00\n");
+    fprintf(prof_file, "END_SAMPLE 0.00\n");
+
+#ifdef DEBUG_HEAP_PROF
+    DEBUG_LoadSymbols(prog_argv[0]);
+    initSymbolHash();
+#endif
+
+    return 0;
+}
+
+void
+endHeapProfiling(void)
+{
+    StgDouble seconds;
+
+    if (! RtsFlags.ProfFlags.doHeapProfile) {
+        return;
+    }
+
+    seconds = mut_user_time();
+    fprintf(prof_file, "BEGIN_SAMPLE %0.2f\n", seconds);
+    fprintf(prof_file, "END_SAMPLE %0.2f\n", seconds);
+    fclose(prof_file);
+}
+
+#ifdef DEBUG_HEAP_PROF
+/* -----------------------------------------------------------------------------
+   Hash table for symbols.
+   -------------------------------------------------------------------------- */
+
+typedef struct {
+    const char *name;
+    void *ptr;
+    nat data;
+} symbol_info;
+
+#define SYMBOL_HASH_SIZE 0x3fff
+
+symbol_info symbol_hash[SYMBOL_HASH_SIZE];
+
+static inline nat
+hash(void *ptr)
+{
+    return ((W_)ptr)>>4 & 0x3fff;
+}
+
+static void
+initSymbolHash(void)
+{
+    nat i;
+
+    for (i=0; i < SYMBOL_HASH_SIZE; i++) {
+       symbol_hash[i].ptr = NULL;
+    }
+}
+
+static nat
+lookup_symbol(void *addr)
+{
+    nat orig_bucket = hash(addr);
+    nat bucket;
+
+    bucket = orig_bucket;
+    while (bucket < SYMBOL_HASH_SIZE && symbol_hash[bucket].ptr != NULL) {
+       if (symbol_hash[bucket].ptr == addr) {
+           return bucket;
+       }
+       bucket++;
+    }
+    if (bucket == SYMBOL_HASH_SIZE) {
+       bucket = 0;
+       while (bucket < orig_bucket && symbol_hash[bucket].ptr != NULL) {
+           if (symbol_hash[bucket].ptr == addr) {
+               return bucket;
+           }
+           bucket++;
+       }
+       if (bucket == orig_bucket) {
+           barf("out of symbol table space");
+       }
+    }
+    
+    symbol_hash[bucket].ptr  = addr;
+    lookupGHCName(addr,&symbol_hash[bucket].name);
+    symbol_hash[bucket].data = 0;
+    return bucket;
+}
+
+static void
+clear_table_data(void)
+{
+    nat i;
+
+    for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
+       symbol_hash[i].data = 0;
+    }
+}
+
+static void
+fprint_data(FILE *fp)
+{
+    nat i;
+    
+    for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
+       if (symbol_hash[i].data) {
+           fprintf(fp, "   %s %d\n", symbol_hash[i].name, symbol_hash[i].data);
+       }
+    }
+}
+
+static inline void
+add_data(void *addr, nat data)
+{
+    symbol_hash[lookup_symbol(addr)].data += data;
+}
+
+/* -----------------------------------------------------------------------------
+   Closure Type Profiling;
+
+   PROBABLY TOTALLY OUT OF DATE -- ToDo (SDM)
+   -------------------------------------------------------------------------- */
+
+static nat closure_types[N_CLOSURE_TYPES];
+
+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_UPD"
+
+    , "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"
+    , "SEQ_FRAME"
+
+    , "BLACKHOLE"
+    , "BLACKHOLE_BQ"
+    , "MVAR"
+
+    , "ARR_WORDS"
+
+    , "MUT_ARR_PTRS"
+    , "MUT_ARR_PTRS_FROZEN"
+    , "MUT_VAR"
+
+    , "WEAK"
+    , "FOREIGN"
+  
+    , "TSO"
+
+    , "BLOCKED_FETCH"
+    , "FETCH_ME"
+
+    , "EVACUATED"
+};
+
+static void 
+fprint_closure_types(FILE *fp)
+{
+  nat i;
+
+  for (i = 0; i < N_CLOSURE_TYPES; i++) {
+    if (closure_types[i]) {
+      fprintf(fp, "   %s %d\n", type_names[i], closure_types[i]);
+    }
+  }
+}
+
+#endif /* DEBUG_HEAP_PROF */
+
+
+#ifdef PROFILING
+static void
+clearCCSResid(CostCentreStack *ccs)
+{
+  IndexTable *i;
+
+  ccs->mem_resid = 0;
+
+  for (i = ccs->indexTable; i != 0; i = i->next) {
+    clearCCSResid(i->ccs);
+  }
+}
+
+static void
+fprint_ccs(FILE *fp, CostCentreStack *ccs, nat components)
+{
+  CostCentre *cc;
+  CostCentreStack *prev;
+
+  cc = ccs->cc;
+  prev = ccs->prevStack;
+
+  if (prev == NULL
+      || prev->cc->is_subsumed != CC_IS_BORING
+      || components == 1) { 
+    fprintf(fp,"%s",cc->label);
+    return; 
+
+  } else {
+    fprint_ccs(fp, ccs->prevStack,components-1);
+    fprintf(fp,"/%s",cc->label);
+  }
+}
+
+static void
+reportCCSResid(FILE *fp, CostCentreStack *ccs)
+{
+  IndexTable *i;
+
+  if (ccs->mem_resid != 0) {
+    fprintf(fp,"   ");
+    fprint_ccs(fp,ccs,2/*print 2 components only*/);
+    fprintf(fp," %ld\n", ccs->mem_resid * sizeof(W_));
+  }
+
+  for (i = ccs->indexTable; i != 0; i = i->next) {
+    reportCCSResid(fp,i->ccs);
+  }
+}
+#endif
+
+void
+heapCensus(void)
+{
+  bdescr *bd;
+  const StgInfoTable *info;
+  StgDouble time;
+  nat size;
+  StgPtr p;
+  
+#ifdef DEBUG_HEAP_PROF
+  switch (RtsFlags.ProfFlags.doHeapProfile) {
+  case HEAP_BY_INFOPTR:
+    clear_table_data();
+    break;
+  case HEAP_BY_CLOSURE_TYPE:
+    memset(closure_types, 0, N_CLOSURE_TYPES * sizeof(nat));
+    break;
+  default:
+    return;
+  }
+#endif
+
+#ifdef PROFILING
+  switch (RtsFlags.ProfFlags.doHeapProfile) {
+  case NO_HEAP_PROFILING:
+    return;
+  case HEAP_BY_CCS:
+    break;
+  default:
+    barf("heapCensus; doHeapProfile");
+  }
+  /* zero all the residency counters */
+  clearCCSResid(CCS_MAIN);
+#endif
+
+  /* Only do heap profiling in a two-space heap */
+  ASSERT(RtsFlags.GcFlags.generations == 1);
+  bd = g0s0->to_space;
+
+  time = mut_user_time_during_GC();
+  fprintf(prof_file, "BEGIN_SAMPLE %0.2f\n", time);
+  
+  while (bd != NULL) {
+    p = bd->start;
+    while (p < bd->free) {
+      info = get_itbl((StgClosure *)p);
+
+      switch (info->type) {
+      case BCO:
+       size = bco_sizeW((StgBCO *)p);
+       break;
+       
+      case CONSTR:
+       if (((StgClosure *)p)->header.info == &DEAD_WEAK_info) {
+         size = sizeofW(StgWeak);
+         break;
+       }
+       /* else, fall through... */
+
+      case FUN:
+      case THUNK:
+      case IND_PERM:
+      case IND_OLDGEN_PERM:
+      case CAF_BLACKHOLE:
+      case SE_CAF_BLACKHOLE:
+      case SE_BLACKHOLE:
+      case BLACKHOLE:
+      case BLACKHOLE_BQ:
+      case WEAK:
+      case FOREIGN:
+      case STABLE_NAME:
+      case MVAR:
+      case MUT_VAR:
+      case CONSTR_INTLIKE:
+      case CONSTR_CHARLIKE:
+      case FUN_1_0:
+      case FUN_0_1:
+      case FUN_1_1:
+      case FUN_0_2:
+      case FUN_2_0:
+      case THUNK_1_0:
+      case THUNK_0_1:
+      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_0_2:
+      case CONSTR_2_0:
+       size = sizeW_fromITBL(info);
+       break;
+       
+      case THUNK_SELECTOR:
+       size = sizeofW(StgHeader) + MIN_UPD_SIZE;
+       break;
+       
+      case AP_UPD: /* we can treat this as being the same as a PAP */
+      case PAP:
+       size = pap_sizeW((StgPAP *)p);
+       break;
+       
+      case ARR_WORDS:
+       size = arr_words_sizeW(stgCast(StgArrWords*,p));
+       break;
+       
+      case MUT_ARR_PTRS:
+      case MUT_ARR_PTRS_FROZEN:
+       size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
+       break;
+       
+      case TSO:
+       size = tso_sizeW((StgTSO *)p);
+       break;
+       
+      default:
+       barf("heapCensus");
+      }
+
+#ifdef DEBUG_HEAP_PROF
+      switch (RtsFlags.ProfFlags.doHeapProfile) {
+      case HEAP_BY_INFOPTR:
+       add_data((void *)(*p), size * sizeof(W_));
+       break;
+      case HEAP_BY_CLOSURE_TYPE:
+       closure_types[info->type] += size * sizeof(W_);
+       break;
+      }
+#endif
+
+#ifdef PROFILING      
+      ((StgClosure *)p)->header.prof.ccs->mem_resid += size;
+#endif
+      p += size;
+    }
+    bd = bd->link;
+  }
+
+#ifdef DEBUG_HEAP_PROF
+  switch (RtsFlags.ProfFlags.doHeapProfile) {
+  case HEAP_BY_INFOPTR:
+    fprint_data(prof_file);
+    break;
+  case HEAP_BY_CLOSURE_TYPE:
+    fprint_closure_types(prof_file);
+    break;
+  }
+#endif
+    
+#ifdef PROFILING
+  reportCCSResid(prof_file,CCS_MAIN);
+#endif
+
+  fprintf(prof_file, "END_SAMPLE %0.2f\n", time);
+}    
+
+#endif /* PROFILING || DEBUG_HEAP_PROF */
+
diff --git a/ghc/rts/ProfHeap.h b/ghc/rts/ProfHeap.h
new file mode 100644 (file)
index 0000000..270dc55
--- /dev/null
@@ -0,0 +1,13 @@
+/* -----------------------------------------------------------------------------
+ * $Id: ProfHeap.h,v 1.1 1999/09/15 13:46:29 simonmar Exp $
+ *
+ * (c) The GHC Team, 1998-1999
+ *
+ * Support for heap profiling
+ *
+ * ---------------------------------------------------------------------------*/
+
+
+void heapCensus(void);
+extern nat initHeapProfiling(void);
+void endHeapProfiling(void);