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(cc_select_str, mod_select_str, grp_select_str,
113 descr_select_str, type_select_str, kind_select_str,
116 char *mod_select_str;
117 char *grp_select_str;
118 char *descr_select_str;
119 char *type_select_str;
120 char *kind_select_str;
123 hash_t count, max, first;
126 if (! RTSflags.ProfFlags.doHeapProfile)
129 /* for now, if using a generational collector and trying
130 to heap-profile, just force the GC to be used in two-space mode.
133 #if defined(GCap) || defined(GCgn)
134 RTSflags.GcFlags.force2s = rtsTrue;
137 heap_prof_style = RTSflags.ProfFlags.doHeapProfile;
139 /* process select strings -- will break them into bits */
143 while (cc_select_str && cc_select_no < MAX_SELECT) {
144 if ((comma = strchr(cc_select_str, ',')) != 0) {
147 if ((colon = strchr(cc_select_str, ':')) != 0) {
149 ccmod_select_strs[cc_select_no] = cc_select_str;
150 cc_select_strs[cc_select_no++] = colon + 1;
152 ccmod_select_strs[cc_select_no] = (char *)0;
153 cc_select_strs[cc_select_no++] = cc_select_str;
156 cc_select_str = comma + 1;
158 cc_select_str = (char *)0;
161 if (cc_select_str && cc_select_no >= MAX_SELECT) {
162 fprintf(stderr, "heap_profile_init: Too many Cost Centres selected\n %ld used %s remaining\n",
163 cc_select_no, cc_select_str);
166 cc_select |= cc_select_no > 0;
168 if (mod_select_str) {
170 while ((comma = strchr(mod_select_str, ',')) && mod_select_no < MAX_SELECT) {
171 mod_select_strs[mod_select_no++] = mod_select_str;
173 mod_select_str = comma + 1;
175 if (mod_select_no < MAX_SELECT) {
176 mod_select_strs[mod_select_no++] = mod_select_str;
178 fprintf(stderr, "heap_profile_init: Too many Modules selected\n %ld used %s remaining\n",
179 mod_select_no, mod_select_str);
182 cc_select |= mod_select_no > 0;
184 if (grp_select_str) {
186 while ((comma = strchr(grp_select_str, ',')) && grp_select_no < MAX_SELECT) {
187 grp_select_strs[grp_select_no++] = grp_select_str;
189 grp_select_str = comma + 1;
191 if (grp_select_no < MAX_SELECT) {
192 grp_select_strs[grp_select_no++] = grp_select_str;
194 fprintf(stderr, "heap_profile_init: Too many Groups selected\n %ld used %s remaining\n",
195 grp_select_no, grp_select_str);
198 cc_select |= grp_select_no > 0;
201 if (descr_select_str) {
203 while ((comma = strchr(descr_select_str, ',')) && descr_select_no < MAX_SELECT) {
204 descr_select_strs[descr_select_no++] = descr_select_str;
206 descr_select_str = comma + 1;
208 if (descr_select_no < MAX_SELECT) {
209 descr_select_strs[descr_select_no++] = descr_select_str;
211 fprintf(stderr, "heap_profile_init: Too many Closure Descriptions selected\n %ld used %s remaining\n",
212 descr_select_no, descr_select_str);
215 clcat_select |= descr_select_no > 0;
217 if (type_select_str) {
219 while ((comma = strchr(type_select_str, ',')) && type_select_no < MAX_SELECT) {
220 type_select_strs[type_select_no++] = type_select_str;
222 type_select_str = comma + 1;
224 if (type_select_no < MAX_SELECT) {
225 type_select_strs[type_select_no++] = type_select_str;
227 fprintf(stderr, "heap_profile_init: Too many Closure Types selected\n %ld used %s remaining\n",
228 type_select_no, type_select_str);
231 clcat_select |= type_select_no > 0;
233 if (kind_select_str) {
235 while ((comma = strchr(kind_select_str, ',')) != 0) {
237 for (count = 1; kind_select_strs[count]; count++) {
238 if (strcmp(kind_select_strs[count],kind_select_str) == 0) {
239 kind_selected[count] = 1;
244 if (! kind_select_strs[count]) {
245 fprintf(stderr, "heap_profile_init: Invalid Kind: %s\n", kind_select_str);
248 kind_select_str = comma + 1;
250 for (count = 1; kind_select_strs[count]; count++) {
251 if (strcmp(kind_select_strs[count],kind_select_str) == 0) {
252 kind_selected[count] = 1;
257 if (! kind_select_strs[count]) {
258 fprintf(stderr, "heap_profile_init: Invalid Kind: %s\n", kind_select_str);
261 clcat_select |= kind_select_no > 0;
264 /* open heap profiling log file */
266 sprintf(heap_filename, HP_FILENAME_FMT, argv[0]);
267 if ( (heap_file = fopen(heap_filename,"w")) == NULL ) {
268 fprintf(stderr, "Can't open heap log file %s\n", heap_filename);
272 /* write start of log file */
274 fprintf(heap_file, "JOB \"%s", argv[0]);
275 fprintf(heap_file, " +RTS -h%c", heap_profiling_char[heap_prof_style]);
276 if (heap_prof_style == HEAP_BY_TIME) {
277 fprintf(heap_file, "%ld", time_intervals);
279 fprintf(heap_file, ",%3.1f",
280 earlier_ticks / (StgFloat)TICK_FREQUENCY);
284 fprintf(heap_file, " -c{%s:%s",
285 ccmod_select_strs[0],
287 for (count = 1; count < cc_select_no; count++) {
288 fprintf(heap_file, ",%s:%s",
289 ccmod_select_strs[count],
290 cc_select_strs[count]);
292 fprintf(heap_file, "}");
295 fprintf(heap_file, " -m{%s", mod_select_strs[0]);
296 for (count = 1; count < mod_select_no; count++)
297 fprintf(heap_file, ",%s", mod_select_strs[count]);
298 fprintf(heap_file, "}");
301 fprintf(heap_file, " -g{%s", grp_select_strs[0]);
302 for (count = 1; count < grp_select_no; count++)
303 fprintf(heap_file, ",%s", grp_select_strs[count]);
304 fprintf(heap_file, "}");
306 if (descr_select_no) {
307 fprintf(heap_file, " -d{%s", descr_select_strs[0]);
308 for (count = 1; count < descr_select_no; count++)
309 fprintf(heap_file, ",%s", descr_select_strs[count]);
310 fprintf(heap_file, "}");
312 if (type_select_no) {
313 fprintf(heap_file, " -t{%s", type_select_strs[0]);
314 for (count = 1; count < type_select_no; count++)
315 fprintf(heap_file, ",%s", type_select_strs[count]);
316 fprintf(heap_file, "}");
318 if (kind_select_no) {
319 fprintf(heap_file, " -k{");
320 for (count = 1, first = 1; kind_select_strs[count]; count++)
321 if (kind_selected[count]) {
322 fprintf(heap_file, "%s%s", first?"":",", kind_select_strs[count]);
325 fprintf(heap_file, "}");
328 fprintf(heap_file, " -i%4.2f -RTS", interval_ticks/(StgFloat)TICK_FREQUENCY);
329 for(count = 1; argv[count]; count++)
330 fprintf(heap_file, " %s", argv[count]);
331 fprintf(heap_file, "\"\n");
333 fprintf(heap_file, "DATE \"%s\"\n", time_str());
335 fprintf(heap_file, "SAMPLE_UNIT \"seconds\"\n");
336 fprintf(heap_file, "VALUE_UNIT \"bytes\"\n");
338 fprintf(heap_file, "BEGIN_SAMPLE 0.00\n");
339 fprintf(heap_file, "END_SAMPLE 0.00\n");
342 /* initialise required heap profiling data structures & hashing */
344 earlier_intervals = (earlier_ticks / interval_ticks) + 1;
345 max = (* init_index_fns[heap_prof_style])();
346 resid = (I_ *) stgMallocBytes(max * sizeof(I_), "heap_profile_init");
348 for (count = 0; count < max; count++)
355 Cost centre selection is set up before a heap profile by running
356 through the list of registered cost centres and memoising the
357 selection in the cost centre record. It is only necessary to memoise
358 the cost centre selection if a selection profiling function is
361 Category selection is determined when each closure is encountered. It
362 is memoised within the category record. We always have to check that
363 the memoisation has been done as we do not have a list of categories
364 we can process before hand.
366 Age selection is done for every closure -- not memoised.
370 set_selected_ccs(STG_NO_ARGS) /* set selection before we profile heap */
376 for (cc = Registered_CC; cc != REGISTERED_END; cc = cc->registered) {
377 for (x = 0; ! cc->selected && x < cc_select_no; x++)
378 cc->selected = (strcmp(cc->label, cc_select_strs[x]) == 0) &&
379 (strcmp(cc->module, ccmod_select_strs[x]) == 0);
380 for (x = 0; ! cc->selected && x < mod_select_no; x++)
381 cc->selected = (strcmp(cc->module, mod_select_strs[x]) == 0);
382 for (x = 0; ! cc->selected && x < grp_select_no; x++)
383 cc->selected = (strcmp(cc->group, grp_select_strs[x]) == 0);
386 for (cc = Registered_CC; cc != REGISTERED_END; cc = cc->registered)
387 cc->selected = 1; /* true if ! cc_select */
393 selected_clcat(ClCategory clcat)
397 if (clcat->selected == -1) { /* if not memoised check selection */
400 for (x = 0; ! clcat->selected && x < descr_select_no; x++)
401 clcat->selected = (strcmp(clcat->descr, descr_select_strs[x]) == 0);
402 for (x = 0; ! clcat->selected && x < type_select_no; x++)
403 clcat->selected = (strcmp(clcat->type, type_select_strs[x]) == 0);
404 if (kind_select_no) clcat->selected |= kind_selected[clcat->kind];
409 return clcat->selected; /* return memoised selection */
414 Profiling functions called for each closure. The appropriate function
415 is stored in @heap_profile_fn@ by @heap_profile_setup@.
416 @heap_profile_fn@ is called for each live closure by the macros
417 embedded in the garbage collector. They increment the appropriate
418 resident space counter by the size of the closure (less any profiling
422 #define NON_PROF_HS (FIXED_HS - PROF_FIXED_HDR - TICKY_FIXED_HDR)
425 profile_closure_none(P_ closure, I_ size)
431 profile_closure_cc(P_ closure, I_ size)
433 CostCentre cc = (CostCentre) CC_HDR(closure);
434 resid[index_cc(cc)] += size + NON_PROF_HS;
439 profile_closure_cc_select(P_ closure, I_ size)
441 CostCentre cc; ClCategory clcat;
443 cc = (CostCentre) CC_HDR(closure);
444 if (! cc->selected) /* selection determined before profile */
445 return; /* all selected if ! cc_select */
447 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
448 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
451 resid[index_cc(cc)] += size + NON_PROF_HS;
456 profile_closure_mod(P_ closure, I_ size)
458 CostCentre cc = (CostCentre) CC_HDR(closure);
459 resid[index_mod(cc)] += size + NON_PROF_HS;
464 profile_closure_mod_select(P_ closure, I_ size)
466 CostCentre cc; ClCategory clcat;
468 cc = (CostCentre) CC_HDR(closure);
469 if (! cc->selected) /* selection determined before profile */
472 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
473 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
476 resid[index_mod(cc)] += size + NON_PROF_HS;
481 profile_closure_grp(P_ closure, I_ size)
483 CostCentre cc = (CostCentre) CC_HDR(closure);
484 resid[index_grp(cc)] += size + NON_PROF_HS;
489 profile_closure_grp_select(P_ closure, I_ size)
491 CostCentre cc; ClCategory clcat;
493 cc = (CostCentre) CC_HDR(closure);
494 if (! cc->selected) /* selection determined before profile */
497 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
498 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
501 resid[index_grp(cc)] += size + NON_PROF_HS;
506 profile_closure_descr(P_ closure, I_ size)
508 ClCategory clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
509 resid[index_descr(clcat)] += size + NON_PROF_HS;
514 profile_closure_descr_select(P_ closure, I_ size)
516 CostCentre cc; ClCategory clcat;
518 cc = (CostCentre) CC_HDR(closure);
519 if (! cc->selected) /* selection determined before profile */
520 return; /* all selected if ! cc_select */
522 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
523 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
526 resid[index_descr(clcat)] += size + NON_PROF_HS;
531 profile_closure_type(P_ closure, I_ size)
533 ClCategory clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
534 resid[index_type(clcat)] += size + NON_PROF_HS;
539 profile_closure_type_select(P_ closure, I_ size)
541 CostCentre cc; ClCategory clcat;
543 cc = (CostCentre) CC_HDR(closure);
544 if (! cc->selected) /* selection determined before profile */
545 return; /* all selected if ! cc_select */
547 clcat = (ClCategory) INFO_CAT(INFO_PTR(closure));
548 if (clcat_select && ! selected_clcat(clcat)) /* selection memoised during profile */
551 resid[index_type(clcat)] += size + NON_PROF_HS;
556 profile_closure_time(P_ closure, I_ size)
562 profile_closure_time_select(P_ closure, I_ size)
568 @heap_profile_setup@ is called before garbage collection to initialise
569 for the profile. It assigns the appropriate closure profiling function
570 to @heap_profile_fn@ and memoises any cost centre selection. If no
571 profile is required @profile_closure_none@ is assigned.
573 On completion of garbage collection @heap_profile_done@ is called. It
574 produces a heap profile report and resets the residency counts to 0.
578 void (* heap_profile_fn) PROTO((P_,I_)) = profile_closure_none;
580 void (* profiling_fns_select[]) PROTO((P_,I_)) = {
581 profile_closure_none,
582 profile_closure_cc_select,
583 profile_closure_mod_select,
584 profile_closure_grp_select,
585 profile_closure_descr_select,
586 profile_closure_type_select,
587 profile_closure_time_select
590 void (* profiling_fns[]) PROTO((P_,I_)) = {
591 profile_closure_none,
595 profile_closure_descr,
596 profile_closure_type,
601 heap_profile_setup(STG_NO_ARGS) /* called at start of heap profile */
605 if (! RTSflags.ProfFlags.doHeapProfile)
608 heap_prof_style = RTSflags.ProfFlags.doHeapProfile;
610 if (cc_select || clcat_select) {
611 set_selected_ccs(); /* memoise cc selection */
612 heap_profile_fn = profiling_fns_select[heap_prof_style];
614 heap_profile_fn = profiling_fns[heap_prof_style];
619 heap_profile_done(STG_NO_ARGS) /* called at end of heap profile */
627 if (! RTSflags.ProfFlags.doHeapProfile)
630 heap_prof_style = RTSflags.ProfFlags.doHeapProfile;
631 heap_profile_fn = profile_closure_none;
633 seconds = (previous_ticks + current_ticks) / (StgFloat)TICK_FREQUENCY;
634 fprintf(heap_file, "BEGIN_SAMPLE %0.2f\n", seconds);
636 max = (* init_index_fns[heap_prof_style])();
638 switch (heap_prof_style) {
640 for (ind = 0; ind < max; ind++) {
641 if ((cc = index_cc_table[ind]) != 0 && ! cc_to_ignore(cc)) {
642 fprintf(heap_file, " %0.11s:%0.16s %ld\n", cc->module, cc->label, resid[ind] * sizeof(W_));
649 for (ind = 0; ind < max; ind++) {
650 if ((cc = index_mod_table[ind]) != 0 && ! cc_to_ignore(cc)) {
651 fprintf(heap_file, " %0.11s %ld\n", cc->module, resid[ind] * sizeof(W_));
658 for (ind = 0; ind < max; ind++) {
659 if ((cc = index_grp_table[ind]) != 0 && ! cc_to_ignore(cc)) {
660 fprintf(heap_file, " %0.11s %ld\n", cc->group, resid[ind] * sizeof(W_));
667 for (ind = 0; ind < max; ind++) {
668 if ((clcat = index_descr_table[ind]) != 0 && ! cc_to_ignore(cc)) {
669 fprintf(heap_file, " %0.28s %ld\n", clcat->descr, resid[ind] * sizeof(W_));
676 for (ind = 0; ind < max; ind++) {
677 if ((clcat = index_type_table[ind]) != 0 && ! cc_to_ignore(cc)) {
678 fprintf(heap_file, " %0.28s %ld\n", clcat->type, resid[ind] * sizeof(W_));
685 fprintf(heap_file, "END_SAMPLE %0.2f\n", seconds);
690 heap_profile_finish(STG_NO_ARGS) /* called at end of execution */
694 if (! RTSflags.ProfFlags.doHeapProfile)
697 seconds = (previous_ticks + current_ticks) / (StgFloat)TICK_FREQUENCY;
698 fprintf(heap_file, "BEGIN_SAMPLE %0.2f\n", seconds);
699 fprintf(heap_file, "END_SAMPLE %0.2f\n", seconds);
707 #endif /* PROFILING */