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