1 Only have cost centres etc if @PROFILING@ defined
5 Some of the code in here is pretty hairy for the compiler to deal
6 with after we've swiped all of the useful registers. I don't believe
7 any STG registers are live here, but I'm not completely certain.
9 Any specific routines that require the preservation of caller-saves
10 STG registers should be pulled out into another file and compiled
11 with the the appropriate register map. (Presumably one of the GC
12 register mappings?) --JSM
16 #include "../storage/SMinternal.h" /* for ???? */
18 #if defined (PROFILING)
21 %************************************************************************
23 \subsection[heap-profiling]{Heap Profiling}
25 %************************************************************************
27 The heap profiling reports the amount of heap space occupied by live
28 closures pressent in the heap during a garbage collection. This
29 profile may be broken down in a number of ways:
31 \item {\bf Cost Centre:} The cost centres responsible for building the
32 various closures in the heap.
33 \item {\bf Module:} Aggregation of all the cost centres declared in a module.
34 \item {\bf Group:} Aggregation of all the cost centres declared in a group.
35 \item {\bf Closure Description:} The heap occupied by closures with a particular description (normally the data constructor).
36 \item {\bf Type Description:} The heap occupied by closures with a particular type (normally the type constructor).
37 \item {\bf Production time stamp:} The heap occupied by closures of produced during a particular time interval.
40 Relevant closures may be selected by the Cost Centre (label, module
41 and group), by Closure Category (description, type, and kind) and/or
42 by age. A cost centre will be selected if its label, module or group
43 is selected (default is all). A closure category will be selected if
44 its description, type or kind is selected (default is all). A closure
45 will be selected if both its cost centre, closure category and age are
48 When recording the size of the heap objects the additional profiling
49 etc words are disregarded. The profiling itself is considered an
50 idealised process which should not affect the statistics gathered.
55 static char heap_profiling_char[] /* indexed by RTSflags.ProfFlags.doHeapProfile */
56 = {'?', CCchar, MODchar, GRPchar, DESCRchar, TYPEchar, TIMEchar};
58 static I_ cc_select = 0; /* are we selecting on Cost Centre */
59 static I_ clcat_select = 0; /* are we selecting on Closure Category*/
61 static I_ cc_select_no = 0;
62 static char *cc_select_strs[MAX_SELECT];
63 static char *ccmod_select_strs[MAX_SELECT];
65 static I_ mod_select_no = 0;
66 static char *mod_select_strs[MAX_SELECT];
67 static I_ grp_select_no = 0;
68 static char *grp_select_strs[MAX_SELECT];
70 static I_ descr_select_no = 0;
71 static char *descr_select_strs[MAX_SELECT];
72 static I_ type_select_no = 0;
73 static char *type_select_strs[MAX_SELECT];
74 static I_ kind_select_no = 0;
75 static I_ kind_selected[] = {0, 0, 0, 0, 0, 0};
76 static char *kind_select_strs[] = {"","CON","FN","PAP","THK","BH",0};
78 I_ *resid = 0; /* residencies indexed by hashed feature */
80 /* For production times we have a resid table of time_intervals */
81 /* And a seperate resid counter stuff produced earlier & later */
85 I_ resid_max = 0; /* Max residency -- used for aux file */
87 I_ earlier_ticks = 0; /* No of earlier ticks grouped together */
88 hash_t time_intervals = 18; /* No of time_intervals, also earlier & later */
90 static hash_t earlier_intervals; /* No of earlier intervals grouped together + 1*/
93 dummy_index_time(STG_NO_ARGS)
95 return time_intervals;
98 hash_t (* init_index_fns[])() = {
108 static char heap_filename[STATS_FILENAME_MAXLEN]; /* heap log file name = <program>.hp */
109 static FILE *heap_file = NULL;
112 heap_profile_init(argv)
115 char *cc_select_str = RTSflags.ProfFlags.ccSelector;
116 char *mod_select_str = RTSflags.ProfFlags.modSelector;
117 char *grp_select_str = RTSflags.ProfFlags.grpSelector;
118 char *descr_select_str = RTSflags.ProfFlags.descrSelector;
119 char *type_select_str = RTSflags.ProfFlags.typeSelector;
120 char *kind_select_str = RTSflags.ProfFlags.kindSelector;
122 hash_t count, max, first;
125 if (! RTSflags.ProfFlags.doHeapProfile)
128 /* for now, if using a generational collector and trying
129 to heap-profile, just force the GC to be used in two-space mode.
132 #if defined(GCap) || defined(GCgn)
133 RTSflags.GcFlags.force2s = rtsTrue;
136 heap_prof_style = RTSflags.ProfFlags.doHeapProfile;
138 /* process select strings -- will break them into bits */
142 while (cc_select_str && cc_select_no < MAX_SELECT) {
143 if ((comma = strchr(cc_select_str, ',')) != 0) {
146 if ((colon = strchr(cc_select_str, ':')) != 0) {
148 ccmod_select_strs[cc_select_no] = cc_select_str;
149 cc_select_strs[cc_select_no++] = colon + 1;
151 ccmod_select_strs[cc_select_no] = (char *)0;
152 cc_select_strs[cc_select_no++] = cc_select_str;
155 cc_select_str = comma + 1;
157 cc_select_str = (char *)0;
160 if (cc_select_str && cc_select_no >= MAX_SELECT) {
161 fprintf(stderr, "heap_profile_init: Too many Cost Centres selected\n %ld used %s remaining\n",
162 cc_select_no, cc_select_str);
165 cc_select |= cc_select_no > 0;
167 if (mod_select_str) {
169 while ((comma = strchr(mod_select_str, ',')) && mod_select_no < MAX_SELECT) {
170 mod_select_strs[mod_select_no++] = mod_select_str;
172 mod_select_str = comma + 1;
174 if (mod_select_no < MAX_SELECT) {
175 mod_select_strs[mod_select_no++] = mod_select_str;
177 fprintf(stderr, "heap_profile_init: Too many Modules selected\n %ld used %s remaining\n",
178 mod_select_no, mod_select_str);
181 cc_select |= mod_select_no > 0;
183 if (grp_select_str) {
185 while ((comma = strchr(grp_select_str, ',')) && grp_select_no < MAX_SELECT) {
186 grp_select_strs[grp_select_no++] = grp_select_str;
188 grp_select_str = comma + 1;
190 if (grp_select_no < MAX_SELECT) {
191 grp_select_strs[grp_select_no++] = grp_select_str;
193 fprintf(stderr, "heap_profile_init: Too many Groups selected\n %ld used %s remaining\n",
194 grp_select_no, grp_select_str);
197 cc_select |= grp_select_no > 0;
200 if (descr_select_str) {
202 while ((comma = strchr(descr_select_str, ',')) && descr_select_no < MAX_SELECT) {
203 descr_select_strs[descr_select_no++] = descr_select_str;
205 descr_select_str = comma + 1;
207 if (descr_select_no < MAX_SELECT) {
208 descr_select_strs[descr_select_no++] = descr_select_str;
210 fprintf(stderr, "heap_profile_init: Too many Closure Descriptions selected\n %ld used %s remaining\n",
211 descr_select_no, descr_select_str);
214 clcat_select |= descr_select_no > 0;
216 if (type_select_str) {
218 while ((comma = strchr(type_select_str, ',')) && type_select_no < MAX_SELECT) {
219 type_select_strs[type_select_no++] = type_select_str;
221 type_select_str = comma + 1;
223 if (type_select_no < MAX_SELECT) {
224 type_select_strs[type_select_no++] = type_select_str;
226 fprintf(stderr, "heap_profile_init: Too many Closure Types selected\n %ld used %s remaining\n",
227 type_select_no, type_select_str);
230 clcat_select |= type_select_no > 0;
232 if (kind_select_str) {
234 while ((comma = strchr(kind_select_str, ',')) != 0) {
236 for (count = 1; kind_select_strs[count]; count++) {
237 if (strcmp(kind_select_strs[count],kind_select_str) == 0) {
238 kind_selected[count] = 1;
243 if (! kind_select_strs[count]) {
244 fprintf(stderr, "heap_profile_init: Invalid Kind: %s\n", kind_select_str);
247 kind_select_str = comma + 1;
249 for (count = 1; kind_select_strs[count]; count++) {
250 if (strcmp(kind_select_strs[count],kind_select_str) == 0) {
251 kind_selected[count] = 1;
256 if (! kind_select_strs[count]) {
257 fprintf(stderr, "heap_profile_init: Invalid Kind: %s\n", kind_select_str);
260 clcat_select |= kind_select_no > 0;
263 /* open heap profiling log file */
265 sprintf(heap_filename, HP_FILENAME_FMT, argv[0]);
266 if ( (heap_file = fopen(heap_filename,"w")) == NULL ) {
267 fprintf(stderr, "Can't open heap log file %s\n", heap_filename);
271 /* write start of log file */
273 fprintf(heap_file, "JOB \"%s", argv[0]);
274 fprintf(heap_file, " +RTS -h%c", heap_profiling_char[heap_prof_style]);
275 if (heap_prof_style == HEAP_BY_TIME) {
276 fprintf(heap_file, "%ld", time_intervals);
278 fprintf(heap_file, ",%3.1f",
279 earlier_ticks / (StgFloat)TICK_FREQUENCY);
283 fprintf(heap_file, " -c{%s:%s",
284 ccmod_select_strs[0],
286 for (count = 1; count < cc_select_no; count++) {
287 fprintf(heap_file, ",%s:%s",
288 ccmod_select_strs[count],
289 cc_select_strs[count]);
291 fprintf(heap_file, "}");
294 fprintf(heap_file, " -m{%s", mod_select_strs[0]);
295 for (count = 1; count < mod_select_no; count++)
296 fprintf(heap_file, ",%s", mod_select_strs[count]);
297 fprintf(heap_file, "}");
300 fprintf(heap_file, " -g{%s", grp_select_strs[0]);
301 for (count = 1; count < grp_select_no; count++)
302 fprintf(heap_file, ",%s", grp_select_strs[count]);
303 fprintf(heap_file, "}");
305 if (descr_select_no) {
306 fprintf(heap_file, " -d{%s", descr_select_strs[0]);
307 for (count = 1; count < descr_select_no; count++)
308 fprintf(heap_file, ",%s", descr_select_strs[count]);
309 fprintf(heap_file, "}");
311 if (type_select_no) {
312 fprintf(heap_file, " -y{%s", type_select_strs[0]);
313 for (count = 1; count < type_select_no; count++)
314 fprintf(heap_file, ",%s", type_select_strs[count]);
315 fprintf(heap_file, "}");
317 if (kind_select_no) {
318 fprintf(heap_file, " -k{");
319 for (count = 1, first = 1; kind_select_strs[count]; count++)
320 if (kind_selected[count]) {
321 fprintf(heap_file, "%s%s", first?"":",", kind_select_strs[count]);
324 fprintf(heap_file, "}");
327 fprintf(heap_file, " -i%4.2f -RTS", interval_ticks/(StgFloat)TICK_FREQUENCY);
328 for(count = 1; argv[count]; count++)
329 fprintf(heap_file, " %s", argv[count]);
330 fprintf(heap_file, "\"\n");
332 fprintf(heap_file, "DATE \"%s\"\n", time_str());
334 fprintf(heap_file, "SAMPLE_UNIT \"seconds\"\n");
335 fprintf(heap_file, "VALUE_UNIT \"bytes\"\n");
337 fprintf(heap_file, "BEGIN_SAMPLE 0.00\n");
338 fprintf(heap_file, "END_SAMPLE 0.00\n");
341 /* initialise required heap profiling data structures & hashing */
343 earlier_intervals = (earlier_ticks / interval_ticks) + 1;
344 max = (* init_index_fns[heap_prof_style])();
345 resid = (I_ *) stgMallocBytes(max * sizeof(I_), "heap_profile_init");
347 for (count = 0; count < max; count++)
354 Cost centre selection is set up before a heap profile by running
355 through the list of registered cost centres and memoising the
356 selection in the cost centre record. It is only necessary to memoise
357 the cost centre selection if a selection profiling function is
360 Category selection is determined when each closure is encountered. It
361 is memoised within the category record. We always have to check that
362 the memoisation has been done as we do not have a list of categories
363 we can process before hand.
365 Age selection is done for every closure -- not memoised.
369 set_selected_ccs(STG_NO_ARGS) /* set selection before we profile heap */
375 for (cc = Registered_CC; cc != REGISTERED_END; cc = cc->registered) {
376 for (x = 0; ! cc->selected && x < cc_select_no; x++)
377 cc->selected = (strcmp(cc->label, cc_select_strs[x]) == 0) &&
378 (strcmp(cc->module, ccmod_select_strs[x]) == 0);
379 for (x = 0; ! cc->selected && x < mod_select_no; x++)
380 cc->selected = (strcmp(cc->module, mod_select_strs[x]) == 0);
381 for (x = 0; ! cc->selected && x < grp_select_no; x++)
382 cc->selected = (strcmp(cc->group, grp_select_strs[x]) == 0);
385 for (cc = Registered_CC; cc != REGISTERED_END; cc = cc->registered)
386 cc->selected = 1; /* true if ! cc_select */
392 selected_clcat(ClCategory clcat)
396 if (clcat->selected == -1) { /* if not memoised check selection */
399 for (x = 0; ! clcat->selected && x < descr_select_no; x++)
400 clcat->selected = (strcmp(clcat->descr, descr_select_strs[x]) == 0);
401 for (x = 0; ! clcat->selected && x < type_select_no; x++)
402 clcat->selected = (strcmp(clcat->type, type_select_strs[x]) == 0);
403 if (kind_select_no) clcat->selected |= kind_selected[clcat->kind];
408 return clcat->selected; /* return memoised selection */
413 Profiling functions called for each closure. The appropriate function
414 is stored in @heap_profile_fn@ by @heap_profile_setup@.
415 @heap_profile_fn@ is called for each live closure by the macros
416 embedded in the garbage collector. They increment the appropriate
417 resident space counter by the size of the closure (less any profiling
421 #define NON_PROF_HS (FIXED_HS - PROF_FIXED_HDR - TICKY_FIXED_HDR)
424 profile_closure_cc(P_ closure, I_ size)
426 CostCentre cc = (CostCentre) CC_HDR(closure);
427 resid[index_cc(cc)] += size + NON_PROF_HS;
432 profile_closure_cc_select(P_ closure, I_ size)
434 CostCentre cc; ClCategory clcat;
436 cc = (CostCentre) CC_HDR(closure);
437 if (! cc->selected) /* selection determined before profile */
438 return; /* all selected if ! cc_select */
440 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
441 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
444 resid[index_cc(cc)] += size + NON_PROF_HS;
449 profile_closure_mod(P_ closure, I_ size)
451 CostCentre cc = (CostCentre) CC_HDR(closure);
452 resid[index_mod(cc)] += size + NON_PROF_HS;
457 profile_closure_mod_select(P_ closure, I_ size)
459 CostCentre cc; ClCategory clcat;
461 cc = (CostCentre) CC_HDR(closure);
462 if (! cc->selected) /* selection determined before profile */
465 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
466 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
469 resid[index_mod(cc)] += size + NON_PROF_HS;
474 profile_closure_grp(P_ closure, I_ size)
476 CostCentre cc = (CostCentre) CC_HDR(closure);
477 resid[index_grp(cc)] += size + NON_PROF_HS;
482 profile_closure_grp_select(P_ closure, I_ size)
484 CostCentre cc; ClCategory clcat;
486 cc = (CostCentre) CC_HDR(closure);
487 if (! cc->selected) /* selection determined before profile */
490 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
491 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
494 resid[index_grp(cc)] += size + NON_PROF_HS;
499 profile_closure_descr(P_ closure, I_ size)
501 ClCategory clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
502 resid[index_descr(clcat)] += size + NON_PROF_HS;
507 profile_closure_descr_select(P_ closure, I_ size)
509 CostCentre cc; ClCategory clcat;
511 cc = (CostCentre) CC_HDR(closure);
512 if (! cc->selected) /* selection determined before profile */
513 return; /* all selected if ! cc_select */
515 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
516 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
519 resid[index_descr(clcat)] += size + NON_PROF_HS;
524 profile_closure_type(P_ closure, I_ size)
526 ClCategory clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
527 resid[index_type(clcat)] += size + NON_PROF_HS;
532 profile_closure_type_select(P_ closure, I_ size)
534 CostCentre cc; ClCategory clcat;
536 cc = (CostCentre) CC_HDR(closure);
537 if (! cc->selected) /* selection determined before profile */
538 return; /* all selected if ! cc_select */
540 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
541 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
544 resid[index_type(clcat)] += size + NON_PROF_HS;
549 profile_closure_time(P_ closure, I_ size)
555 profile_closure_time_select(P_ closure, I_ size)
561 @heap_profile_setup@ is called before garbage collection to initialise
562 for the profile. It assigns the appropriate closure profiling function
563 to @heap_profile_fn@ and memoises any cost centre selection. If no
564 profile is required @heap_profile_fn@ is assigned NULL.
566 On completion of garbage collection @heap_profile_done@ is called. It
567 produces a heap profile report and resets the residency counts to 0.
571 void (* heap_profile_fn) PROTO((P_,I_)) = NULL;
573 void (* profiling_fns_select[]) PROTO((P_,I_)) = {
575 profile_closure_cc_select,
576 profile_closure_mod_select,
577 profile_closure_grp_select,
578 profile_closure_descr_select,
579 profile_closure_type_select,
580 profile_closure_time_select
583 void (* profiling_fns[]) PROTO((P_,I_)) = {
588 profile_closure_descr,
589 profile_closure_type,
594 heap_profile_setup(STG_NO_ARGS) /* called at start of heap profile */
598 if (! RTSflags.ProfFlags.doHeapProfile)
601 heap_prof_style = RTSflags.ProfFlags.doHeapProfile;
603 if (cc_select || clcat_select) {
604 set_selected_ccs(); /* memoise cc selection */
605 heap_profile_fn = profiling_fns_select[heap_prof_style];
607 heap_profile_fn = profiling_fns[heap_prof_style];
612 heap_profile_done(STG_NO_ARGS) /* called at end of heap profile */
620 if (! RTSflags.ProfFlags.doHeapProfile)
623 heap_prof_style = RTSflags.ProfFlags.doHeapProfile;
624 heap_profile_fn = NULL;
626 seconds = (previous_ticks + current_ticks) / (StgFloat)TICK_FREQUENCY;
627 fprintf(heap_file, "BEGIN_SAMPLE %0.2f\n", seconds);
629 max = (* init_index_fns[heap_prof_style])();
631 switch (heap_prof_style) {
633 for (ind = 0; ind < max; ind++) {
634 if ((cc = index_cc_table[ind]) != 0 && ! cc_to_ignore(cc)) {
635 fprintf(heap_file, " %s:%s %ld\n", cc->module, cc->label, resid[ind] * sizeof(W_));
642 for (ind = 0; ind < max; ind++) {
643 if ((cc = index_mod_table[ind]) != 0 && ! cc_to_ignore(cc)) {
644 fprintf(heap_file, " %s %ld\n", cc->module, resid[ind] * sizeof(W_));
651 for (ind = 0; ind < max; ind++) {
652 if ((cc = index_grp_table[ind]) != 0 && ! cc_to_ignore(cc)) {
653 fprintf(heap_file, " %0.11s %ld\n", cc->group, resid[ind] * sizeof(W_));
660 for (ind = 0; ind < max; ind++) {
661 if ((clcat = index_descr_table[ind]) != 0 && ! cc_to_ignore(cc)) {
662 fprintf(heap_file, " %0.28s %ld\n", clcat->descr, resid[ind] * sizeof(W_));
669 for (ind = 0; ind < max; ind++) {
670 if ((clcat = index_type_table[ind]) != 0 && ! cc_to_ignore(cc)) {
671 fprintf(heap_file, " %0.28s %ld\n", clcat->type, resid[ind] * sizeof(W_));
678 fprintf(heap_file, "END_SAMPLE %0.2f\n", seconds);
683 heap_profile_finish(STG_NO_ARGS) /* called at end of execution */
687 if (! RTSflags.ProfFlags.doHeapProfile)
690 seconds = (previous_ticks + current_ticks) / (StgFloat)TICK_FREQUENCY;
691 fprintf(heap_file, "BEGIN_SAMPLE %0.2f\n", seconds);
692 fprintf(heap_file, "END_SAMPLE %0.2f\n", seconds);
700 #endif /* PROFILING */