Lots of changes from David Mosberger-Tang; see ChangeLog and NOTES for details:
[external/binutils.git] / gprof / hist.c
1 /*
2  * Histogram related operations.
3  */
4 #include <stdio.h>
5 #include "libiberty.h"
6 #include "gprof.h"
7 #include "core.h"
8 #include "gmon_io.h"
9 #include "gmon_out.h"
10 #include "hist.h"
11 #include "symtab.h"
12 #include "sym_ids.h"
13 #include "utils.h"
14
15 /* declarations of automatically generated functions to output blurbs: */
16 extern void flat_blurb PARAMS((FILE *fp));
17
18 bfd_vma s_lowpc;                /* lowest address in .text */
19 bfd_vma s_highpc = 0;           /* highest address in .text */
20 bfd_vma lowpc, highpc;          /* same, but expressed in UNITs */
21 int hist_num_bins = 0;          /* number of histogram samples */
22 int *hist_sample = 0;           /* histogram samples (shorts in the file!) */
23 double hist_scale;
24 char hist_dimension[sizeof(((struct gmon_hist_hdr*)0)->dimen) + 1] =
25      "seconds";
26 char hist_dimension_abbrev = 's';
27
28 static double accum_time;       /* accumulated time so far for print_line() */
29 static double total_time;       /* total time for all routines */
30 /*
31  * Table of SI prefixes for powers of 10 (used to automatically
32  * scale some of the values in the flat profile).
33  */
34 const struct {
35     char prefix;
36     double scale;
37 } SItab[] = {
38     {'T', 1e-12},       /* tera */
39     {'G', 1e-09},       /* giga */
40     {'M', 1e-06},       /* mega */
41     {'K', 1e-03},       /* kilo */
42     {' ', 1e-00},
43     {'m', 1e+03},       /* milli */
44     {'u', 1e+06},       /* micro */
45     {'n', 1e+09},       /* nano */
46     {'p', 1e+12},       /* pico */
47     {'f', 1e+15},       /* femto */
48     {'a', 1e+18},       /* ato */
49 };
50
51 /*
52  * Read the histogram from file IFP.  FILENAME is the name of IFP and
53  * is provided for formatting error messages only.
54  */
55 void
56 DEFUN(hist_read_rec, (ifp, filename), FILE *ifp AND const char *filename)
57 {
58     struct gmon_hist_hdr hdr;
59     bfd_vma n_lowpc, n_highpc;
60     int i, ncnt, profrate;
61     UNIT count;
62
63     if (fread(&hdr, sizeof(hdr), 1, ifp) != 1) {
64         fprintf(stderr, "%s: %s: unexpected end of file\n",
65                 whoami, filename);
66         done(1);
67     } /* if */
68
69     n_lowpc  = (bfd_vma) get_vma(core_bfd, (bfd_byte *) hdr.low_pc);
70     n_highpc = (bfd_vma) get_vma(core_bfd, (bfd_byte *) hdr.high_pc);
71     ncnt     = bfd_get_32(core_bfd, (bfd_byte *) hdr.hist_size);
72     profrate = bfd_get_32(core_bfd, (bfd_byte *) hdr.prof_rate);
73     strncpy(hist_dimension, hdr.dimen, sizeof(hdr.dimen));
74     hist_dimension[sizeof(hdr.dimen)] = '\0';
75     hist_dimension_abbrev = hdr.dimen_abbrev;
76
77     if (!s_highpc) {
78
79         /* this is the first histogram record: */
80
81         s_lowpc   = n_lowpc;
82         s_highpc  = n_highpc;
83         lowpc = (bfd_vma) n_lowpc / sizeof(UNIT);
84         highpc = (bfd_vma) n_highpc / sizeof(UNIT);
85         hist_num_bins = ncnt;
86         hz = profrate;
87     } /* if */
88
89     DBG(SAMPLEDEBUG,
90         printf("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %d\n",
91                n_lowpc, n_highpc, ncnt);
92         printf("[hist_read_rec] s_lowpc 0x%lx s_highpc 0x%lx nsamples %d\n",
93                s_lowpc, s_highpc, hist_num_bins);
94         printf("[hist_read_rec]   lowpc 0x%lx   highpc 0x%lx\n",
95                lowpc, highpc));
96
97     if (n_lowpc != s_lowpc || n_highpc != s_highpc
98         || ncnt != hist_num_bins || hz != profrate)
99     {
100         fprintf(stderr, "%s: `%s' is incompatible with first gmon file\n",
101                 whoami, filename);
102         done(1);
103     } /* if */
104
105     if (!hist_sample) {
106         hist_sample = (int*)xmalloc(hist_num_bins * sizeof(hist_sample[0]));
107         memset(hist_sample, 0, hist_num_bins * sizeof(hist_sample[0]));
108     } /* if */
109
110     for (i = 0; i < hist_num_bins; ++i) {
111         if (fread(&count[0], sizeof(count), 1, ifp) != 1) {
112             fprintf(stderr,
113                     "%s: %s: unexpected EOF after reading %d of %d samples\n",
114                     whoami, filename, i, hist_num_bins);
115             done(1);
116         } /* if */
117         hist_sample[i] += bfd_get_16(core_bfd, (bfd_byte*) &count[0]);
118     } /* for */
119 } /* hist_read_rec */
120
121
122 /*
123  * Write execution histogram to file OFP.  FILENAME is the name
124  * of OFP and is provided for formatting error-messages only.
125  */
126 void
127 DEFUN(hist_write_hist, (ofp, filename), FILE *ofp AND const char *filename)
128 {
129     struct gmon_hist_hdr hdr;
130     unsigned char tag;
131     UNIT count;
132     int i;
133     
134     /* write header: */
135
136     tag = GMON_TAG_TIME_HIST;
137     put_vma(core_bfd, s_lowpc, (bfd_byte*) hdr.low_pc);
138     put_vma(core_bfd, s_highpc, (bfd_byte*) hdr.high_pc);
139     bfd_put_32(core_bfd, hist_num_bins, (bfd_byte*) hdr.hist_size);
140     bfd_put_32(core_bfd, hz, (bfd_byte*) hdr.prof_rate);
141     strncpy(hdr.dimen, hist_dimension, sizeof(hdr.dimen));
142     hdr.dimen_abbrev = hist_dimension_abbrev;
143
144     if (fwrite(&tag, sizeof(tag), 1, ofp) != 1
145         || fwrite(&hdr, sizeof(hdr), 1, ofp) != 1)
146     {
147         perror(filename);
148         done(1);
149     } /* if */
150
151     for (i = 0; i < hist_num_bins; ++i) {
152         bfd_put_16(core_bfd, hist_sample[i], (bfd_byte*) &count[0]);
153         if (fwrite(&count[0], sizeof(count), 1, ofp) != 1) {
154             perror(filename);
155             done(1);
156         } /* if */
157     } /* for */
158 } /* hist_write_hist */
159
160
161 /*
162  * Calculate scaled entry point addresses (to save time in
163  * hist_assign_samples), and, on architectures that have procedure
164  * entry masks at the start of a function, possibly push the scaled
165  * entry points over the procedure entry mask, if it turns out that
166  * the entry point is in one bin and the code for a routine is in the
167  * next bin.
168  */
169 static void
170 DEFUN_VOID(scale_and_align_entries)
171 {
172     Sym *sym;
173 #if OFFSET_TO_CODE > 0
174     bfd_vma bin_of_entry;
175     bfd_vma bin_of_code;
176 #endif
177
178     for (sym = symtab.base; sym < symtab.limit; sym++) {
179         sym->hist.scaled_addr = sym->addr / sizeof(UNIT);
180 #if OFFSET_TO_CODE > 0
181         bin_of_entry = (sym->hist.scaled_addr - lowpc) / hist_scale;
182         bin_of_code = (sym->hist.scaled_addr + UNITS_TO_CODE - lowpc) / hist_scale;
183         if (bin_of_entry < bin_of_code) {
184             DBG(SAMPLEDEBUG,
185                 printf("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
186                        sym->hist.scaled_addr, sym->aligned_addr + UNITS_TO_CODE));
187             sym->aligned_addr += UNITS_TO_CODE;
188         } /* if */
189 #endif /* OFFSET_TO_CODE > 0 */
190     } /* for */
191 } /* scale_and_align_entries */
192
193
194 /*
195  * Assign samples to the symbol to which they belong.
196  *
197  * Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
198  * which may overlap one more symbol address ranges.  If a symbol
199  * overlaps with the bin's address range by O percent, then O percent
200  * of the bin's count is credited to that symbol.
201  *
202  * There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
203  * with respect to the symbol's address range [SYM_LOW_PC,
204  * SYM_HIGH_PC) as shown in the following diagram.  OVERLAP computes
205  * the distance (in UNITs) between the arrows, the fraction of the
206  * sample that is to be credited to the symbol which starts at
207  * SYM_LOW_PC.
208  *
209  *        sym_low_pc                                      sym_high_pc
210  *             |                                               |
211  *             v                                               v
212  *
213  *             +-----------------------------------------------+
214  *             |                                               |
215  *        |  ->|    |<-         ->|         |<-         ->|    |<-  |
216  *        |         |             |         |             |         |
217  *        +---------+             +---------+             +---------+
218  *
219  *        ^         ^             ^         ^             ^         ^
220  *        |         |             |         |             |         |
221  *   bin_low_pc bin_high_pc  bin_low_pc bin_high_pc  bin_low_pc bin_high_pc
222  *
223  * For the VAX we assert that samples will never fall in the first two
224  * bytes of any routine, since that is the entry mask, thus we call
225  * scale_and_align_entries() to adjust the entry points if the entry
226  * mask falls in one bin but the code for the routine doesn't start
227  * until the next bin.  In conjunction with the alignment of routine
228  * addresses, this should allow us to have only one sample for every
229  * four bytes of text space and never have any overlap (the two end
230  * cases, above).
231  */
232 void
233 DEFUN_VOID(hist_assign_samples)
234 {
235     bfd_vma bin_low_pc, bin_high_pc;
236     bfd_vma sym_low_pc, sym_high_pc;
237     bfd_vma overlap, addr;
238     int bin_count, i, j;
239     double time, credit;
240
241     /* read samples and assign to symbols: */
242     hist_scale = highpc - lowpc;
243     hist_scale /= hist_num_bins;
244     scale_and_align_entries();
245
246     /* iterate over all sample bins: */
247
248     for (i = 0, j = 1; i < hist_num_bins; ++i) {
249         bin_count = hist_sample[i];
250         if (!bin_count) {
251             continue;
252         } /* if */
253         bin_low_pc = lowpc + (bfd_vma)(hist_scale * i);
254         bin_high_pc = lowpc + (bfd_vma)(hist_scale * (i + 1));
255         time = bin_count;
256         DBG(SAMPLEDEBUG,
257             printf(
258 "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%d\n",
259                    sizeof(UNIT) * bin_low_pc, sizeof(UNIT) * bin_high_pc,
260                    bin_count));
261         total_time += time;
262
263         /* credit all symbols that are covered by bin I: */
264
265         for (j = j - 1; j < symtab.len; ++j) {
266             sym_low_pc = symtab.base[j].hist.scaled_addr;
267             sym_high_pc = symtab.base[j+1].hist.scaled_addr;
268             /*
269              * If high end of bin is below entry address, go for next
270              * bin:
271              */
272             if (bin_high_pc < sym_low_pc) {
273                 break;
274             } /* if */
275             /*
276              * If low end of bin is above high end of symbol, go for
277              * next symbol.
278              */
279             if (bin_low_pc >= sym_high_pc) {
280                 continue;
281             } /* if */
282             overlap =
283               MIN(bin_high_pc, sym_high_pc) - MAX(bin_low_pc, sym_low_pc);
284             if (overlap > 0) {
285                 DBG(SAMPLEDEBUG,
286                     printf(
287 "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
288                            symtab.base[j].addr, sizeof(UNIT) * sym_high_pc,
289                            symtab.base[j].name, overlap * time / hist_scale,
290                            overlap));
291                 addr = symtab.base[j].addr;
292                 credit = overlap * time / hist_scale;
293                 /*
294                  * Credit symbol if it appears in INCL_FLAT or that
295                  * table is empty and it does not appear it in
296                  * EXCL_FLAT.
297                  */
298                 if (sym_lookup(&syms[INCL_FLAT], addr)
299                     || (syms[INCL_FLAT].len == 0
300                         && !sym_lookup(&syms[EXCL_FLAT], addr)))
301                 {
302                     symtab.base[j].hist.time += credit;
303                 } else {
304                     total_time -= credit;
305                 } /* if */
306             } /* if */
307         } /* if */
308     } /* for */
309     DBG(SAMPLEDEBUG, printf("[assign_samples] total_time %f\n",
310                             total_time));
311 } /* hist_assign_samples */
312
313
314 /*
315  * Print header for flag histogram profile:
316  */
317 static void
318 DEFUN(print_header, (prefix), const char prefix)
319 {
320     char unit[64];
321
322     sprintf(unit, "%c%c/call", prefix, hist_dimension_abbrev);
323
324     if (bsd_style_output) {
325         printf("\ngranularity: each sample hit covers %ld byte(s)",
326                (long) hist_scale * sizeof(UNIT));
327         if (total_time > 0.0) {
328             printf(" for %.2f%% of %.2f %s\n\n",
329                    100.0/total_time, total_time/hz, hist_dimension);
330         } /* if */
331     } else {
332         printf("\nEach sample counts as %g %s.\n", 1.0 / hz, hist_dimension);
333     } /* if */
334
335     if (total_time <= 0.0) {
336         printf(" no time accumulated\n\n");
337         /* this doesn't hurt since all the numerators will be zero: */
338         total_time = 1.0;
339     } /* if */
340
341     printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
342            "%  ", "cumulative", "self  ", "", "self  ", "total ", "");
343     printf("%5.5s %9.9s  %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
344            "time", hist_dimension, hist_dimension, "calls", unit, unit,
345            "name");
346 } /* print_header */
347
348
349 static void
350 DEFUN(print_line, (sym, scale), Sym *sym AND double scale)
351 {
352     if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0) {
353         return;
354     } /* if */
355
356     accum_time += sym->hist.time;
357     if (bsd_style_output) {
358         printf("%5.1f %10.2f %8.2f",
359                total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
360                accum_time / hz, sym->hist.time / hz);
361     } else {
362         printf("%6.2f %9.2f %8.2f",
363                total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
364                accum_time / hz, sym->hist.time / hz);
365     } /* if */
366     if (sym->ncalls) {
367         printf(" %8d %8.2f %8.2f  ",
368                sym->ncalls, scale*sym->hist.time/hz/sym->ncalls,
369                scale*(sym->hist.time + sym->cg.child_time)/hz/sym->ncalls);
370     } else {
371         printf(" %8.8s %8.8s %8.8s  ", "", "", "");
372     } /* if */
373     if (bsd_style_output) {
374         print_name(sym);
375     } else {
376         print_name_only(sym);
377     } /* if */
378     printf("\n");
379 } /* print_line */
380
381
382 /*
383  * Compare LP and RP.  The primary comparison key is execution time,
384  * the secondary is number of invocation, and the tertiary is the
385  * lexicographic order of the function names.
386  */
387 static int
388 DEFUN(cmp_time, (lp, rp), const PTR lp AND const PTR rp)
389 {
390     const Sym *left = *(const Sym **)lp;
391     const Sym *right = *(const Sym **)rp;
392     double time_diff;
393     long call_diff;
394
395     time_diff = right->hist.time - left->hist.time;
396     if (time_diff > 0.0) {
397         return 1;
398     } /* if */
399     if (time_diff < 0.0) {
400         return -1;
401     } /* if */
402
403     call_diff = right->ncalls - left->ncalls;
404     if (call_diff > 0) {
405         return 1;
406     } /* if */
407     if (call_diff < 0) {
408         return -1;
409     } /* if */
410
411     return strcmp(left->name, right->name);
412 } /* cmp_time */
413
414
415 /*
416  * Print the flat histogram profile.
417  */
418 void
419 DEFUN_VOID(hist_print)
420 {
421     Sym **time_sorted_syms, *top_dog, *sym;
422     int index, log_scale;
423     double top_time, time;
424     bfd_vma addr;
425
426     if (first_output) {
427         first_output = FALSE;
428     } else {
429         printf("\f\n");
430     } /* if */
431
432     accum_time = 0.0;
433     if (bsd_style_output) {
434         if (print_descriptions) {
435             printf("\n\n\nflat profile:\n");
436             flat_blurb(stdout);
437         } /* if */
438     } else {
439         printf ("Flat profile:\n");
440     } /* if */
441     /*
442      * Sort the symbol table by time (call-count and name as secondary
443      * and tertiary keys):
444      */
445     time_sorted_syms = (Sym**)xmalloc(symtab.len * sizeof(Sym*));
446     for (index = 0; index < symtab.len; ++index) {
447         time_sorted_syms[index] = &symtab.base[index];
448     } /* for */
449     qsort(time_sorted_syms, symtab.len, sizeof(Sym *), cmp_time);
450
451     if (bsd_style_output) {
452         log_scale = 5;          /* milli-seconds is BSD-default */
453     } else {
454         /*
455          * Search for symbol with highest per-call execution time and
456          * scale accordingly:
457          */
458         log_scale = 0;
459         top_dog = 0;
460         top_time = 0.0;
461         for (index = 0; index < symtab.len; ++index) {
462             sym = time_sorted_syms[index];
463             if (sym->ncalls) {
464                 time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
465                 if (time > top_time) {
466                     top_dog = sym;
467                     top_time = time;
468                 } /* if */
469             } /* if */
470         } /* for */
471         if (top_dog && top_dog->ncalls && top_time > 0.0) {
472             top_time /= hz;
473             while (SItab[log_scale].scale * top_time < 1000.0
474                    && log_scale < sizeof(SItab)/sizeof(SItab[0]) - 1)
475             {
476                 ++log_scale;
477             } /* while */
478         } /* if */
479     } /* if */
480
481     /*
482      * For now, the dimension is always seconds.  In the future, we
483      * may also want to support other (pseudo-)dimensions (such as
484      * I-cache misses etc.).
485      */
486     print_header(SItab[log_scale].prefix);
487     for (index = 0; index < symtab.len; ++index) {
488         addr = time_sorted_syms[index]->addr;
489         /*
490          * Print symbol if its in INCL_FLAT table or that table
491          * is empty and the symbol is not in EXCL_FLAT.
492          */
493         if (sym_lookup(&syms[INCL_FLAT], addr)
494             || (syms[INCL_FLAT].len == 0
495                 && !sym_lookup(&syms[EXCL_FLAT], addr)))
496         {
497             print_line(time_sorted_syms[index], SItab[log_scale].scale);
498         } /* if */
499     } /* for */
500     free(time_sorted_syms);
501
502     if (print_descriptions && !bsd_style_output) {
503         flat_blurb(stdout);
504     } /* if */
505 } /* hist_print */
506
507                         /*** end of hist.c ***/