1 /* -----------------------------------------------------------------------------
2 * $Id: ProfHeap.c,v 1.12 2000/04/19 12:42:48 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 /* -----------------------------------------------------------------------------
38 * For profiling by module, constructor or closure type we need to be
39 * able to get from a string describing the category to a structure
40 * containing the counters for that category. The strings aren't
41 * unique (although gcc will do a fairly good job of commoning them up
42 * where possible), so we have a many->one mapping.
44 * We represent the many->one mapping with a hash table. In order to
45 * find the unique counter associated with a string the first time we
46 * encounter a particular string, we need another hash table, mapping
47 * hashed strings to buckets of counters. The string is hashed, then
48 * the bucket is searched for an existing counter for the same
51 * -------------------------------------------------------------------------- */
55 unsigned long mem_resid;
57 struct _ctr *next_bucket;
60 /* Linked list of all existing ctr structs */
63 /* Hash table mapping (char *) -> (struct _ctr) */
64 HashTable *str_to_ctr;
66 /* Hash table mapping hash_t (hashed string) -> (struct _ctr) */
67 HashTable *hashstr_to_ctrs;
70 initHashTables( void )
72 str_to_ctr = allocHashTable();
73 hashstr_to_ctrs = allocHashTable();
78 strToCtr(const char *str)
82 ctr = lookupHashTable( str_to_ctr, (W_)str );
84 if (ctr != NULL) { return ctr; }
87 hash_t str_hash = hash_str((char *)str);
90 ctr = lookupHashTable( hashstr_to_ctrs, (W_)str_hash );
93 for (; ctr != NULL; prev = ctr, ctr = ctr->next_bucket ) {
94 if (!strcmp(ctr->str, str)) {
95 insertHashTable( str_to_ctr, (W_)str, ctr );
97 fprintf(stderr,"strToCtr: existing ctr for `%s'\n",str);
103 ctr = stgMallocBytes(sizeof(prof_ctr), "strToCtr");
106 ctr->next_bucket = NULL;
107 ctr->next = all_ctrs;
111 fprintf(stderr,"strToCtr: new ctr for `%s'\n",str);
115 prev->next_bucket = ctr;
117 insertHashTable( hashstr_to_ctrs, str_hash, ctr );
119 insertHashTable( str_to_ctr, (W_)str, ctr);
125 clearCtrResid( void )
129 for (ctr = all_ctrs; ctr != NULL; ctr = ctr->next) {
135 reportCtrResid(FILE *fp)
139 for (ctr = all_ctrs; ctr != NULL; ctr = ctr->next) {
140 if (ctr->mem_resid != 0) {
141 fprintf(fp," %s %ld\n", ctr->str, ctr->mem_resid * sizeof(W_));
146 /* -------------------------------------------------------------------------- */
148 #ifdef DEBUG_HEAP_PROF
151 void initProfiling1( void )
155 void initProfiling2( void )
160 void endProfiling( void )
164 #endif /* DEBUG_HEAP_PROF */
167 initHeapProfiling(void)
169 if (! RtsFlags.ProfFlags.doHeapProfile) {
173 fprintf(hp_file, "JOB \"%s\"\n", prog_argv[0]);
174 fprintf(hp_file, "DATE \"%s\"\n", time_str());
176 fprintf(hp_file, "SAMPLE_UNIT \"seconds\"\n");
177 fprintf(hp_file, "VALUE_UNIT \"bytes\"\n");
179 fprintf(hp_file, "BEGIN_SAMPLE 0.00\n");
180 fprintf(hp_file, "END_SAMPLE 0.00\n");
182 #ifdef DEBUG_HEAP_PROF
183 DEBUG_LoadSymbols(prog_argv[0]);
195 endHeapProfiling(void)
199 if (! RtsFlags.ProfFlags.doHeapProfile) {
203 seconds = mut_user_time();
204 fprintf(hp_file, "BEGIN_SAMPLE %0.2f\n", seconds);
205 fprintf(hp_file, "END_SAMPLE %0.2f\n", seconds);
209 #ifdef DEBUG_HEAP_PROF
210 /* -----------------------------------------------------------------------------
211 Hash table for symbols.
212 -------------------------------------------------------------------------- */
220 #define SYMBOL_HASH_SIZE 0x3fff
222 symbol_info symbol_hash[SYMBOL_HASH_SIZE];
227 return ((W_)ptr)>>4 & 0x3fff;
235 for (i=0; i < SYMBOL_HASH_SIZE; i++) {
236 symbol_hash[i].ptr = NULL;
241 lookup_symbol(void *addr)
243 nat orig_bucket = hash(addr);
246 bucket = orig_bucket;
247 while (bucket < SYMBOL_HASH_SIZE && symbol_hash[bucket].ptr != NULL) {
248 if (symbol_hash[bucket].ptr == addr) {
253 if (bucket == SYMBOL_HASH_SIZE) {
255 while (bucket < orig_bucket && symbol_hash[bucket].ptr != NULL) {
256 if (symbol_hash[bucket].ptr == addr) {
261 if (bucket == orig_bucket) {
262 barf("out of symbol table space");
266 symbol_hash[bucket].ptr = addr;
267 lookupGHCName(addr,&symbol_hash[bucket].name);
268 symbol_hash[bucket].data = 0;
273 clear_table_data(void)
277 for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
278 symbol_hash[i].data = 0;
283 fprint_data(FILE *fp)
287 for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
288 if (symbol_hash[i].data) {
289 fprintf(fp, " %s %d\n", symbol_hash[i].name, symbol_hash[i].data);
295 add_data(void *addr, nat data)
297 symbol_hash[lookup_symbol(addr)].data += data;
300 /* -----------------------------------------------------------------------------
301 Closure Type Profiling;
303 PROBABLY TOTALLY OUT OF DATE -- ToDo (SDM)
304 -------------------------------------------------------------------------- */
306 static nat closure_types[N_CLOSURE_TYPES];
308 static char *type_names[] = {
314 , "CONSTR_NOCAF_STATIC"
352 , "MUT_ARR_PTRS_FROZEN"
367 fprint_closure_types(FILE *fp)
371 for (i = 0; i < N_CLOSURE_TYPES; i++) {
372 if (closure_types[i]) {
373 fprintf(fp, " %s %d\n", type_names[i], closure_types[i]);
378 #endif /* DEBUG_HEAP_PROF */
383 clearCCSResid(CostCentreStack *ccs)
389 for (i = ccs->indexTable; i != 0; i = i->next) {
391 clearCCSResid(i->ccs);
397 fprint_ccs(FILE *fp, CostCentreStack *ccs, nat components)
400 CostCentreStack *prev;
403 prev = ccs->prevStack;
406 || prev->cc->is_caf != CC_IS_BORING
407 || components == 1) {
408 fprintf(fp,"%s",cc->label);
412 fprint_ccs(fp, ccs->prevStack,components-1);
413 fprintf(fp,"/%s",cc->label);
418 reportCCSResid(FILE *fp, CostCentreStack *ccs)
422 if (ccs->mem_resid != 0) {
424 fprint_ccs(fp,ccs,2/*print 2 components only*/);
425 fprintf(fp," %ld\n", ccs->mem_resid * sizeof(W_));
428 for (i = ccs->indexTable; i != 0; i = i->next) {
430 reportCCSResid(fp,i->ccs);
440 const StgInfoTable *info;
445 #ifdef DEBUG_HEAP_PROF
446 switch (RtsFlags.ProfFlags.doHeapProfile) {
447 case HEAP_BY_INFOPTR:
450 case HEAP_BY_CLOSURE_TYPE:
453 memset(closure_types, 0, N_CLOSURE_TYPES * sizeof(nat));
462 switch (RtsFlags.ProfFlags.doHeapProfile) {
463 case NO_HEAP_PROFILING:
466 /* zero all the residency counters */
467 clearCCSResid(CCS_MAIN);
475 barf("heapCensus; doHeapProfile");
479 /* Only do heap profiling in a two-space heap */
480 ASSERT(RtsFlags.GcFlags.generations == 1);
483 time = mut_user_time_during_GC();
484 fprintf(hp_file, "BEGIN_SAMPLE %0.2f\n", time);
488 while (p < bd->free) {
489 info = get_itbl((StgClosure *)p);
491 switch (info->type) {
493 size = bco_sizeW((StgBCO *)p);
497 if (((StgClosure *)p)->header.info == &DEAD_WEAK_info) {
498 size = sizeofW(StgWeak);
501 /* else, fall through... */
506 case IND_OLDGEN_PERM:
508 case SE_CAF_BLACKHOLE:
518 case CONSTR_CHARLIKE:
532 size = sizeW_fromITBL(info);
535 case THUNK_1_0: /* ToDo - shouldn't be here */
536 case THUNK_0_1: /* " ditto " */
538 size = sizeofW(StgHeader) + MIN_UPD_SIZE;
541 case AP_UPD: /* we can treat this as being the same as a PAP */
543 size = pap_sizeW((StgPAP *)p);
547 size = arr_words_sizeW(stgCast(StgArrWords*,p));
551 case MUT_ARR_PTRS_FROZEN:
552 size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
556 size = tso_sizeW((StgTSO *)p);
563 #ifdef DEBUG_HEAP_PROF
564 switch (RtsFlags.ProfFlags.doHeapProfile) {
565 case HEAP_BY_INFOPTR:
566 add_data((void *)(*p), size * sizeof(W_));
568 case HEAP_BY_CLOSURE_TYPE:
569 closure_types[info->type] += size * sizeof(W_);
575 switch (RtsFlags.ProfFlags.doHeapProfile) {
577 ((StgClosure *)p)->header.prof.ccs->mem_resid += size;
580 strToCtr(((StgClosure *)p)->header.prof.ccs->cc->module)
584 strToCtr(get_itbl(((StgClosure *)p))->prof.closure_desc)->mem_resid
588 strToCtr(get_itbl(((StgClosure *)p))->prof.closure_type)->mem_resid
592 barf("heapCensus; doHeapProfile");
600 #ifdef DEBUG_HEAP_PROF
601 switch (RtsFlags.ProfFlags.doHeapProfile) {
602 case HEAP_BY_INFOPTR:
603 fprint_data(hp_file);
605 case HEAP_BY_CLOSURE_TYPE:
606 fprint_closure_types(hp_file);
612 switch (RtsFlags.ProfFlags.doHeapProfile) {
614 reportCCSResid(hp_file,CCS_MAIN);
619 reportCtrResid(hp_file);
622 barf("heapCensus; doHeapProfile");
626 fprintf(hp_file, "END_SAMPLE %0.2f\n", time);
629 #endif /* PROFILING || DEBUG_HEAP_PROF */