[project @ 2000-03-08 17:48:24 by simonmar]
[ghc-hetmet.git] / ghc / rts / ProfHeap.c
1 /* -----------------------------------------------------------------------------
2  * $Id: ProfHeap.c,v 1.6 2000/03/08 17:48:24 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-2000
5  *
6  * Support for heap profiling
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #if defined(DEBUG) && !defined(PROFILING)
11 #define DEBUG_HEAP_PROF
12 #else
13 #undef DEBUG_HEAP_PROF
14 #endif
15
16 #if defined(PROFILING) || defined(DEBUG_HEAP_PROF)
17
18 #include "Rts.h"
19 #include "RtsUtils.h"
20 #include "RtsFlags.h"
21 #include "ProfRts.h"
22 #include "Storage.h"
23 #include "ProfHeap.h"
24 #include "Stats.h"
25 #include "ProfRts.h"
26 #ifdef DEBUG_HEAP_PROF
27 #include "Printer.h"
28 static void initSymbolHash(void);
29 static void clear_table_data(void);
30 static void fprint_data(FILE *fp);
31 #endif
32
33 char prof_filename[128];        /* urk */
34
35 #ifdef DEBUG_HEAP_PROF
36 FILE *prof_file;
37
38 void initProfiling1( void )
39 {
40 }
41
42 void initProfiling2( void )
43 {
44   initHeapProfiling();
45 }
46
47 void endProfiling( void )
48 {
49   endHeapProfiling();
50 }
51 #endif /* DEBUG_HEAP_PROF */
52
53 nat
54 initHeapProfiling(void)
55 {
56     if (! RtsFlags.ProfFlags.doHeapProfile) {
57         return 0;
58     }
59
60     fprintf(prof_file, "JOB \"%s\"\n", prog_argv[0]);
61     fprintf(prof_file, "DATE \"%s\"\n", time_str());
62
63     fprintf(prof_file, "SAMPLE_UNIT \"seconds\"\n");
64     fprintf(prof_file, "VALUE_UNIT \"bytes\"\n");
65
66     fprintf(prof_file, "BEGIN_SAMPLE 0.00\n");
67     fprintf(prof_file, "END_SAMPLE 0.00\n");
68
69 #ifdef DEBUG_HEAP_PROF
70     DEBUG_LoadSymbols(prog_argv[0]);
71     initSymbolHash();
72 #endif
73
74     return 0;
75 }
76
77 void
78 endHeapProfiling(void)
79 {
80     StgDouble seconds;
81
82     if (! RtsFlags.ProfFlags.doHeapProfile) {
83         return;
84     }
85
86     seconds = mut_user_time();
87     fprintf(prof_file, "BEGIN_SAMPLE %0.2f\n", seconds);
88     fprintf(prof_file, "END_SAMPLE %0.2f\n", seconds);
89     fclose(prof_file);
90 }
91
92 #ifdef DEBUG_HEAP_PROF
93 /* -----------------------------------------------------------------------------
94    Hash table for symbols.
95    -------------------------------------------------------------------------- */
96
97 typedef struct {
98     const char *name;
99     void *ptr;
100     nat data;
101 } symbol_info;
102
103 #define SYMBOL_HASH_SIZE 0x3fff
104
105 symbol_info symbol_hash[SYMBOL_HASH_SIZE];
106
107 static inline nat
108 hash(void *ptr)
109 {
110     return ((W_)ptr)>>4 & 0x3fff;
111 }
112
113 static void
114 initSymbolHash(void)
115 {
116     nat i;
117
118     for (i=0; i < SYMBOL_HASH_SIZE; i++) {
119         symbol_hash[i].ptr = NULL;
120     }
121 }
122
123 static nat
124 lookup_symbol(void *addr)
125 {
126     nat orig_bucket = hash(addr);
127     nat bucket;
128
129     bucket = orig_bucket;
130     while (bucket < SYMBOL_HASH_SIZE && symbol_hash[bucket].ptr != NULL) {
131         if (symbol_hash[bucket].ptr == addr) {
132             return bucket;
133         }
134         bucket++;
135     }
136     if (bucket == SYMBOL_HASH_SIZE) {
137         bucket = 0;
138         while (bucket < orig_bucket && symbol_hash[bucket].ptr != NULL) {
139             if (symbol_hash[bucket].ptr == addr) {
140                 return bucket;
141             }
142             bucket++;
143         }
144         if (bucket == orig_bucket) {
145             barf("out of symbol table space");
146         }
147     }
148     
149     symbol_hash[bucket].ptr  = addr;
150     lookupGHCName(addr,&symbol_hash[bucket].name);
151     symbol_hash[bucket].data = 0;
152     return bucket;
153 }
154
155 static void
156 clear_table_data(void)
157 {
158     nat i;
159
160     for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
161         symbol_hash[i].data = 0;
162     }
163 }
164
165 static void
166 fprint_data(FILE *fp)
167 {
168     nat i;
169     
170     for (i = 0; i < SYMBOL_HASH_SIZE; i++) {
171         if (symbol_hash[i].data) {
172             fprintf(fp, "   %s %d\n", symbol_hash[i].name, symbol_hash[i].data);
173         }
174     }
175 }
176
177 static inline void
178 add_data(void *addr, nat data)
179 {
180     symbol_hash[lookup_symbol(addr)].data += data;
181 }
182
183 /* -----------------------------------------------------------------------------
184    Closure Type Profiling;
185
186    PROBABLY TOTALLY OUT OF DATE -- ToDo (SDM)
187    -------------------------------------------------------------------------- */
188
189 static nat closure_types[N_CLOSURE_TYPES];
190
191 static char *type_names[] = {
192       "INVALID_OBJECT"
193     , "CONSTR"
194     , "CONSTR_INTLIKE"
195     , "CONSTR_CHARLIKE"
196     , "CONSTR_STATIC"
197     , "CONSTR_NOCAF_STATIC"
198
199     , "FUN"
200     , "FUN_STATIC"
201
202     , "THUNK"
203     , "THUNK_STATIC"
204     , "THUNK_SELECTOR"
205
206     , "BCO"
207     , "AP_UPD"
208
209     , "PAP"
210
211     , "IND"
212     , "IND_OLDGEN"
213     , "IND_PERM"
214     , "IND_OLDGEN_PERM"
215     , "IND_STATIC"
216
217     , "RET_BCO"
218     , "RET_SMALL"
219     , "RET_VEC_SMALL"
220     , "RET_BIG"
221     , "RET_VEC_BIG"
222     , "RET_DYN"
223     , "UPDATE_FRAME"
224     , "CATCH_FRAME"
225     , "STOP_FRAME"
226     , "SEQ_FRAME"
227
228     , "BLACKHOLE"
229     , "BLACKHOLE_BQ"
230     , "MVAR"
231
232     , "ARR_WORDS"
233
234     , "MUT_ARR_PTRS"
235     , "MUT_ARR_PTRS_FROZEN"
236     , "MUT_VAR"
237
238     , "WEAK"
239     , "FOREIGN"
240   
241     , "TSO"
242
243     , "BLOCKED_FETCH"
244     , "FETCH_ME"
245
246     , "EVACUATED"
247 };
248
249 static void 
250 fprint_closure_types(FILE *fp)
251 {
252   nat i;
253
254   for (i = 0; i < N_CLOSURE_TYPES; i++) {
255     if (closure_types[i]) {
256       fprintf(fp, "   %s %d\n", type_names[i], closure_types[i]);
257     }
258   }
259 }
260
261 #endif /* DEBUG_HEAP_PROF */
262
263
264 #ifdef PROFILING
265 static void
266 clearCCSResid(CostCentreStack *ccs)
267 {
268   IndexTable *i;
269
270   ccs->mem_resid = 0;
271
272   for (i = ccs->indexTable; i != 0; i = i->next) {
273     clearCCSResid(i->ccs);
274   }
275 }
276
277 static void
278 fprint_ccs(FILE *fp, CostCentreStack *ccs, nat components)
279 {
280   CostCentre *cc;
281   CostCentreStack *prev;
282
283   cc = ccs->cc;
284   prev = ccs->prevStack;
285
286   if (prev == NULL
287       || prev->cc->is_subsumed != CC_IS_BORING
288       || components == 1) { 
289     fprintf(fp,"%s",cc->label);
290     return; 
291
292   } else {
293     fprint_ccs(fp, ccs->prevStack,components-1);
294     fprintf(fp,"/%s",cc->label);
295   }
296 }
297
298 static void
299 reportCCSResid(FILE *fp, CostCentreStack *ccs)
300 {
301   IndexTable *i;
302
303   if (ccs->mem_resid != 0) {
304     fprintf(fp,"   ");
305     fprint_ccs(fp,ccs,2/*print 2 components only*/);
306     fprintf(fp," %ld\n", ccs->mem_resid * sizeof(W_));
307   }
308
309   for (i = ccs->indexTable; i != 0; i = i->next) {
310     reportCCSResid(fp,i->ccs);
311   }
312 }
313 #endif
314
315 void
316 heapCensus(void)
317 {
318   bdescr *bd;
319   const StgInfoTable *info;
320   StgDouble time;
321   nat size;
322   StgPtr p;
323   
324 #ifdef DEBUG_HEAP_PROF
325   switch (RtsFlags.ProfFlags.doHeapProfile) {
326   case HEAP_BY_INFOPTR:
327     clear_table_data();
328     break;
329   case HEAP_BY_CLOSURE_TYPE:
330     memset(closure_types, 0, N_CLOSURE_TYPES * sizeof(nat));
331     break;
332   default:
333     return;
334   }
335 #endif
336
337 #ifdef PROFILING
338   switch (RtsFlags.ProfFlags.doHeapProfile) {
339   case NO_HEAP_PROFILING:
340     return;
341   case HEAP_BY_CCS:
342     break;
343   default:
344     barf("heapCensus; doHeapProfile");
345   }
346   /* zero all the residency counters */
347   clearCCSResid(CCS_MAIN);
348 #endif
349
350   /* Only do heap profiling in a two-space heap */
351   ASSERT(RtsFlags.GcFlags.generations == 1);
352   bd = g0s0->to_space;
353
354   time = mut_user_time_during_GC();
355   fprintf(prof_file, "BEGIN_SAMPLE %0.2f\n", time);
356   
357   while (bd != NULL) {
358     p = bd->start;
359     while (p < bd->free) {
360       info = get_itbl((StgClosure *)p);
361
362       switch (info->type) {
363       case BCO:
364         size = bco_sizeW((StgBCO *)p);
365         break;
366         
367       case CONSTR:
368         if (((StgClosure *)p)->header.info == &DEAD_WEAK_info) {
369           size = sizeofW(StgWeak);
370           break;
371         }
372         /* else, fall through... */
373
374       case FUN:
375       case THUNK:
376       case IND_PERM:
377       case IND_OLDGEN_PERM:
378       case CAF_BLACKHOLE:
379       case SE_CAF_BLACKHOLE:
380       case SE_BLACKHOLE:
381       case BLACKHOLE:
382       case BLACKHOLE_BQ:
383       case WEAK:
384       case FOREIGN:
385       case STABLE_NAME:
386       case MVAR:
387       case MUT_VAR:
388       case CONSTR_INTLIKE:
389       case CONSTR_CHARLIKE:
390       case FUN_1_0:
391       case FUN_0_1:
392       case FUN_1_1:
393       case FUN_0_2:
394       case FUN_2_0:
395       case THUNK_1_0:
396       case THUNK_0_1:
397       case THUNK_1_1:
398       case THUNK_0_2:
399       case THUNK_2_0:
400       case CONSTR_1_0:
401       case CONSTR_0_1:
402       case CONSTR_1_1:
403       case CONSTR_0_2:
404       case CONSTR_2_0:
405         size = sizeW_fromITBL(info);
406         break;
407         
408       case THUNK_SELECTOR:
409         size = sizeofW(StgHeader) + MIN_UPD_SIZE;
410         break;
411         
412       case AP_UPD: /* we can treat this as being the same as a PAP */
413       case PAP:
414         size = pap_sizeW((StgPAP *)p);
415         break;
416         
417       case ARR_WORDS:
418         size = arr_words_sizeW(stgCast(StgArrWords*,p));
419         break;
420         
421       case MUT_ARR_PTRS:
422       case MUT_ARR_PTRS_FROZEN:
423         size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
424         break;
425         
426       case TSO:
427         size = tso_sizeW((StgTSO *)p);
428         break;
429         
430       default:
431         barf("heapCensus");
432       }
433
434 #ifdef DEBUG_HEAP_PROF
435       switch (RtsFlags.ProfFlags.doHeapProfile) {
436       case HEAP_BY_INFOPTR:
437         add_data((void *)(*p), size * sizeof(W_));
438         break;
439       case HEAP_BY_CLOSURE_TYPE:
440         closure_types[info->type] += size * sizeof(W_);
441         break;
442       }
443 #endif
444
445 #ifdef PROFILING      
446       ((StgClosure *)p)->header.prof.ccs->mem_resid += size;
447 #endif
448       p += size;
449     }
450     bd = bd->link;
451   }
452
453 #ifdef DEBUG_HEAP_PROF
454   switch (RtsFlags.ProfFlags.doHeapProfile) {
455   case HEAP_BY_INFOPTR:
456     fprint_data(prof_file);
457     break;
458   case HEAP_BY_CLOSURE_TYPE:
459     fprint_closure_types(prof_file);
460     break;
461   }
462 #endif
463     
464 #ifdef PROFILING
465   reportCCSResid(prof_file,CCS_MAIN);
466 #endif
467
468   fprintf(prof_file, "END_SAMPLE %0.2f\n", time);
469 }    
470
471 #endif /* PROFILING || DEBUG_HEAP_PROF */
472