1 /* hist.c - Histogram related operations.
3 Copyright (C) 2000 Free Software Foundation, Inc.
5 This file is part of GNU Binutils.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 #include "libiberty.h"
33 #define UNITS_TO_CODE (offset_to_code / sizeof(UNIT))
35 static void scale_and_align_entries PARAMS ((void));
37 /* Declarations of automatically generated functions to output blurbs. */
38 extern void flat_blurb PARAMS ((FILE * fp));
40 bfd_vma s_lowpc; /* Lowest address in .text. */
41 bfd_vma s_highpc = 0; /* Highest address in .text. */
42 bfd_vma lowpc, highpc; /* Same, but expressed in UNITs. */
43 int hist_num_bins = 0; /* Number of histogram samples. */
44 int *hist_sample = 0; /* Histogram samples (shorts in the file!). */
46 char hist_dimension[sizeof (((struct gmon_hist_hdr *) 0)->dimen) + 1] =
48 char hist_dimension_abbrev = 's';
50 static double accum_time; /* Accumulated time so far for print_line(). */
51 static double total_time; /* Total time for all routines. */
53 /* Table of SI prefixes for powers of 10 (used to automatically
54 scale some of the values in the flat profile). */
109 /* Read the histogram from file IFP. FILENAME is the name of IFP and
110 is provided for formatting error messages only. */
113 DEFUN (hist_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
115 struct gmon_hist_hdr hdr;
116 bfd_vma n_lowpc, n_highpc;
117 int i, ncnt, profrate;
120 if (fread (&hdr, sizeof (hdr), 1, ifp) != 1)
122 fprintf (stderr, _("%s: %s: unexpected end of file\n"),
127 n_lowpc = (bfd_vma) get_vma (core_bfd, (bfd_byte *) hdr.low_pc);
128 n_highpc = (bfd_vma) get_vma (core_bfd, (bfd_byte *) hdr.high_pc);
129 ncnt = bfd_get_32 (core_bfd, (bfd_byte *) hdr.hist_size);
130 profrate = bfd_get_32 (core_bfd, (bfd_byte *) hdr.prof_rate);
131 strncpy (hist_dimension, hdr.dimen, sizeof (hdr.dimen));
132 hist_dimension[sizeof (hdr.dimen)] = '\0';
133 hist_dimension_abbrev = hdr.dimen_abbrev;
137 /* This is the first histogram record. */
140 lowpc = (bfd_vma) n_lowpc / sizeof (UNIT);
141 highpc = (bfd_vma) n_highpc / sizeof (UNIT);
142 hist_num_bins = ncnt;
147 printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %d\n",
148 (unsigned long) n_lowpc, (unsigned long) n_highpc, ncnt);
149 printf ("[hist_read_rec] s_lowpc 0x%lx s_highpc 0x%lx nsamples %d\n",
150 (unsigned long) s_lowpc, (unsigned long) s_highpc,
152 printf ("[hist_read_rec] lowpc 0x%lx highpc 0x%lx\n",
153 (unsigned long) lowpc, (unsigned long) highpc));
155 if (n_lowpc != s_lowpc || n_highpc != s_highpc
156 || ncnt != hist_num_bins || hz != profrate)
158 fprintf (stderr, _("%s: `%s' is incompatible with first gmon file\n"),
165 hist_sample = (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0]));
166 memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0]));
169 for (i = 0; i < hist_num_bins; ++i)
171 if (fread (&count[0], sizeof (count), 1, ifp) != 1)
174 _("%s: %s: unexpected EOF after reading %d of %d samples\n"),
175 whoami, filename, i, hist_num_bins);
178 hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]);
183 /* Write execution histogram to file OFP. FILENAME is the name
184 of OFP and is provided for formatting error-messages only. */
187 DEFUN (hist_write_hist, (ofp, filename), FILE * ofp AND const char *filename)
189 struct gmon_hist_hdr hdr;
196 tag = GMON_TAG_TIME_HIST;
197 put_vma (core_bfd, s_lowpc, (bfd_byte *) hdr.low_pc);
198 put_vma (core_bfd, s_highpc, (bfd_byte *) hdr.high_pc);
199 bfd_put_32 (core_bfd, hist_num_bins, (bfd_byte *) hdr.hist_size);
200 bfd_put_32 (core_bfd, hz, (bfd_byte *) hdr.prof_rate);
201 strncpy (hdr.dimen, hist_dimension, sizeof (hdr.dimen));
202 hdr.dimen_abbrev = hist_dimension_abbrev;
204 if (fwrite (&tag, sizeof (tag), 1, ofp) != 1
205 || fwrite (&hdr, sizeof (hdr), 1, ofp) != 1)
211 for (i = 0; i < hist_num_bins; ++i)
213 bfd_put_16 (core_bfd, hist_sample[i], (bfd_byte *) & count[0]);
215 if (fwrite (&count[0], sizeof (count), 1, ofp) != 1)
224 /* Calculate scaled entry point addresses (to save time in
225 hist_assign_samples), and, on architectures that have procedure
226 entry masks at the start of a function, possibly push the scaled
227 entry points over the procedure entry mask, if it turns out that
228 the entry point is in one bin and the code for a routine is in the
232 scale_and_align_entries ()
235 bfd_vma bin_of_entry;
238 for (sym = symtab.base; sym < symtab.limit; sym++)
240 sym->hist.scaled_addr = sym->addr / sizeof (UNIT);
241 bin_of_entry = (sym->hist.scaled_addr - lowpc) / hist_scale;
242 bin_of_code = (sym->hist.scaled_addr + UNITS_TO_CODE - lowpc) / hist_scale;
243 if (bin_of_entry < bin_of_code)
246 printf ("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
247 (unsigned long) sym->hist.scaled_addr,
248 (unsigned long) (sym->hist.scaled_addr
250 sym->hist.scaled_addr += UNITS_TO_CODE;
256 /* Assign samples to the symbol to which they belong.
258 Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
259 which may overlap one more symbol address ranges. If a symbol
260 overlaps with the bin's address range by O percent, then O percent
261 of the bin's count is credited to that symbol.
263 There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
264 with respect to the symbol's address range [SYM_LOW_PC,
265 SYM_HIGH_PC) as shown in the following diagram. OVERLAP computes
266 the distance (in UNITs) between the arrows, the fraction of the
267 sample that is to be credited to the symbol which starts at
270 sym_low_pc sym_high_pc
274 +-----------------------------------------------+
276 | ->| |<- ->| |<- ->| |<- |
278 +---------+ +---------+ +---------+
282 bin_low_pc bin_high_pc bin_low_pc bin_high_pc bin_low_pc bin_high_pc
284 For the VAX we assert that samples will never fall in the first two
285 bytes of any routine, since that is the entry mask, thus we call
286 scale_and_align_entries() to adjust the entry points if the entry
287 mask falls in one bin but the code for the routine doesn't start
288 until the next bin. In conjunction with the alignment of routine
289 addresses, this should allow us to have only one sample for every
290 four bytes of text space and never have any overlap (the two end
294 DEFUN_VOID (hist_assign_samples)
296 bfd_vma bin_low_pc, bin_high_pc;
297 bfd_vma sym_low_pc, sym_high_pc;
298 bfd_vma overlap, addr;
303 /* Read samples and assign to symbols. */
304 hist_scale = highpc - lowpc;
305 hist_scale /= hist_num_bins;
306 scale_and_align_entries ();
308 /* Iterate over all sample bins. */
309 for (i = 0, j = 1; i < hist_num_bins; ++i)
311 bin_count = hist_sample[i];
315 bin_low_pc = lowpc + (bfd_vma) (hist_scale * i);
316 bin_high_pc = lowpc + (bfd_vma) (hist_scale * (i + 1));
321 "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%d\n",
322 (unsigned long) (sizeof (UNIT) * bin_low_pc),
323 (unsigned long) (sizeof (UNIT) * bin_high_pc),
327 /* Credit all symbols that are covered by bin I. */
328 for (j = j - 1; j < symtab.len; ++j)
330 sym_low_pc = symtab.base[j].hist.scaled_addr;
331 sym_high_pc = symtab.base[j + 1].hist.scaled_addr;
333 /* If high end of bin is below entry address,
335 if (bin_high_pc < sym_low_pc)
338 /* If low end of bin is above high end of symbol,
339 go for next symbol. */
340 if (bin_low_pc >= sym_high_pc)
344 MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc);
349 "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
350 (unsigned long) symtab.base[j].addr,
351 (unsigned long) (sizeof (UNIT) * sym_high_pc),
352 symtab.base[j].name, overlap * time / hist_scale,
355 addr = symtab.base[j].addr;
356 credit = overlap * time / hist_scale;
358 /* Credit symbol if it appears in INCL_FLAT or that
359 table is empty and it does not appear it in
361 if (sym_lookup (&syms[INCL_FLAT], addr)
362 || (syms[INCL_FLAT].len == 0
363 && !sym_lookup (&syms[EXCL_FLAT], addr)))
365 symtab.base[j].hist.time += credit;
369 total_time -= credit;
375 DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n",
380 /* Print header for flag histogram profile. */
383 DEFUN (print_header, (prefix), const char prefix)
387 sprintf (unit, _("%c%c/call"), prefix, hist_dimension_abbrev);
389 if (bsd_style_output)
391 printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
392 (long) hist_scale * sizeof (UNIT));
393 if (total_time > 0.0)
395 printf (_(" for %.2f%% of %.2f %s\n\n"),
396 100.0 / total_time, total_time / hz, hist_dimension);
401 printf (_("\nEach sample counts as %g %s.\n"), 1.0 / hz, hist_dimension);
404 if (total_time <= 0.0)
406 printf (_(" no time accumulated\n\n"));
408 /* This doesn't hurt since all the numerators will be zero. */
412 printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
413 "% ", _("cumulative"), _("self "), "", _("self "), _("total "), "");
414 printf ("%5.5s %9.9s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
415 _("time"), hist_dimension, hist_dimension, _("calls"), unit, unit,
421 DEFUN (print_line, (sym, scale), Sym * sym AND double scale)
423 if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0)
426 accum_time += sym->hist.time;
428 if (bsd_style_output)
429 printf ("%5.1f %10.2f %8.2f",
430 total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
431 accum_time / hz, sym->hist.time / hz);
433 printf ("%6.2f %9.2f %8.2f",
434 total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
435 accum_time / hz, sym->hist.time / hz);
437 if (sym->ncalls != 0)
438 printf (" %8lu %8.2f %8.2f ",
439 sym->ncalls, scale * sym->hist.time / hz / sym->ncalls,
440 scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls);
442 printf (" %8.8s %8.8s %8.8s ", "", "", "");
444 if (bsd_style_output)
447 print_name_only (sym);
453 /* Compare LP and RP. The primary comparison key is execution time,
454 the secondary is number of invocation, and the tertiary is the
455 lexicographic order of the function names. */
458 DEFUN (cmp_time, (lp, rp), const PTR lp AND const PTR rp)
460 const Sym *left = *(const Sym **) lp;
461 const Sym *right = *(const Sym **) rp;
464 time_diff = right->hist.time - left->hist.time;
472 if (right->ncalls > left->ncalls)
475 if (right->ncalls < left->ncalls)
478 return strcmp (left->name, right->name);
482 /* Print the flat histogram profile. */
485 DEFUN_VOID (hist_print)
487 Sym **time_sorted_syms, *top_dog, *sym;
490 double top_time, time;
494 first_output = FALSE;
500 if (bsd_style_output)
502 if (print_descriptions)
504 printf (_("\n\n\nflat profile:\n"));
510 printf (_("Flat profile:\n"));
513 /* Sort the symbol table by time (call-count and name as secondary
514 and tertiary keys). */
515 time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
517 for (index = 0; index < symtab.len; ++index)
518 time_sorted_syms[index] = &symtab.base[index];
520 qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
522 if (bsd_style_output)
524 log_scale = 5; /* Milli-seconds is BSD-default. */
528 /* Search for symbol with highest per-call
529 execution time and scale accordingly. */
534 for (index = 0; index < symtab.len; ++index)
536 sym = time_sorted_syms[index];
538 if (sym->ncalls != 0)
540 time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
550 if (top_dog && top_dog->ncalls != 0 && top_time > 0.0)
554 while (SItab[log_scale].scale * top_time < 1000.0
555 && ((size_t) log_scale
556 < sizeof (SItab) / sizeof (SItab[0]) - 1))
563 /* For now, the dimension is always seconds. In the future, we
564 may also want to support other (pseudo-)dimensions (such as
565 I-cache misses etc.). */
566 print_header (SItab[log_scale].prefix);
568 for (index = 0; index < symtab.len; ++index)
570 addr = time_sorted_syms[index]->addr;
572 /* Print symbol if its in INCL_FLAT table or that table
573 is empty and the symbol is not in EXCL_FLAT. */
574 if (sym_lookup (&syms[INCL_FLAT], addr)
575 || (syms[INCL_FLAT].len == 0
576 && !sym_lookup (&syms[EXCL_FLAT], addr)))
577 print_line (time_sorted_syms[index], SItab[log_scale].scale);
580 free (time_sorted_syms);
582 if (print_descriptions && !bsd_style_output)