1 /* -----------------------------------------------------------------------------
2 * $Id: ProfHeap.c,v 1.11 2000/04/05 15:32:08 simonmar Exp $
4 * (c) The GHC Team, 1998-2000
6 * Support for heap profiling
8 * ---------------------------------------------------------------------------*/
10 #if defined(DEBUG) && !defined(PROFILING)
11 #define DEBUG_HEAP_PROF
13 #undef DEBUG_HEAP_PROF
16 #if defined(PROFILING) || defined(DEBUG_HEAP_PROF)
21 #include "Profiling.h"
28 #ifdef DEBUG_HEAP_PROF
30 static void initSymbolHash(void);
31 static void clear_table_data(void);
32 static void fprint_data(FILE *fp);
35 char prof_filename[128]; /* urk */
37 /* -----------------------------------------------------------------------------
40 * For profiling by module, constructor or closure type we need to be
41 * able to get from a string describing the category to a structure
42 * containing the counters for that category. The strings aren't
43 * unique (although gcc will do a fairly good job of commoning them up
44 * where possible), so we have a many->one mapping.
46 * We represent the many->one mapping with a hash table. In order to
47 * find the unique counter associated with a string the first time we
48 * encounter a particular string, we need another hash table, mapping
49 * hashed strings to buckets of counters. The string is hashed, then
50 * the bucket is searched for an existing counter for the same
53 * -------------------------------------------------------------------------- */
57 unsigned long mem_resid;
59 struct _ctr *next_bucket;
62 /* Linked list of all existing ctr structs */
65 /* Hash table mapping (char *) -> (struct _ctr) */
66 HashTable *str_to_ctr;
68 /* Hash table mapping hash_t (hashed string) -> (struct _ctr) */
69 HashTable *hashstr_to_ctrs;
72 initHashTables( void )
74 str_to_ctr = allocHashTable();
75 hashstr_to_ctrs = allocHashTable();
80 strToCtr(const char *str)
84 ctr = lookupHashTable( str_to_ctr, (W_)str );
86 if (ctr != NULL) { return ctr; }
89 hash_t str_hash = hash_str((char *)str);
92 ctr = lookupHashTable( hashstr_to_ctrs, (W_)str_hash );
95 for (; ctr != NULL; prev = ctr, ctr = ctr->next_bucket ) {
96 if (!strcmp(ctr->str, str)) {
97 insertHashTable( str_to_ctr, (W_)str, ctr );
99 fprintf(stderr,"strToCtr: existing ctr for `%s'\n",str);
105 ctr = stgMallocBytes(sizeof(prof_ctr), "strToCtr");
108 ctr->next_bucket = NULL;
109 ctr->next = all_ctrs;
113 fprintf(stderr,"strToCtr: new ctr for `%s'\n",str);
117 prev->next_bucket = ctr;
119 insertHashTable( hashstr_to_ctrs, str_hash, ctr );
121 insertHashTable( str_to_ctr, (W_)str, ctr);
127 clearCtrResid( void )
131 for (ctr = all_ctrs; ctr != NULL; ctr = ctr->next) {
137 reportCtrResid(FILE *fp)
141 for (ctr = all_ctrs; ctr != NULL; ctr = ctr->next) {
142 if (ctr->mem_resid != 0) {
143 fprintf(fp," %s %ld\n", ctr->str, ctr->mem_resid * sizeof(W_));
148 /* -------------------------------------------------------------------------- */
150 #ifdef DEBUG_HEAP_PROF
153 void initProfiling1( void )
157 void initProfiling2( void )
162 void endProfiling( void )
166 #endif /* DEBUG_HEAP_PROF */
169 initHeapProfiling(void)
171 if (! RtsFlags.ProfFlags.doHeapProfile) {
175 fprintf(prof_file, "JOB \"%s\"\n", prog_argv[0]);
176 fprintf(prof_file, "DATE \"%s\"\n", time_str());
178 fprintf(prof_file, "SAMPLE_UNIT \"seconds\"\n");
179 fprintf(prof_file, "VALUE_UNIT \"bytes\"\n");
181 fprintf(prof_file, "BEGIN_SAMPLE 0.00\n");
182 fprintf(prof_file, "END_SAMPLE 0.00\n");
184 #ifdef DEBUG_HEAP_PROF
185 DEBUG_LoadSymbols(prog_argv[0]);
197 endHeapProfiling(void)
201 if (! RtsFlags.ProfFlags.doHeapProfile) {
205 seconds = mut_user_time();
206 fprintf(prof_file, "BEGIN_SAMPLE %0.2f\n", seconds);
207 fprintf(prof_file, "END_SAMPLE %0.2f\n", seconds);
211 #ifdef DEBUG_HEAP_PROF
212 /* -----------------------------------------------------------------------------
213 Hash table for symbols.
214 -------------------------------------------------------------------------- */
222 #define SYMBOL_HASH_SIZE 0x3fff
224 symbol_info symbol_hash[SYMBOL_HASH_SIZE];
229 return ((W_)ptr)>>4 & 0x3fff;
237 for (i=0; i < SYMBOL_HASH_SIZE; i++) {
238 symbol_hash[i].ptr = NULL;
243 lookup_symbol(void *addr)
245 nat orig_bucket = hash(addr);
248 bucket = orig_bucket;
249 while (bucket < SYMBOL_HASH_SIZE && symbol_hash[bucket].ptr != NULL) {
250 if (symbol_hash[bucket].ptr == addr) {
255 if (bucket == SYMBOL_HASH_SIZE) {
257 while (bucket < orig_bucket && symbol_hash[bucket].ptr != NULL) {
258 if (symbol_hash[bucket].ptr == addr) {
263 if (bucket == orig_bucket) {
264 barf("out of symbol table space");
268 symbol_hash[bucket].ptr = addr;
269 lookupGHCName(addr,&symbol_hash[bucket].name);
270 symbol_hash[bucket].data = 0;
275 clear_table_data(void)
279 for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
280 symbol_hash[i].data = 0;
285 fprint_data(FILE *fp)
289 for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
290 if (symbol_hash[i].data) {
291 fprintf(fp, " %s %d\n", symbol_hash[i].name, symbol_hash[i].data);
297 add_data(void *addr, nat data)
299 symbol_hash[lookup_symbol(addr)].data += data;
302 /* -----------------------------------------------------------------------------
303 Closure Type Profiling;
305 PROBABLY TOTALLY OUT OF DATE -- ToDo (SDM)
306 -------------------------------------------------------------------------- */
308 static nat closure_types[N_CLOSURE_TYPES];
310 static char *type_names[] = {
316 , "CONSTR_NOCAF_STATIC"
354 , "MUT_ARR_PTRS_FROZEN"
369 fprint_closure_types(FILE *fp)
373 for (i = 0; i < N_CLOSURE_TYPES; i++) {
374 if (closure_types[i]) {
375 fprintf(fp, " %s %d\n", type_names[i], closure_types[i]);
380 #endif /* DEBUG_HEAP_PROF */
385 clearCCSResid(CostCentreStack *ccs)
391 for (i = ccs->indexTable; i != 0; i = i->next) {
393 clearCCSResid(i->ccs);
399 fprint_ccs(FILE *fp, CostCentreStack *ccs, nat components)
402 CostCentreStack *prev;
405 prev = ccs->prevStack;
408 || prev->cc->is_caf != CC_IS_BORING
409 || components == 1) {
410 fprintf(fp,"%s",cc->label);
414 fprint_ccs(fp, ccs->prevStack,components-1);
415 fprintf(fp,"/%s",cc->label);
420 reportCCSResid(FILE *fp, CostCentreStack *ccs)
424 if (ccs->mem_resid != 0) {
426 fprint_ccs(fp,ccs,2/*print 2 components only*/);
427 fprintf(fp," %ld\n", ccs->mem_resid * sizeof(W_));
430 for (i = ccs->indexTable; i != 0; i = i->next) {
432 reportCCSResid(fp,i->ccs);
442 const StgInfoTable *info;
447 #ifdef DEBUG_HEAP_PROF
448 switch (RtsFlags.ProfFlags.doHeapProfile) {
449 case HEAP_BY_INFOPTR:
452 case HEAP_BY_CLOSURE_TYPE:
455 memset(closure_types, 0, N_CLOSURE_TYPES * sizeof(nat));
464 switch (RtsFlags.ProfFlags.doHeapProfile) {
465 case NO_HEAP_PROFILING:
468 /* zero all the residency counters */
469 clearCCSResid(CCS_MAIN);
477 barf("heapCensus; doHeapProfile");
481 /* Only do heap profiling in a two-space heap */
482 ASSERT(RtsFlags.GcFlags.generations == 1);
485 time = mut_user_time_during_GC();
486 fprintf(prof_file, "BEGIN_SAMPLE %0.2f\n", time);
490 while (p < bd->free) {
491 info = get_itbl((StgClosure *)p);
493 switch (info->type) {
495 size = bco_sizeW((StgBCO *)p);
499 if (((StgClosure *)p)->header.info == &DEAD_WEAK_info) {
500 size = sizeofW(StgWeak);
503 /* else, fall through... */
508 case IND_OLDGEN_PERM:
510 case SE_CAF_BLACKHOLE:
520 case CONSTR_CHARLIKE:
534 size = sizeW_fromITBL(info);
537 case THUNK_1_0: /* ToDo - shouldn't be here */
538 case THUNK_0_1: /* " ditto " */
540 size = sizeofW(StgHeader) + MIN_UPD_SIZE;
543 case AP_UPD: /* we can treat this as being the same as a PAP */
545 size = pap_sizeW((StgPAP *)p);
549 size = arr_words_sizeW(stgCast(StgArrWords*,p));
553 case MUT_ARR_PTRS_FROZEN:
554 size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
558 size = tso_sizeW((StgTSO *)p);
565 #ifdef DEBUG_HEAP_PROF
566 switch (RtsFlags.ProfFlags.doHeapProfile) {
567 case HEAP_BY_INFOPTR:
568 add_data((void *)(*p), size * sizeof(W_));
570 case HEAP_BY_CLOSURE_TYPE:
571 closure_types[info->type] += size * sizeof(W_);
577 switch (RtsFlags.ProfFlags.doHeapProfile) {
579 ((StgClosure *)p)->header.prof.ccs->mem_resid += size;
582 strToCtr(((StgClosure *)p)->header.prof.ccs->cc->module)
586 strToCtr(get_itbl(((StgClosure *)p))->prof.closure_desc)->mem_resid
590 strToCtr(get_itbl(((StgClosure *)p))->prof.closure_type)->mem_resid
594 barf("heapCensus; doHeapProfile");
602 #ifdef DEBUG_HEAP_PROF
603 switch (RtsFlags.ProfFlags.doHeapProfile) {
604 case HEAP_BY_INFOPTR:
605 fprint_data(prof_file);
607 case HEAP_BY_CLOSURE_TYPE:
608 fprint_closure_types(prof_file);
614 switch (RtsFlags.ProfFlags.doHeapProfile) {
616 reportCCSResid(prof_file,CCS_MAIN);
621 reportCtrResid(prof_file);
624 barf("heapCensus; doHeapProfile");
628 fprintf(prof_file, "END_SAMPLE %0.2f\n", time);
631 #endif /* PROFILING || DEBUG_HEAP_PROF */