diff options
Diffstat (limited to 'gprof/hist.c')
-rw-r--r-- | gprof/hist.c | 204 |
1 files changed, 84 insertions, 120 deletions
diff --git a/gprof/hist.c b/gprof/hist.c index f63e37d..ed360cd 100644 --- a/gprof/hist.c +++ b/gprof/hist.c @@ -1,6 +1,6 @@ /* hist.c - Histogram related operations. - Copyright 2000 Free Software Foundation, Inc. + Copyright 2000, 2001 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -43,11 +43,10 @@ bfd_vma lowpc, highpc; /* Same, but expressed in UNITs. */ int hist_num_bins = 0; /* Number of histogram samples. */ int *hist_sample = 0; /* Histogram samples (shorts in the file!). */ double hist_scale; -char hist_dimension[sizeof (((struct gmon_hist_hdr *) 0)->dimen) + 1] = - "seconds"; +char hist_dimension[16] = "seconds"; char hist_dimension_abbrev = 's'; -static double accum_time; /* Accumulated time so far for print_line(). */ +static double accum_time; /* Accumulated time so far for print_line(). */ static double total_time; /* Total time for all routines. */ /* Table of SI prefixes for powers of 10 (used to automatically @@ -59,50 +58,17 @@ const struct } SItab[] = { - { - 'T', 1e-12 - } - , /* tera */ - { - 'G', 1e-09 - } - , /* giga */ - { - 'M', 1e-06 - } - , /* mega */ - { - 'K', 1e-03 - } - , /* kilo */ - { - ' ', 1e-00 - } - , - { - 'm', 1e+03 - } - , /* milli */ - { - 'u', 1e+06 - } - , /* micro */ - { - 'n', 1e+09 - } - , /* nano */ - { - 'p', 1e+12 - } - , /* pico */ - { - 'f', 1e+15 - } - , /* femto */ - { - 'a', 1e+18 - } - , /* ato */ + { 'T', 1e-12 }, /* tera */ + { 'G', 1e-09 }, /* giga */ + { 'M', 1e-06 }, /* mega */ + { 'K', 1e-03 }, /* kilo */ + { ' ', 1e-00 }, + { 'm', 1e+03 }, /* milli */ + { 'u', 1e+06 }, /* micro */ + { 'n', 1e+09 }, /* nano */ + { 'p', 1e+12 }, /* pico */ + { 'f', 1e+15 }, /* femto */ + { 'a', 1e+18 } /* ato */ }; @@ -112,26 +78,23 @@ SItab[] = void DEFUN (hist_read_rec, (ifp, filename), FILE * ifp AND const char *filename) { - struct gmon_hist_hdr hdr; bfd_vma n_lowpc, n_highpc; int i, ncnt, profrate; UNIT count; - if (fread (&hdr, sizeof (hdr), 1, ifp) != 1) + if (gmon_io_read_vma (ifp, &n_lowpc) + || gmon_io_read_vma (ifp, &n_highpc) + || gmon_io_read_32 (ifp, &ncnt) + || gmon_io_read_32 (ifp, &profrate) + || gmon_io_read (ifp, hist_dimension, 15) + || gmon_io_read (ifp, &hist_dimension_abbrev, 1)) { fprintf (stderr, _("%s: %s: unexpected end of file\n"), whoami, filename); + done (1); } - n_lowpc = (bfd_vma) get_vma (core_bfd, (bfd_byte *) hdr.low_pc); - n_highpc = (bfd_vma) get_vma (core_bfd, (bfd_byte *) hdr.high_pc); - ncnt = bfd_get_32 (core_bfd, (bfd_byte *) hdr.hist_size); - profrate = bfd_get_32 (core_bfd, (bfd_byte *) hdr.prof_rate); - strncpy (hist_dimension, hdr.dimen, sizeof (hdr.dimen)); - hist_dimension[sizeof (hdr.dimen)] = '\0'; - hist_dimension_abbrev = hdr.dimen_abbrev; - if (!s_highpc) { /* This is the first histogram record. */ @@ -171,11 +134,15 @@ DEFUN (hist_read_rec, (ifp, filename), FILE * ifp AND const char *filename) if (fread (&count[0], sizeof (count), 1, ifp) != 1) { fprintf (stderr, - _("%s: %s: unexpected EOF after reading %d of %d samples\n"), + _("%s: %s: unexpected EOF after reading %d of %d samples\n"), whoami, filename, i, hist_num_bins); done (1); } hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]); + DBG (SAMPLEDEBUG, + printf ("[hist_read_rec] 0x%lx: %u\n", + (unsigned long) (n_lowpc + i * (n_highpc - n_lowpc) / ncnt), + hist_sample[i])); } } @@ -186,23 +153,18 @@ DEFUN (hist_read_rec, (ifp, filename), FILE * ifp AND const char *filename) void DEFUN (hist_write_hist, (ofp, filename), FILE * ofp AND const char *filename) { - struct gmon_hist_hdr hdr; - unsigned char tag; UNIT count; int i; /* Write header. */ - tag = GMON_TAG_TIME_HIST; - put_vma (core_bfd, s_lowpc, (bfd_byte *) hdr.low_pc); - put_vma (core_bfd, s_highpc, (bfd_byte *) hdr.high_pc); - bfd_put_32 (core_bfd, hist_num_bins, (bfd_byte *) hdr.hist_size); - bfd_put_32 (core_bfd, hz, (bfd_byte *) hdr.prof_rate); - strncpy (hdr.dimen, hist_dimension, sizeof (hdr.dimen)); - hdr.dimen_abbrev = hist_dimension_abbrev; - - if (fwrite (&tag, sizeof (tag), 1, ofp) != 1 - || fwrite (&hdr, sizeof (hdr), 1, ofp) != 1) + if (gmon_io_write_8 (ofp, GMON_TAG_TIME_HIST) + || gmon_io_write_vma (ofp, s_lowpc) + || gmon_io_write_vma (ofp, s_highpc) + || gmon_io_write_32 (ofp, hist_num_bins) + || gmon_io_write_32 (ofp, hz) + || gmon_io_write (ofp, hist_dimension, 15) + || gmon_io_write (ofp, &hist_dimension_abbrev, 1)) { perror (filename); done (1); @@ -211,7 +173,7 @@ DEFUN (hist_write_hist, (ofp, filename), FILE * ofp AND const char *filename) for (i = 0; i < hist_num_bins; ++i) { bfd_put_16 (core_bfd, hist_sample[i], (bfd_byte *) & count[0]); - + if (fwrite (&count[0], sizeof (count), 1, ofp) != 1) { perror (filename); @@ -239,7 +201,8 @@ scale_and_align_entries () { sym->hist.scaled_addr = sym->addr / sizeof (UNIT); bin_of_entry = (sym->hist.scaled_addr - lowpc) / hist_scale; - bin_of_code = (sym->hist.scaled_addr + UNITS_TO_CODE - lowpc) / hist_scale; + bin_of_code = ((sym->hist.scaled_addr + UNITS_TO_CODE - lowpc) + / hist_scale); if (bin_of_entry < bin_of_code) { DBG (SAMPLEDEBUG, @@ -254,33 +217,33 @@ scale_and_align_entries () /* Assign samples to the symbol to which they belong. - + Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC) which may overlap one more symbol address ranges. If a symbol overlaps with the bin's address range by O percent, then O percent of the bin's count is credited to that symbol. - + There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be with respect to the symbol's address range [SYM_LOW_PC, SYM_HIGH_PC) as shown in the following diagram. OVERLAP computes the distance (in UNITs) between the arrows, the fraction of the sample that is to be credited to the symbol which starts at SYM_LOW_PC. - - sym_low_pc sym_high_pc - | | - v v - - +-----------------------------------------------+ - | | - | ->| |<- ->| |<- ->| |<- | - | | | | | | - +---------+ +---------+ +---------+ - - ^ ^ ^ ^ ^ ^ - | | | | | | + + sym_low_pc sym_high_pc + | | + v v + + +-----------------------------------------------+ + | | + | ->| |<- ->| |<- ->| |<- | + | | | | | | + +---------+ +---------+ +---------+ + + ^ ^ ^ ^ ^ ^ + | | | | | | bin_low_pc bin_high_pc bin_low_pc bin_high_pc bin_low_pc bin_high_pc - + For the VAX we assert that samples will never fall in the first two bytes of any routine, since that is the entry mask, thus we call scale_and_align_entries() to adjust the entry points if the entry @@ -315,7 +278,7 @@ DEFUN_VOID (hist_assign_samples) bin_low_pc = lowpc + (bfd_vma) (hist_scale * i); bin_high_pc = lowpc + (bfd_vma) (hist_scale * (i + 1)); time = bin_count; - + DBG (SAMPLEDEBUG, printf ( "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%d\n", @@ -329,7 +292,7 @@ DEFUN_VOID (hist_assign_samples) { sym_low_pc = symtab.base[j].hist.scaled_addr; sym_high_pc = symtab.base[j + 1].hist.scaled_addr; - + /* If high end of bin is below entry address, go for next bin. */ if (bin_high_pc < sym_low_pc) @@ -346,18 +309,18 @@ DEFUN_VOID (hist_assign_samples) { DBG (SAMPLEDEBUG, printf ( - "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n", - (unsigned long) symtab.base[j].addr, - (unsigned long) (sizeof (UNIT) * sym_high_pc), - symtab.base[j].name, overlap * time / hist_scale, - (long) overlap)); - + "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n", + (unsigned long) symtab.base[j].addr, + (unsigned long) (sizeof (UNIT) * sym_high_pc), + symtab.base[j].name, overlap * time / hist_scale, + (long) overlap)); + addr = symtab.base[j].addr; credit = overlap * time / hist_scale; - + /* Credit symbol if it appears in INCL_FLAT or that - table is empty and it does not appear it in - EXCL_FLAT. */ + table is empty and it does not appear it in + EXCL_FLAT. */ if (sym_lookup (&syms[INCL_FLAT], addr) || (syms[INCL_FLAT].len == 0 && !sym_lookup (&syms[EXCL_FLAT], addr))) @@ -371,7 +334,7 @@ DEFUN_VOID (hist_assign_samples) } } } - + DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n", total_time)); } @@ -404,13 +367,14 @@ DEFUN (print_header, (prefix), const char prefix) if (total_time <= 0.0) { printf (_(" no time accumulated\n\n")); - + /* This doesn't hurt since all the numerators will be zero. */ total_time = 1.0; } printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n", - "% ", _("cumulative"), _("self "), "", _("self "), _("total "), ""); + "% ", _("cumulative"), _("self "), "", _("self "), _("total "), + ""); printf ("%5.5s %9.9s %8.8s %8.8s %8.8s %8.8s %-8.8s\n", _("time"), hist_dimension, hist_dimension, _("calls"), unit, unit, _("name")); @@ -424,7 +388,7 @@ DEFUN (print_line, (sym, scale), Sym * sym AND double scale) return; accum_time += sym->hist.time; - + if (bsd_style_output) printf ("%5.1f %10.2f %8.2f", total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0, @@ -433,14 +397,14 @@ DEFUN (print_line, (sym, scale), Sym * sym AND double scale) printf ("%6.2f %9.2f %8.2f", total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0, accum_time / hz, sym->hist.time / hz); - + if (sym->ncalls != 0) printf (" %8lu %8.2f %8.2f ", sym->ncalls, scale * sym->hist.time / hz / sym->ncalls, scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls); else printf (" %8.8s %8.8s %8.8s ", "", "", ""); - + if (bsd_style_output) print_name (sym); else @@ -462,10 +426,10 @@ DEFUN (cmp_time, (lp, rp), const PTR lp AND const PTR rp) double time_diff; time_diff = right->hist.time - left->hist.time; - + if (time_diff > 0.0) return 1; - + if (time_diff < 0.0) return -1; @@ -496,7 +460,7 @@ DEFUN_VOID (hist_print) printf ("\f\n"); accum_time = 0.0; - + if (bsd_style_output) { if (print_descriptions) @@ -509,11 +473,11 @@ DEFUN_VOID (hist_print) { printf (_("Flat profile:\n")); } - + /* Sort the symbol table by time (call-count and name as secondary and tertiary keys). */ time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *)); - + for (index = 0; index < symtab.len; ++index) time_sorted_syms[index] = &symtab.base[index]; @@ -530,15 +494,15 @@ DEFUN_VOID (hist_print) log_scale = 0; top_dog = 0; top_time = 0.0; - + for (index = 0; index < symtab.len; ++index) { sym = time_sorted_syms[index]; - + if (sym->ncalls != 0) { time = (sym->hist.time + sym->cg.child_time) / sym->ncalls; - + if (time > top_time) { top_dog = sym; @@ -546,11 +510,11 @@ DEFUN_VOID (hist_print) } } } - + if (top_dog && top_dog->ncalls != 0 && top_time > 0.0) { top_time /= hz; - + while (SItab[log_scale].scale * top_time < 1000.0 && ((size_t) log_scale < sizeof (SItab) / sizeof (SItab[0]) - 1)) @@ -564,19 +528,19 @@ DEFUN_VOID (hist_print) may also want to support other (pseudo-)dimensions (such as I-cache misses etc.). */ print_header (SItab[log_scale].prefix); - + for (index = 0; index < symtab.len; ++index) { addr = time_sorted_syms[index]->addr; - + /* Print symbol if its in INCL_FLAT table or that table - is empty and the symbol is not in EXCL_FLAT. */ + is empty and the symbol is not in EXCL_FLAT. */ if (sym_lookup (&syms[INCL_FLAT], addr) || (syms[INCL_FLAT].len == 0 && !sym_lookup (&syms[EXCL_FLAT], addr))) print_line (time_sorted_syms[index], SItab[log_scale].scale); } - + free (time_sorted_syms); if (print_descriptions && !bsd_style_output) |