Home | History | Annotate | Line # | Download | only in gprof
hist.c revision 1.1
      1 /* hist.c  -  Histogram related operations.
      2 
      3    Copyright 1999, 2000, 2001, 2002, 2004, 2005, 2007, 2009
      4    Free Software Foundation, Inc.
      5 
      6    This file is part of GNU Binutils.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
     21    02110-1301, USA.  */
     22 
     23 #include "gprof.h"
     25 #include "libiberty.h"
     26 #include "search_list.h"
     27 #include "source.h"
     28 #include "symtab.h"
     29 #include "corefile.h"
     30 #include "gmon_io.h"
     31 #include "gmon_out.h"
     32 #include "hist.h"
     33 #include "sym_ids.h"
     34 #include "utils.h"
     35 #include "math.h"
     36 #include "stdio.h"
     37 #include "stdlib.h"
     38 
     39 #define UNITS_TO_CODE (offset_to_code / sizeof(UNIT))
     40 
     41 static void scale_and_align_entries (void);
     42 static void print_header (int);
     43 static void print_line (Sym *, double);
     44 static int cmp_time (const PTR, const PTR);
     45 
     46 /* Declarations of automatically generated functions to output blurbs.  */
     47 extern void flat_blurb (FILE * fp);
     48 
     49 static histogram *find_histogram (bfd_vma lowpc, bfd_vma highpc);
     50 static histogram *find_histogram_for_pc (bfd_vma pc);
     51 
     52 histogram * histograms;
     53 unsigned num_histograms;
     54 double hist_scale;
     55 static char hist_dimension[16] = "seconds";
     56 static char hist_dimension_abbrev = 's';
     57 
     58 static double accum_time;	/* Accumulated time so far for print_line(). */
     59 static double total_time;	/* Total time for all routines.  */
     60 
     61 /* Table of SI prefixes for powers of 10 (used to automatically
     62    scale some of the values in the flat profile).  */
     63 const struct
     64   {
     65     char prefix;
     66     double scale;
     67   }
     68 SItab[] =
     69 {
     70   { 'T', 1e-12 },				/* tera */
     71   { 'G', 1e-09 },				/* giga */
     72   { 'M', 1e-06 },				/* mega */
     73   { 'K', 1e-03 },				/* kilo */
     74   { ' ', 1e-00 },
     75   { 'm', 1e+03 },				/* milli */
     76   { 'u', 1e+06 },				/* micro */
     77   { 'n', 1e+09 },				/* nano */
     78   { 'p', 1e+12 },				/* pico */
     79   { 'f', 1e+15 },				/* femto */
     80   { 'a', 1e+18 }				/* ato */
     81 };
     82 
     83 /* Reads just the header part of histogram record into
     84    *RECORD from IFP.  FILENAME is the name of IFP and
     85    is provided for formatting error messages only.
     86 
     87    If FIRST is non-zero, sets global variables HZ, HIST_DIMENSION,
     88    HIST_DIMENSION_ABBREV, HIST_SCALE.  If FIRST is zero, checks
     89    that the new histogram is compatible with already-set values
     90    of those variables and emits an error if that's not so.  */
     91 static void
     92 read_histogram_header (histogram *record,
     93 		       FILE *ifp, const char *filename,
     94 		       int first)
     95 {
     96   unsigned int profrate;
     97   char n_hist_dimension[15];
     98   char n_hist_dimension_abbrev;
     99   double n_hist_scale;
    100 
    101   if (gmon_io_read_vma (ifp, &record->lowpc)
    102       || gmon_io_read_vma (ifp, &record->highpc)
    103       || gmon_io_read_32 (ifp, &record->num_bins)
    104       || gmon_io_read_32 (ifp, &profrate)
    105       || gmon_io_read (ifp, n_hist_dimension, 15)
    106       || gmon_io_read (ifp, &n_hist_dimension_abbrev, 1))
    107     {
    108       fprintf (stderr, _("%s: %s: unexpected end of file\n"),
    109 	       whoami, filename);
    110 
    111       done (1);
    112     }
    113 
    114   n_hist_scale = (double)((record->highpc - record->lowpc) / sizeof (UNIT))
    115     / record->num_bins;
    116 
    117   if (first)
    118     {
    119       /* We don't try to veryfy profrate is the same for all histogram
    120 	 records.  If we have two histogram records for the same
    121 	 address range and profiling samples is done as often
    122 	 as possible as opposed on timer, then the actual profrate will
    123 	 be slightly different.  Most of the time the difference does not
    124 	 matter and insisting that profiling rate is exactly the same
    125 	 will only create inconvenient.  */
    126       hz = profrate;
    127       memcpy (hist_dimension, n_hist_dimension, 15);
    128       hist_dimension_abbrev = n_hist_dimension_abbrev;
    129       hist_scale = n_hist_scale;
    130     }
    131   else
    132     {
    133       if (strncmp (n_hist_dimension, hist_dimension, 15) != 0)
    134 	{
    135 	  fprintf (stderr,
    136 		   _("%s: dimension unit changed between histogram records\n"
    137 		     "%s: from '%s'\n"
    138 		     "%s: to '%s'\n"),
    139 		   whoami, whoami, hist_dimension, whoami, n_hist_dimension);
    140 	  done (1);
    141 	}
    142 
    143       if (n_hist_dimension_abbrev != hist_dimension_abbrev)
    144 	{
    145 	  fprintf (stderr,
    146 		   _("%s: dimension abbreviation changed between histogram records\n"
    147 		     "%s: from '%c'\n"
    148 		     "%s: to '%c'\n"),
    149 		   whoami, whoami, hist_dimension_abbrev, whoami, n_hist_dimension_abbrev);
    150 	  done (1);
    151 	}
    152 
    153       /* The only reason we require the same scale for histograms is that
    154 	 there's code (notably printing code), that prints units,
    155 	 and it would be very confusing to have one unit mean different
    156 	 things for different functions.  */
    157       if (fabs (hist_scale - n_hist_scale) > 0.000001)
    158 	{
    159 	  fprintf (stderr,
    160 		   _("%s: different scales in histogram records"),
    161 		   whoami);
    162 	  done (1);
    163 	}
    164     }
    165 }
    166 
    167 /* Read the histogram from file IFP.  FILENAME is the name of IFP and
    168    is provided for formatting error messages only.  */
    169 
    170 void
    171 hist_read_rec (FILE * ifp, const char *filename)
    172 {
    173   bfd_vma lowpc, highpc;
    174   histogram n_record;
    175   histogram *record, *existing_record;
    176   unsigned i;
    177 
    178   /* 1. Read the header and see if there's existing record for the
    179      same address range and that there are no overlapping records.  */
    180   read_histogram_header (&n_record, ifp, filename, num_histograms == 0);
    181 
    182   existing_record = find_histogram (n_record.lowpc, n_record.highpc);
    183   if (existing_record)
    184     {
    185       record = existing_record;
    186     }
    187   else
    188     {
    189       /* If this record overlaps, but does not completely match an existing
    190 	 record, it's an error.  */
    191       lowpc = n_record.lowpc;
    192       highpc = n_record.highpc;
    193       hist_clip_symbol_address (&lowpc, &highpc);
    194       if (lowpc != highpc)
    195 	{
    196 	  fprintf (stderr,
    197 		   _("%s: overlapping histogram records\n"),
    198 		   whoami);
    199 	  done (1);
    200 	}
    201 
    202       /* This is new record.  Add it to global array and allocate space for
    203 	 the samples.  */
    204       histograms = (struct histogram *)
    205           xrealloc (histograms, sizeof (histogram) * (num_histograms + 1));
    206       memcpy (histograms + num_histograms,
    207 	      &n_record, sizeof (histogram));
    208       record = &histograms[num_histograms];
    209       ++num_histograms;
    210 
    211       record->sample = (int *) xmalloc (record->num_bins
    212 					* sizeof (record->sample[0]));
    213       memset (record->sample, 0, record->num_bins * sizeof (record->sample[0]));
    214     }
    215 
    216   /* 2. We have either a new record (with zeroed histogram data), or an existing
    217      record with some data in the histogram already.  Read new data into the
    218      record, adding hit counts.  */
    219 
    220   DBG (SAMPLEDEBUG,
    221        printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %u\n",
    222 	       (unsigned long) record->lowpc, (unsigned long) record->highpc,
    223                record->num_bins));
    224 
    225   for (i = 0; i < record->num_bins; ++i)
    226     {
    227       UNIT count;
    228       if (fread (&count[0], sizeof (count), 1, ifp) != 1)
    229 	{
    230 	  fprintf (stderr,
    231 		  _("%s: %s: unexpected EOF after reading %u of %u samples\n"),
    232 		   whoami, filename, i, record->num_bins);
    233 	  done (1);
    234 	}
    235       record->sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]);
    236       DBG (SAMPLEDEBUG,
    237 	   printf ("[hist_read_rec] 0x%lx: %u\n",
    238 		   (unsigned long) (record->lowpc
    239                                     + i * (record->highpc - record->lowpc)
    240                                     / record->num_bins),
    241 		   record->sample[i]));
    242     }
    243 }
    244 
    245 
    246 /* Write all execution histograms file OFP.  FILENAME is the name
    247    of OFP and is provided for formatting error-messages only.  */
    248 
    249 void
    250 hist_write_hist (FILE * ofp, const char *filename)
    251 {
    252   UNIT count;
    253   unsigned int i, r;
    254 
    255   for (r = 0; r < num_histograms; ++r)
    256     {
    257       histogram *record = &histograms[r];
    258 
    259       /* Write header.  */
    260 
    261       if (gmon_io_write_8 (ofp, GMON_TAG_TIME_HIST)
    262 	  || gmon_io_write_vma (ofp, record->lowpc)
    263 	  || gmon_io_write_vma (ofp, record->highpc)
    264 	  || gmon_io_write_32 (ofp, record->num_bins)
    265 	  || gmon_io_write_32 (ofp, hz)
    266 	  || gmon_io_write (ofp, hist_dimension, 15)
    267 	  || gmon_io_write (ofp, &hist_dimension_abbrev, 1))
    268 	{
    269 	  perror (filename);
    270 	  done (1);
    271 	}
    272 
    273       for (i = 0; i < record->num_bins; ++i)
    274 	{
    275 	  bfd_put_16 (core_bfd, (bfd_vma) record->sample[i], (bfd_byte *) &count[0]);
    276 
    277 	  if (fwrite (&count[0], sizeof (count), 1, ofp) != 1)
    278 	    {
    279 	      perror (filename);
    280 	      done (1);
    281 	    }
    282 	}
    283     }
    284 }
    285 
    286 /* Calculate scaled entry point addresses (to save time in
    287    hist_assign_samples), and, on architectures that have procedure
    288    entry masks at the start of a function, possibly push the scaled
    289    entry points over the procedure entry mask, if it turns out that
    290    the entry point is in one bin and the code for a routine is in the
    291    next bin.  */
    292 
    293 static void
    294 scale_and_align_entries ()
    295 {
    296   Sym *sym;
    297   bfd_vma bin_of_entry;
    298   bfd_vma bin_of_code;
    299 
    300   for (sym = symtab.base; sym < symtab.limit; sym++)
    301     {
    302       histogram *r = find_histogram_for_pc (sym->addr);
    303 
    304       sym->hist.scaled_addr = sym->addr / sizeof (UNIT);
    305 
    306       if (r)
    307 	{
    308 	  bin_of_entry = (sym->hist.scaled_addr - r->lowpc) / hist_scale;
    309 	  bin_of_code = ((sym->hist.scaled_addr + UNITS_TO_CODE - r->lowpc)
    310 		     / hist_scale);
    311 	  if (bin_of_entry < bin_of_code)
    312 	    {
    313 	      DBG (SAMPLEDEBUG,
    314 		   printf ("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
    315 			   (unsigned long) sym->hist.scaled_addr,
    316 			   (unsigned long) (sym->hist.scaled_addr
    317 					    + UNITS_TO_CODE)));
    318 	      sym->hist.scaled_addr += UNITS_TO_CODE;
    319 	    }
    320 	}
    321     }
    322 }
    323 
    324 
    325 /* Assign samples to the symbol to which they belong.
    326 
    327    Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
    328    which may overlap one more symbol address ranges.  If a symbol
    329    overlaps with the bin's address range by O percent, then O percent
    330    of the bin's count is credited to that symbol.
    331 
    332    There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
    333    with respect to the symbol's address range [SYM_LOW_PC,
    334    SYM_HIGH_PC) as shown in the following diagram.  OVERLAP computes
    335    the distance (in UNITs) between the arrows, the fraction of the
    336    sample that is to be credited to the symbol which starts at
    337    SYM_LOW_PC.
    338 
    339 	  sym_low_pc                                      sym_high_pc
    340 	       |                                               |
    341 	       v                                               v
    342 
    343 	       +-----------------------------------------------+
    344 	       |                                               |
    345 	  |  ->|    |<-         ->|         |<-         ->|    |<-  |
    346 	  |         |             |         |             |         |
    347 	  +---------+             +---------+             +---------+
    348 
    349 	  ^         ^             ^         ^             ^         ^
    350 	  |         |             |         |             |         |
    351      bin_low_pc bin_high_pc  bin_low_pc bin_high_pc  bin_low_pc bin_high_pc
    352 
    353    For the VAX we assert that samples will never fall in the first two
    354    bytes of any routine, since that is the entry mask, thus we call
    355    scale_and_align_entries() to adjust the entry points if the entry
    356    mask falls in one bin but the code for the routine doesn't start
    357    until the next bin.  In conjunction with the alignment of routine
    358    addresses, this should allow us to have only one sample for every
    359    four bytes of text space and never have any overlap (the two end
    360    cases, above).  */
    361 
    362 static void
    363 hist_assign_samples_1 (histogram *r)
    364 {
    365   bfd_vma bin_low_pc, bin_high_pc;
    366   bfd_vma sym_low_pc, sym_high_pc;
    367   bfd_vma overlap, addr;
    368   unsigned int bin_count;
    369   unsigned int i, j, k;
    370   double count_time, credit;
    371 
    372   bfd_vma lowpc = r->lowpc / sizeof (UNIT);
    373 
    374   /* Iterate over all sample bins.  */
    375   for (i = 0, k = 1; i < r->num_bins; ++i)
    376     {
    377       bin_count = r->sample[i];
    378       if (! bin_count)
    379 	continue;
    380 
    381       bin_low_pc = lowpc + (bfd_vma) (hist_scale * i);
    382       bin_high_pc = lowpc + (bfd_vma) (hist_scale * (i + 1));
    383       count_time = bin_count;
    384 
    385       DBG (SAMPLEDEBUG,
    386 	   printf (
    387       "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%u\n",
    388 		    (unsigned long) (sizeof (UNIT) * bin_low_pc),
    389 		    (unsigned long) (sizeof (UNIT) * bin_high_pc),
    390 		    bin_count));
    391       total_time += count_time;
    392 
    393       /* Credit all symbols that are covered by bin I.
    394 
    395          PR gprof/13325: Make sure that K does not get decremented
    396 	 and J will never be less than 0.  */
    397       for (j = k - 1; j < symtab.len; k = ++j)
    398 	{
    399 	  sym_low_pc = symtab.base[j].hist.scaled_addr;
    400 	  sym_high_pc = symtab.base[j + 1].hist.scaled_addr;
    401 
    402 	  /* If high end of bin is below entry address,
    403 	     go for next bin.  */
    404 	  if (bin_high_pc < sym_low_pc)
    405 	    break;
    406 
    407 	  /* If low end of bin is above high end of symbol,
    408 	     go for next symbol.  */
    409 	  if (bin_low_pc >= sym_high_pc)
    410 	    continue;
    411 
    412 	  overlap =
    413 	    MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc);
    414 	  if (overlap > 0)
    415 	    {
    416 	      DBG (SAMPLEDEBUG,
    417 		   printf (
    418 	       "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
    419 			   (unsigned long) symtab.base[j].addr,
    420 			   (unsigned long) (sizeof (UNIT) * sym_high_pc),
    421 			   symtab.base[j].name, overlap * count_time / hist_scale,
    422 			   (long) overlap));
    423 
    424 	      addr = symtab.base[j].addr;
    425 	      credit = overlap * count_time / hist_scale;
    426 
    427 	      /* Credit symbol if it appears in INCL_FLAT or that
    428 		 table is empty and it does not appear it in
    429 		 EXCL_FLAT.  */
    430 	      if (sym_lookup (&syms[INCL_FLAT], addr)
    431 		  || (syms[INCL_FLAT].len == 0
    432 		      && !sym_lookup (&syms[EXCL_FLAT], addr)))
    433 		{
    434 		  symtab.base[j].hist.time += credit;
    435 		}
    436 	      else
    437 		{
    438 		  total_time -= credit;
    439 		}
    440 	    }
    441 	}
    442     }
    443 
    444   DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n",
    445 			    total_time));
    446 }
    447 
    448 /* Calls 'hist_assign_sampes_1' for all histogram records read so far. */
    449 void
    450 hist_assign_samples ()
    451 {
    452   unsigned i;
    453 
    454   scale_and_align_entries ();
    455 
    456   for (i = 0; i < num_histograms; ++i)
    457     hist_assign_samples_1 (&histograms[i]);
    458 
    459 }
    460 
    461 /* Print header for flag histogram profile.  */
    462 
    463 static void
    464 print_header (int prefix)
    465 {
    466   char unit[64];
    467 
    468   sprintf (unit, _("%c%c/call"), prefix, hist_dimension_abbrev);
    469 
    470   if (bsd_style_output)
    471     {
    472       printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
    473 	      (long) hist_scale * (long) sizeof (UNIT));
    474       if (total_time > 0.0)
    475 	{
    476 	  printf (_(" for %.2f%% of %.2f %s\n\n"),
    477 		  100.0 / total_time, total_time / hz, hist_dimension);
    478 	}
    479     }
    480   else
    481     {
    482       printf (_("\nEach sample counts as %g %s.\n"), 1.0 / hz, hist_dimension);
    483     }
    484 
    485   if (total_time <= 0.0)
    486     {
    487       printf (_(" no time accumulated\n\n"));
    488 
    489       /* This doesn't hurt since all the numerators will be zero.  */
    490       total_time = 1.0;
    491     }
    492 
    493   printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
    494 	  "%  ", _("cumulative"), _("self  "), "", _("self  "), _("total "),
    495 	  "");
    496   printf ("%5.5s %9.9s  %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
    497 	  _("time"), hist_dimension, hist_dimension, _("calls"), unit, unit,
    498 	  _("name"));
    499 }
    500 
    501 
    502 static void
    503 print_line (Sym *sym, double scale)
    504 {
    505   if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0)
    506     return;
    507 
    508   accum_time += sym->hist.time;
    509 
    510   if (bsd_style_output)
    511     printf ("%5.1f %10.2f %8.2f",
    512 	    total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
    513 	    accum_time / hz, sym->hist.time / hz);
    514   else
    515     printf ("%6.2f %9.2f %8.2f",
    516 	    total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
    517 	    accum_time / hz, sym->hist.time / hz);
    518 
    519   if (sym->ncalls != 0)
    520     printf (" %8lu %8.2f %8.2f  ",
    521 	    sym->ncalls, scale * sym->hist.time / hz / sym->ncalls,
    522 	    scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls);
    523   else
    524     printf (" %8.8s %8.8s %8.8s  ", "", "", "");
    525 
    526   if (bsd_style_output)
    527     print_name (sym);
    528   else
    529     print_name_only (sym);
    530 
    531   printf ("\n");
    532 }
    533 
    534 
    535 /* Compare LP and RP.  The primary comparison key is execution time,
    536    the secondary is number of invocation, and the tertiary is the
    537    lexicographic order of the function names.  */
    538 
    539 static int
    540 cmp_time (const PTR lp, const PTR rp)
    541 {
    542   const Sym *left = *(const Sym **) lp;
    543   const Sym *right = *(const Sym **) rp;
    544   double time_diff;
    545 
    546   time_diff = right->hist.time - left->hist.time;
    547 
    548   if (time_diff > 0.0)
    549     return 1;
    550 
    551   if (time_diff < 0.0)
    552     return -1;
    553 
    554   if (right->ncalls > left->ncalls)
    555     return 1;
    556 
    557   if (right->ncalls < left->ncalls)
    558     return -1;
    559 
    560   return strcmp (left->name, right->name);
    561 }
    562 
    563 
    564 /* Print the flat histogram profile.  */
    565 
    566 void
    567 hist_print ()
    568 {
    569   Sym **time_sorted_syms, *top_dog, *sym;
    570   unsigned int sym_index;
    571   unsigned log_scale;
    572   double top_time;
    573   bfd_vma addr;
    574 
    575   if (first_output)
    576     first_output = FALSE;
    577   else
    578     printf ("\f\n");
    579 
    580   accum_time = 0.0;
    581 
    582   if (bsd_style_output)
    583     {
    584       if (print_descriptions)
    585 	{
    586 	  printf (_("\n\n\nflat profile:\n"));
    587 	  flat_blurb (stdout);
    588 	}
    589     }
    590   else
    591     {
    592       printf (_("Flat profile:\n"));
    593     }
    594 
    595   /* Sort the symbol table by time (call-count and name as secondary
    596      and tertiary keys).  */
    597   time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
    598 
    599   for (sym_index = 0; sym_index < symtab.len; ++sym_index)
    600     time_sorted_syms[sym_index] = &symtab.base[sym_index];
    601 
    602   qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
    603 
    604   if (bsd_style_output)
    605     {
    606       log_scale = 5;		/* Milli-seconds is BSD-default.  */
    607     }
    608   else
    609     {
    610       /* Search for symbol with highest per-call
    611 	 execution time and scale accordingly.  */
    612       log_scale = 0;
    613       top_dog = 0;
    614       top_time = 0.0;
    615 
    616       for (sym_index = 0; sym_index < symtab.len; ++sym_index)
    617 	{
    618 	  sym = time_sorted_syms[sym_index];
    619 
    620 	  if (sym->ncalls != 0)
    621 	    {
    622 	      double call_time;
    623 
    624 	      call_time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
    625 
    626 	      if (call_time > top_time)
    627 		{
    628 		  top_dog = sym;
    629 		  top_time = call_time;
    630 		}
    631 	    }
    632 	}
    633 
    634       if (top_dog && top_dog->ncalls != 0 && top_time > 0.0)
    635 	{
    636 	  top_time /= hz;
    637 
    638 	  for (log_scale = 0; log_scale < ARRAY_SIZE (SItab); log_scale ++)
    639 	    {
    640 	      double scaled_value = SItab[log_scale].scale * top_time;
    641 
    642 	      if (scaled_value >= 1.0 && scaled_value < 1000.0)
    643 		break;
    644 	    }
    645 	}
    646     }
    647 
    648   /* For now, the dimension is always seconds.  In the future, we
    649      may also want to support other (pseudo-)dimensions (such as
    650      I-cache misses etc.).  */
    651   print_header (SItab[log_scale].prefix);
    652 
    653   for (sym_index = 0; sym_index < symtab.len; ++sym_index)
    654     {
    655       addr = time_sorted_syms[sym_index]->addr;
    656 
    657       /* Print symbol if its in INCL_FLAT table or that table
    658 	is empty and the symbol is not in EXCL_FLAT.  */
    659       if (sym_lookup (&syms[INCL_FLAT], addr)
    660 	  || (syms[INCL_FLAT].len == 0
    661 	      && !sym_lookup (&syms[EXCL_FLAT], addr)))
    662 	print_line (time_sorted_syms[sym_index], SItab[log_scale].scale);
    663     }
    664 
    665   free (time_sorted_syms);
    666 
    667   if (print_descriptions && !bsd_style_output)
    668     flat_blurb (stdout);
    669 }
    670 
    671 int
    672 hist_check_address (unsigned address)
    673 {
    674   unsigned i;
    675 
    676   for (i = 0; i < num_histograms; ++i)
    677     if (histograms[i].lowpc <= address && address < histograms[i].highpc)
    678       return 1;
    679 
    680   return 0;
    681 }
    682 
    683 #if ! defined(min)
    684 #define min(a,b) (((a)<(b)) ? (a) : (b))
    685 #endif
    686 #if ! defined(max)
    687 #define max(a,b) (((a)>(b)) ? (a) : (b))
    688 #endif
    689 
    690 void
    691 hist_clip_symbol_address (bfd_vma *p_lowpc, bfd_vma *p_highpc)
    692 {
    693   unsigned i;
    694   int found = 0;
    695 
    696   if (num_histograms == 0)
    697     {
    698       *p_highpc = *p_lowpc;
    699       return;
    700     }
    701 
    702   for (i = 0; i < num_histograms; ++i)
    703     {
    704       bfd_vma common_low, common_high;
    705       common_low = max (histograms[i].lowpc, *p_lowpc);
    706       common_high = min (histograms[i].highpc, *p_highpc);
    707 
    708       if (common_low < common_high)
    709 	{
    710 	  if (found)
    711 	    {
    712 	      fprintf (stderr,
    713 		       _("%s: found a symbol that covers "
    714 			 "several histogram records"),
    715 			 whoami);
    716 	      done (1);
    717 	    }
    718 
    719 	  found = 1;
    720 	  *p_lowpc = common_low;
    721 	  *p_highpc = common_high;
    722 	}
    723     }
    724 
    725   if (!found)
    726     *p_highpc = *p_lowpc;
    727 }
    728 
    729 /* Find and return exising histogram record having the same lowpc and
    730    highpc as passed via the parameters.  Return NULL if nothing is found.
    731    The return value is valid until any new histogram is read.  */
    732 static histogram *
    733 find_histogram (bfd_vma lowpc, bfd_vma highpc)
    734 {
    735   unsigned i;
    736   for (i = 0; i < num_histograms; ++i)
    737     {
    738       if (histograms[i].lowpc == lowpc && histograms[i].highpc == highpc)
    739 	return &histograms[i];
    740     }
    741   return 0;
    742 }
    743 
    744 /* Given a PC, return histogram record which address range include this PC.
    745    Return NULL if there's no such record.  */
    746 static histogram *
    747 find_histogram_for_pc (bfd_vma pc)
    748 {
    749   unsigned i;
    750   for (i = 0; i < num_histograms; ++i)
    751     {
    752       if (histograms[i].lowpc <= pc && pc < histograms[i].highpc)
    753 	return &histograms[i];
    754     }
    755   return 0;
    756 }
    757