Home | History | Annotate | Line # | Download | only in gprof
      1 /* hist.c  -  Histogram related operations.
      2 
      3    Copyright (C) 1999-2026 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"
     23 #include "libiberty.h"
     24 #include "search_list.h"
     25 #include "source.h"
     26 #include "symtab.h"
     27 #include "corefile.h"
     28 #include "gmon_io.h"
     29 #include "gmon_out.h"
     30 #include "hist.h"
     31 #include "sym_ids.h"
     32 #include "utils.h"
     33 #include "math.h"
     34 #include "stdio.h"
     35 #include "stdlib.h"
     36 
     37 #define UNITS_TO_CODE (offset_to_code / sizeof(UNIT))
     38 
     39 static void scale_and_align_entries (void);
     40 static void print_header (int);
     41 static void print_line (Sym *, double);
     42 static int cmp_time (const void *, const void *);
     43 
     44 /* Declarations of automatically generated functions to output blurbs.  */
     45 extern void flat_blurb (FILE * fp);
     46 
     47 static histogram *find_histogram (bfd_vma lowpc, bfd_vma highpc);
     48 static histogram *find_histogram_for_pc (bfd_vma pc);
     49 
     50 histogram * histograms;
     51 unsigned num_histograms;
     52 double hist_scale;
     53 static char hist_dimension[16] = "seconds";
     54 static char hist_dimension_abbrev = 's';
     55 
     56 static double accum_time;	/* Accumulated time so far for print_line(). */
     57 static double total_time;	/* Total time for all routines.  */
     58 
     59 /* Table of SI prefixes for powers of 10 (used to automatically
     60    scale some of the values in the flat profile).  */
     61 const struct
     62   {
     63     char prefix;
     64     double scale;
     65   }
     66 SItab[] =
     67 {
     68   { 'T', 1e-12 },				/* tera */
     69   { 'G', 1e-09 },				/* giga */
     70   { 'M', 1e-06 },				/* mega */
     71   { 'K', 1e-03 },				/* kilo */
     72   { ' ', 1e-00 },
     73   { 'm', 1e+03 },				/* milli */
     74   { 'u', 1e+06 },				/* micro */
     75   { 'n', 1e+09 },				/* nano */
     76   { 'p', 1e+12 },				/* pico */
     77   { 'f', 1e+15 },				/* femto */
     78   { 'a', 1e+18 }				/* ato */
     79 };
     80 
     81 /* Reads just the header part of histogram record into
     82    *RECORD from IFP.  FILENAME is the name of IFP and
     83    is provided for formatting error messages only.
     84 
     85    If FIRST is non-zero, sets global variables HZ, HIST_DIMENSION,
     86    HIST_DIMENSION_ABBREV, HIST_SCALE.  If FIRST is zero, checks
     87    that the new histogram is compatible with already-set values
     88    of those variables and emits an error if that's not so.  */
     89 static void
     90 read_histogram_header (histogram *record,
     91 		       FILE *ifp, const char *filename,
     92 		       int first)
     93 {
     94   unsigned int profrate;
     95   char n_hist_dimension[15];
     96   char n_hist_dimension_abbrev;
     97   double n_hist_scale;
     98 
     99   if (gmon_io_read_vma (ifp, &record->lowpc)
    100       || gmon_io_read_vma (ifp, &record->highpc)
    101       || gmon_io_read_32 (ifp, &record->num_bins)
    102       || gmon_io_read_32 (ifp, &profrate)
    103       || gmon_io_read (ifp, n_hist_dimension, 15)
    104       || gmon_io_read (ifp, &n_hist_dimension_abbrev, 1))
    105     {
    106       fprintf (stderr, _("%s: %s: unexpected end of file\n"),
    107 	       whoami, filename);
    108 
    109       done (1);
    110     }
    111 
    112   n_hist_scale = (double)(record->highpc - record->lowpc) / sizeof (UNIT)
    113     / record->num_bins;
    114 
    115   if (first)
    116     {
    117       /* We don't try to verify profrate is the same for all histogram
    118 	 records.  If we have two histogram records for the same
    119 	 address range and profiling samples is done as often
    120 	 as possible as opposed on timer, then the actual profrate will
    121 	 be slightly different.  Most of the time the difference does not
    122 	 matter and insisting that profiling rate is exactly the same
    123 	 will only create inconvenient.  */
    124       hz = profrate;
    125       memcpy (hist_dimension, n_hist_dimension, 15);
    126       hist_dimension_abbrev = n_hist_dimension_abbrev;
    127       hist_scale = n_hist_scale;
    128     }
    129   else
    130     {
    131       if (strncmp (n_hist_dimension, hist_dimension, 15) != 0)
    132 	{
    133 	  fprintf (stderr,
    134 		   _("%s: dimension unit changed between histogram records\n"
    135 		     "%s: from '%s'\n"
    136 		     "%s: to '%s'\n"),
    137 		   whoami, whoami, hist_dimension, whoami, n_hist_dimension);
    138 	  done (1);
    139 	}
    140 
    141       if (n_hist_dimension_abbrev != hist_dimension_abbrev)
    142 	{
    143 	  fprintf (stderr,
    144 		   _("%s: dimension abbreviation changed between histogram records\n"
    145 		     "%s: from '%c'\n"
    146 		     "%s: to '%c'\n"),
    147 		   whoami, whoami, hist_dimension_abbrev, whoami, n_hist_dimension_abbrev);
    148 	  done (1);
    149 	}
    150 
    151       /* The only reason we require the same scale for histograms is that
    152 	 there's code (notably printing code), that prints units,
    153 	 and it would be very confusing to have one unit mean different
    154 	 things for different functions.  */
    155       if (fabs (hist_scale - n_hist_scale) > 0.000001)
    156 	{
    157 	  fprintf (stderr,
    158 		   _("%s: different scales in histogram records: %f != %f\n"),
    159 		   whoami, hist_scale, n_hist_scale);
    160 	  done (1);
    161 	}
    162     }
    163 }
    164 
    165 /* Read the histogram from file IFP.  FILENAME is the name of IFP and
    166    is provided for formatting error messages only.  */
    167 
    168 void
    169 hist_read_rec (FILE * ifp, const char *filename)
    170 {
    171   bfd_vma lowpc, highpc;
    172   histogram n_record;
    173   histogram *record, *existing_record;
    174   unsigned i;
    175 
    176   /* 1. Read the header and see if there's existing record for the
    177      same address range and that there are no overlapping records.  */
    178   read_histogram_header (&n_record, ifp, filename, num_histograms == 0);
    179 
    180   existing_record = find_histogram (n_record.lowpc, n_record.highpc);
    181   if (existing_record)
    182     {
    183       record = existing_record;
    184     }
    185   else
    186     {
    187       /* If this record overlaps, but does not completely match an existing
    188 	 record, it's an error.  */
    189       lowpc = n_record.lowpc;
    190       highpc = n_record.highpc;
    191       hist_clip_symbol_address (&lowpc, &highpc);
    192       if (lowpc != highpc)
    193 	{
    194 	  fprintf (stderr,
    195 		   _("%s: overlapping histogram records\n"),
    196 		   whoami);
    197 	  done (1);
    198 	}
    199 
    200       /* This is new record.  Add it to global array and allocate space for
    201 	 the samples.  */
    202       histograms = (struct histogram *)
    203           xrealloc (histograms, sizeof (histogram) * (num_histograms + 1));
    204       memcpy (histograms + num_histograms,
    205 	      &n_record, sizeof (histogram));
    206       record = &histograms[num_histograms];
    207       ++num_histograms;
    208 
    209       record->sample = (int *) xmalloc (record->num_bins
    210 					* sizeof (record->sample[0]));
    211       memset (record->sample, 0, record->num_bins * sizeof (record->sample[0]));
    212     }
    213 
    214   /* 2. We have either a new record (with zeroed histogram data), or an existing
    215      record with some data in the histogram already.  Read new data into the
    216      record, adding hit counts.  */
    217 
    218   DBG (SAMPLEDEBUG,
    219        printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %u\n",
    220 	       (unsigned long) record->lowpc, (unsigned long) record->highpc,
    221                record->num_bins));
    222 
    223   for (i = 0; i < record->num_bins; ++i)
    224     {
    225       UNIT count;
    226       if (fread (&count[0], sizeof (count), 1, ifp) != 1)
    227 	{
    228 	  fprintf (stderr,
    229 		  _("%s: %s: unexpected EOF after reading %u of %u samples\n"),
    230 		   whoami, filename, i, record->num_bins);
    231 	  done (1);
    232 	}
    233       record->sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]);
    234       DBG (SAMPLEDEBUG,
    235 	   printf ("[hist_read_rec] 0x%lx: %u\n",
    236 		   (unsigned long) (record->lowpc
    237                                     + i * (record->highpc - record->lowpc)
    238                                     / record->num_bins),
    239 		   record->sample[i]));
    240     }
    241 }
    242 
    243 
    244 /* Write all execution histograms file OFP.  FILENAME is the name
    245    of OFP and is provided for formatting error-messages only.  */
    246 
    247 void
    248 hist_write_hist (FILE * ofp, const char *filename)
    249 {
    250   UNIT count;
    251   unsigned int i, r;
    252 
    253   for (r = 0; r < num_histograms; ++r)
    254     {
    255       histogram *record = &histograms[r];
    256 
    257       /* Write header.  */
    258 
    259       if (gmon_io_write_8 (ofp, GMON_TAG_TIME_HIST)
    260 	  || gmon_io_write_vma (ofp, record->lowpc)
    261 	  || gmon_io_write_vma (ofp, record->highpc)
    262 	  || gmon_io_write_32 (ofp, record->num_bins)
    263 	  || gmon_io_write_32 (ofp, hz)
    264 	  || gmon_io_write (ofp, hist_dimension, 15)
    265 	  || gmon_io_write (ofp, &hist_dimension_abbrev, 1))
    266 	{
    267 	  perror (filename);
    268 	  done (1);
    269 	}
    270 
    271       for (i = 0; i < record->num_bins; ++i)
    272 	{
    273 	  bfd_put_16 (core_bfd, (bfd_vma) record->sample[i], (bfd_byte *) &count[0]);
    274 
    275 	  if (fwrite (&count[0], sizeof (count), 1, ofp) != 1)
    276 	    {
    277 	      perror (filename);
    278 	      done (1);
    279 	    }
    280 	}
    281     }
    282 }
    283 
    284 /* Calculate scaled entry point addresses (to save time in
    285    hist_assign_samples), and, on architectures that have procedure
    286    entry masks at the start of a function, possibly push the scaled
    287    entry points over the procedure entry mask, if it turns out that
    288    the entry point is in one bin and the code for a routine is in the
    289    next bin.  */
    290 
    291 static void
    292 scale_and_align_entries (void)
    293 {
    294   Sym *sym;
    295   bfd_vma bin_of_entry;
    296   bfd_vma bin_of_code;
    297   Sym_Table *symtab = get_symtab ();
    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   Sym_Table *symtab = get_symtab ();
    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_samples_1' for all histogram records read so far. */
    449 void
    450 hist_assign_samples (void)
    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 void *lp, const void *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 (void)
    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   Sym_Table *symtab = get_symtab ();
    575 
    576   if (first_output)
    577     first_output = false;
    578   else
    579     printf ("\f\n");
    580 
    581   accum_time = 0.0;
    582 
    583   if (bsd_style_output)
    584     {
    585       if (print_descriptions)
    586 	{
    587 	  printf (_("\n\n\nflat profile:\n"));
    588 	  flat_blurb (stdout);
    589 	}
    590     }
    591   else
    592     {
    593       printf (_("Flat profile:\n"));
    594     }
    595 
    596   /* Sort the symbol table by time (call-count and name as secondary
    597      and tertiary keys).  */
    598   time_sorted_syms = (Sym **) xmalloc (symtab->len * sizeof (Sym *));
    599 
    600   for (sym_index = 0; sym_index < symtab->len; ++sym_index)
    601     time_sorted_syms[sym_index] = &symtab->base[sym_index];
    602 
    603   qsort (time_sorted_syms, symtab->len, sizeof (Sym *), cmp_time);
    604 
    605   if (bsd_style_output)
    606     {
    607       log_scale = 5;		/* Milli-seconds is BSD-default.  */
    608     }
    609   else
    610     {
    611       /* Search for symbol with highest per-call
    612 	 execution time and scale accordingly.  */
    613       log_scale = 0;
    614       top_dog = 0;
    615       top_time = 0.0;
    616 
    617       for (sym_index = 0; sym_index < symtab->len; ++sym_index)
    618 	{
    619 	  sym = time_sorted_syms[sym_index];
    620 
    621 	  if (sym->ncalls != 0)
    622 	    {
    623 	      double call_time;
    624 
    625 	      call_time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
    626 
    627 	      if (call_time > top_time)
    628 		{
    629 		  top_dog = sym;
    630 		  top_time = call_time;
    631 		}
    632 	    }
    633 	}
    634 
    635       if (top_dog && top_dog->ncalls != 0 && top_time > 0.0)
    636 	{
    637 	  top_time /= hz;
    638 
    639 	  for (log_scale = 0; log_scale < ARRAY_SIZE (SItab); log_scale ++)
    640 	    {
    641 	      double scaled_value = SItab[log_scale].scale * top_time;
    642 
    643 	      if (scaled_value >= 1.0 && scaled_value < 1000.0)
    644 		break;
    645 	    }
    646 	}
    647     }
    648 
    649   /* For now, the dimension is always seconds.  In the future, we
    650      may also want to support other (pseudo-)dimensions (such as
    651      I-cache misses etc.).  */
    652   print_header (SItab[log_scale].prefix);
    653 
    654   for (sym_index = 0; sym_index < symtab->len; ++sym_index)
    655     {
    656       addr = time_sorted_syms[sym_index]->addr;
    657 
    658       /* Print symbol if its in INCL_FLAT table or that table
    659 	is empty and the symbol is not in EXCL_FLAT.  */
    660       if (sym_lookup (&syms[INCL_FLAT], addr)
    661 	  || (syms[INCL_FLAT].len == 0
    662 	      && !sym_lookup (&syms[EXCL_FLAT], addr)))
    663 	print_line (time_sorted_syms[sym_index], SItab[log_scale].scale);
    664     }
    665 
    666   free (time_sorted_syms);
    667 
    668   if (print_descriptions && !bsd_style_output)
    669     flat_blurb (stdout);
    670 }
    671 
    672 int
    673 hist_check_address (unsigned address)
    674 {
    675   unsigned i;
    676 
    677   for (i = 0; i < num_histograms; ++i)
    678     if (histograms[i].lowpc <= address && address < histograms[i].highpc)
    679       return 1;
    680 
    681   return 0;
    682 }
    683 
    684 #if ! defined(min)
    685 #define min(a,b) (((a)<(b)) ? (a) : (b))
    686 #endif
    687 #if ! defined(max)
    688 #define max(a,b) (((a)>(b)) ? (a) : (b))
    689 #endif
    690 
    691 void
    692 hist_clip_symbol_address (bfd_vma *p_lowpc, bfd_vma *p_highpc)
    693 {
    694   unsigned i;
    695   int found = 0;
    696 
    697   if (num_histograms == 0)
    698     {
    699       *p_highpc = *p_lowpc;
    700       return;
    701     }
    702 
    703   for (i = 0; i < num_histograms; ++i)
    704     {
    705       bfd_vma common_low, common_high;
    706       common_low = max (histograms[i].lowpc, *p_lowpc);
    707       common_high = min (histograms[i].highpc, *p_highpc);
    708 
    709       if (common_low < common_high)
    710 	{
    711 	  if (found)
    712 	    {
    713 	      fprintf (stderr,
    714 		       _("%s: found a symbol that covers "
    715 			 "several histogram records"),
    716 			 whoami);
    717 	      done (1);
    718 	    }
    719 
    720 	  found = 1;
    721 	  *p_lowpc = common_low;
    722 	  *p_highpc = common_high;
    723 	}
    724     }
    725 
    726   if (!found)
    727     *p_highpc = *p_lowpc;
    728 }
    729 
    730 /* Find and return existing histogram record having the same lowpc and
    731    highpc as passed via the parameters.  Return NULL if nothing is found.
    732    The return value is valid until any new histogram is read.  */
    733 static histogram *
    734 find_histogram (bfd_vma lowpc, bfd_vma highpc)
    735 {
    736   unsigned i;
    737   for (i = 0; i < num_histograms; ++i)
    738     {
    739       if (histograms[i].lowpc == lowpc && histograms[i].highpc == highpc)
    740 	return &histograms[i];
    741     }
    742   return 0;
    743 }
    744 
    745 /* Given a PC, return histogram record which address range include this PC.
    746    Return NULL if there's no such record.  */
    747 static histogram *
    748 find_histogram_for_pc (bfd_vma pc)
    749 {
    750   unsigned i;
    751   for (i = 0; i < num_histograms; ++i)
    752     {
    753       if (histograms[i].lowpc <= pc && pc < histograms[i].highpc)
    754 	return &histograms[i];
    755     }
    756   return 0;
    757 }
    758