1 /* -----------------------------------------------------------------------------
2 * $Id: ProfHeap.c,v 1.4 2000/03/07 11:53:12 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)
26 #ifdef DEBUG_HEAP_PROF
28 static void initSymbolHash(void);
29 static void clear_table_data(void);
30 static void fprint_data(FILE *fp);
33 char prof_filename[128]; /* urk */
35 #ifdef DEBUG_HEAP_PROF
36 void initProfiling( void )
41 void endProfiling( void )
45 #endif /* DEBUG_HEAP_PROF */
48 initHeapProfiling(void)
50 if (! RtsFlags.ProfFlags.doHeapProfile) {
54 fprintf(prof_file, "JOB \"%s\"\n", prog_argv[0]);
55 fprintf(prof_file, "DATE \"%s\"\n", time_str());
57 fprintf(prof_file, "SAMPLE_UNIT \"seconds\"\n");
58 fprintf(prof_file, "VALUE_UNIT \"bytes\"\n");
60 fprintf(prof_file, "BEGIN_SAMPLE 0.00\n");
61 fprintf(prof_file, "END_SAMPLE 0.00\n");
63 #ifdef DEBUG_HEAP_PROF
64 DEBUG_LoadSymbols(prog_argv[0]);
72 endHeapProfiling(void)
76 if (! RtsFlags.ProfFlags.doHeapProfile) {
80 seconds = mut_user_time();
81 fprintf(prof_file, "BEGIN_SAMPLE %0.2f\n", seconds);
82 fprintf(prof_file, "END_SAMPLE %0.2f\n", seconds);
86 #ifdef DEBUG_HEAP_PROF
87 /* -----------------------------------------------------------------------------
88 Hash table for symbols.
89 -------------------------------------------------------------------------- */
97 #define SYMBOL_HASH_SIZE 0x3fff
99 symbol_info symbol_hash[SYMBOL_HASH_SIZE];
104 return ((W_)ptr)>>4 & 0x3fff;
112 for (i=0; i < SYMBOL_HASH_SIZE; i++) {
113 symbol_hash[i].ptr = NULL;
118 lookup_symbol(void *addr)
120 nat orig_bucket = hash(addr);
123 bucket = orig_bucket;
124 while (bucket < SYMBOL_HASH_SIZE && symbol_hash[bucket].ptr != NULL) {
125 if (symbol_hash[bucket].ptr == addr) {
130 if (bucket == SYMBOL_HASH_SIZE) {
132 while (bucket < orig_bucket && symbol_hash[bucket].ptr != NULL) {
133 if (symbol_hash[bucket].ptr == addr) {
138 if (bucket == orig_bucket) {
139 barf("out of symbol table space");
143 symbol_hash[bucket].ptr = addr;
144 lookupGHCName(addr,&symbol_hash[bucket].name);
145 symbol_hash[bucket].data = 0;
150 clear_table_data(void)
154 for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
155 symbol_hash[i].data = 0;
160 fprint_data(FILE *fp)
164 for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
165 if (symbol_hash[i].data) {
166 fprintf(fp, " %s %d\n", symbol_hash[i].name, symbol_hash[i].data);
172 add_data(void *addr, nat data)
174 symbol_hash[lookup_symbol(addr)].data += data;
177 /* -----------------------------------------------------------------------------
178 Closure Type Profiling;
180 PROBABLY TOTALLY OUT OF DATE -- ToDo (SDM)
181 -------------------------------------------------------------------------- */
183 static nat closure_types[N_CLOSURE_TYPES];
185 static char *type_names[] = {
191 , "CONSTR_NOCAF_STATIC"
229 , "MUT_ARR_PTRS_FROZEN"
244 fprint_closure_types(FILE *fp)
248 for (i = 0; i < N_CLOSURE_TYPES; i++) {
249 if (closure_types[i]) {
250 fprintf(fp, " %s %d\n", type_names[i], closure_types[i]);
255 #endif /* DEBUG_HEAP_PROF */
260 clearCCSResid(CostCentreStack *ccs)
266 for (i = ccs->indexTable; i != 0; i = i->next) {
267 clearCCSResid(i->ccs);
272 fprint_ccs(FILE *fp, CostCentreStack *ccs, nat components)
275 CostCentreStack *prev;
278 prev = ccs->prevStack;
281 || prev->cc->is_subsumed != CC_IS_BORING
282 || components == 1) {
283 fprintf(fp,"%s",cc->label);
287 fprint_ccs(fp, ccs->prevStack,components-1);
288 fprintf(fp,"/%s",cc->label);
293 reportCCSResid(FILE *fp, CostCentreStack *ccs)
297 if (ccs->mem_resid != 0) {
299 fprint_ccs(fp,ccs,2/*print 2 components only*/);
300 fprintf(fp," %ld\n", ccs->mem_resid * sizeof(W_));
303 for (i = ccs->indexTable; i != 0; i = i->next) {
304 reportCCSResid(fp,i->ccs);
313 const StgInfoTable *info;
318 #ifdef DEBUG_HEAP_PROF
319 switch (RtsFlags.ProfFlags.doHeapProfile) {
320 case HEAP_BY_INFOPTR:
323 case HEAP_BY_CLOSURE_TYPE:
324 memset(closure_types, 0, N_CLOSURE_TYPES * sizeof(nat));
332 switch (RtsFlags.ProfFlags.doHeapProfile) {
333 case NO_HEAP_PROFILING:
338 barf("heapCensus; doHeapProfile");
340 /* zero all the residency counters */
341 clearCCSResid(CCS_MAIN);
344 /* Only do heap profiling in a two-space heap */
345 ASSERT(RtsFlags.GcFlags.generations == 1);
348 time = mut_user_time_during_GC();
349 fprintf(prof_file, "BEGIN_SAMPLE %0.2f\n", time);
353 while (p < bd->free) {
354 info = get_itbl((StgClosure *)p);
356 switch (info->type) {
358 size = bco_sizeW((StgBCO *)p);
362 if (((StgClosure *)p)->header.info == &DEAD_WEAK_info) {
363 size = sizeofW(StgWeak);
366 /* else, fall through... */
371 case IND_OLDGEN_PERM:
373 case SE_CAF_BLACKHOLE:
383 case CONSTR_CHARLIKE:
399 size = sizeW_fromITBL(info);
403 size = sizeofW(StgHeader) + MIN_UPD_SIZE;
406 case AP_UPD: /* we can treat this as being the same as a PAP */
408 size = pap_sizeW((StgPAP *)p);
412 size = arr_words_sizeW(stgCast(StgArrWords*,p));
416 case MUT_ARR_PTRS_FROZEN:
417 size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
421 size = tso_sizeW((StgTSO *)p);
428 #ifdef DEBUG_HEAP_PROF
429 switch (RtsFlags.ProfFlags.doHeapProfile) {
430 case HEAP_BY_INFOPTR:
431 add_data((void *)(*p), size * sizeof(W_));
433 case HEAP_BY_CLOSURE_TYPE:
434 closure_types[info->type] += size * sizeof(W_);
440 ((StgClosure *)p)->header.prof.ccs->mem_resid += size;
447 #ifdef DEBUG_HEAP_PROF
448 switch (RtsFlags.ProfFlags.doHeapProfile) {
449 case HEAP_BY_INFOPTR:
450 fprint_data(prof_file);
452 case HEAP_BY_CLOSURE_TYPE:
453 fprint_closure_types(prof_file);
459 reportCCSResid(prof_file,CCS_MAIN);
462 fprintf(prof_file, "END_SAMPLE %0.2f\n", time);
465 #endif /* PROFILING || DEBUG_HEAP_PROF */