xref: /netbsd-src/external/gpl3/binutils/dist/gprof/hist.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
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"
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;
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, j = 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       for (j = j - 1; j < symtab.len; ++j)
394 	{
395 	  sym_low_pc = symtab.base[j].hist.scaled_addr;
396 	  sym_high_pc = symtab.base[j + 1].hist.scaled_addr;
397 
398 	  /* If high end of bin is below entry address,
399 	     go for next bin.  */
400 	  if (bin_high_pc < sym_low_pc)
401 	    break;
402 
403 	  /* If low end of bin is above high end of symbol,
404 	     go for next symbol.  */
405 	  if (bin_low_pc >= sym_high_pc)
406 	    continue;
407 
408 	  overlap =
409 	    MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc);
410 	  if (overlap > 0)
411 	    {
412 	      DBG (SAMPLEDEBUG,
413 		   printf (
414 	       "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
415 			   (unsigned long) symtab.base[j].addr,
416 			   (unsigned long) (sizeof (UNIT) * sym_high_pc),
417 			   symtab.base[j].name, overlap * count_time / hist_scale,
418 			   (long) overlap));
419 
420 	      addr = symtab.base[j].addr;
421 	      credit = overlap * count_time / hist_scale;
422 
423 	      /* Credit symbol if it appears in INCL_FLAT or that
424 		 table is empty and it does not appear it in
425 		 EXCL_FLAT.  */
426 	      if (sym_lookup (&syms[INCL_FLAT], addr)
427 		  || (syms[INCL_FLAT].len == 0
428 		      && !sym_lookup (&syms[EXCL_FLAT], addr)))
429 		{
430 		  symtab.base[j].hist.time += credit;
431 		}
432 	      else
433 		{
434 		  total_time -= credit;
435 		}
436 	    }
437 	}
438     }
439 
440   DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n",
441 			    total_time));
442 }
443 
444 /* Calls 'hist_assign_sampes_1' for all histogram records read so far. */
445 void
446 hist_assign_samples ()
447 {
448   unsigned i;
449 
450   scale_and_align_entries ();
451 
452   for (i = 0; i < num_histograms; ++i)
453     hist_assign_samples_1 (&histograms[i]);
454 
455 }
456 
457 /* Print header for flag histogram profile.  */
458 
459 static void
460 print_header (int prefix)
461 {
462   char unit[64];
463 
464   sprintf (unit, _("%c%c/call"), prefix, hist_dimension_abbrev);
465 
466   if (bsd_style_output)
467     {
468       printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
469 	      (long) hist_scale * (long) sizeof (UNIT));
470       if (total_time > 0.0)
471 	{
472 	  printf (_(" for %.2f%% of %.2f %s\n\n"),
473 		  100.0 / total_time, total_time / hz, hist_dimension);
474 	}
475     }
476   else
477     {
478       printf (_("\nEach sample counts as %g %s.\n"), 1.0 / hz, hist_dimension);
479     }
480 
481   if (total_time <= 0.0)
482     {
483       printf (_(" no time accumulated\n\n"));
484 
485       /* This doesn't hurt since all the numerators will be zero.  */
486       total_time = 1.0;
487     }
488 
489   printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
490 	  "%  ", _("cumulative"), _("self  "), "", _("self  "), _("total "),
491 	  "");
492   printf ("%5.5s %9.9s  %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
493 	  _("time"), hist_dimension, hist_dimension, _("calls"), unit, unit,
494 	  _("name"));
495 }
496 
497 
498 static void
499 print_line (Sym *sym, double scale)
500 {
501   if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0)
502     return;
503 
504   accum_time += sym->hist.time;
505 
506   if (bsd_style_output)
507     printf ("%5.1f %10.2f %8.2f",
508 	    total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
509 	    accum_time / hz, sym->hist.time / hz);
510   else
511     printf ("%6.2f %9.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 
515   if (sym->ncalls != 0)
516     printf (" %8lu %8.2f %8.2f  ",
517 	    sym->ncalls, scale * sym->hist.time / hz / sym->ncalls,
518 	    scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls);
519   else
520     printf (" %8.8s %8.8s %8.8s  ", "", "", "");
521 
522   if (bsd_style_output)
523     print_name (sym);
524   else
525     print_name_only (sym);
526 
527   printf ("\n");
528 }
529 
530 
531 /* Compare LP and RP.  The primary comparison key is execution time,
532    the secondary is number of invocation, and the tertiary is the
533    lexicographic order of the function names.  */
534 
535 static int
536 cmp_time (const PTR lp, const PTR rp)
537 {
538   const Sym *left = *(const Sym **) lp;
539   const Sym *right = *(const Sym **) rp;
540   double time_diff;
541 
542   time_diff = right->hist.time - left->hist.time;
543 
544   if (time_diff > 0.0)
545     return 1;
546 
547   if (time_diff < 0.0)
548     return -1;
549 
550   if (right->ncalls > left->ncalls)
551     return 1;
552 
553   if (right->ncalls < left->ncalls)
554     return -1;
555 
556   return strcmp (left->name, right->name);
557 }
558 
559 
560 /* Print the flat histogram profile.  */
561 
562 void
563 hist_print ()
564 {
565   Sym **time_sorted_syms, *top_dog, *sym;
566   unsigned int sym_index;
567   unsigned log_scale;
568   double top_time;
569   bfd_vma addr;
570 
571   if (first_output)
572     first_output = FALSE;
573   else
574     printf ("\f\n");
575 
576   accum_time = 0.0;
577 
578   if (bsd_style_output)
579     {
580       if (print_descriptions)
581 	{
582 	  printf (_("\n\n\nflat profile:\n"));
583 	  flat_blurb (stdout);
584 	}
585     }
586   else
587     {
588       printf (_("Flat profile:\n"));
589     }
590 
591   /* Sort the symbol table by time (call-count and name as secondary
592      and tertiary keys).  */
593   time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
594 
595   for (sym_index = 0; sym_index < symtab.len; ++sym_index)
596     time_sorted_syms[sym_index] = &symtab.base[sym_index];
597 
598   qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
599 
600   if (bsd_style_output)
601     {
602       log_scale = 5;		/* Milli-seconds is BSD-default.  */
603     }
604   else
605     {
606       /* Search for symbol with highest per-call
607 	 execution time and scale accordingly.  */
608       log_scale = 0;
609       top_dog = 0;
610       top_time = 0.0;
611 
612       for (sym_index = 0; sym_index < symtab.len; ++sym_index)
613 	{
614 	  sym = time_sorted_syms[sym_index];
615 
616 	  if (sym->ncalls != 0)
617 	    {
618 	      double call_time;
619 
620 	      call_time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
621 
622 	      if (call_time > top_time)
623 		{
624 		  top_dog = sym;
625 		  top_time = call_time;
626 		}
627 	    }
628 	}
629 
630       if (top_dog && top_dog->ncalls != 0 && top_time > 0.0)
631 	{
632 	  top_time /= hz;
633 
634 	  for (log_scale = 0; log_scale < ARRAY_SIZE (SItab); log_scale ++)
635 	    {
636 	      double scaled_value = SItab[log_scale].scale * top_time;
637 
638 	      if (scaled_value >= 1.0 && scaled_value < 1000.0)
639 		break;
640 	    }
641 	}
642     }
643 
644   /* For now, the dimension is always seconds.  In the future, we
645      may also want to support other (pseudo-)dimensions (such as
646      I-cache misses etc.).  */
647   print_header (SItab[log_scale].prefix);
648 
649   for (sym_index = 0; sym_index < symtab.len; ++sym_index)
650     {
651       addr = time_sorted_syms[sym_index]->addr;
652 
653       /* Print symbol if its in INCL_FLAT table or that table
654 	is empty and the symbol is not in EXCL_FLAT.  */
655       if (sym_lookup (&syms[INCL_FLAT], addr)
656 	  || (syms[INCL_FLAT].len == 0
657 	      && !sym_lookup (&syms[EXCL_FLAT], addr)))
658 	print_line (time_sorted_syms[sym_index], SItab[log_scale].scale);
659     }
660 
661   free (time_sorted_syms);
662 
663   if (print_descriptions && !bsd_style_output)
664     flat_blurb (stdout);
665 }
666 
667 int
668 hist_check_address (unsigned address)
669 {
670   unsigned i;
671 
672   for (i = 0; i < num_histograms; ++i)
673     if (histograms[i].lowpc <= address && address < histograms[i].highpc)
674       return 1;
675 
676   return 0;
677 }
678 
679 #if ! defined(min)
680 #define min(a,b) (((a)<(b)) ? (a) : (b))
681 #endif
682 #if ! defined(max)
683 #define max(a,b) (((a)>(b)) ? (a) : (b))
684 #endif
685 
686 void
687 hist_clip_symbol_address (bfd_vma *p_lowpc, bfd_vma *p_highpc)
688 {
689   unsigned i;
690   int found = 0;
691 
692   if (num_histograms == 0)
693     {
694       *p_highpc = *p_lowpc;
695       return;
696     }
697 
698   for (i = 0; i < num_histograms; ++i)
699     {
700       bfd_vma common_low, common_high;
701       common_low = max (histograms[i].lowpc, *p_lowpc);
702       common_high = min (histograms[i].highpc, *p_highpc);
703 
704       if (common_low < common_high)
705 	{
706 	  if (found)
707 	    {
708 	      fprintf (stderr,
709 		       _("%s: found a symbol that covers "
710 			 "several histogram records"),
711 			 whoami);
712 	      done (1);
713 	    }
714 
715 	  found = 1;
716 	  *p_lowpc = common_low;
717 	  *p_highpc = common_high;
718 	}
719     }
720 
721   if (!found)
722     *p_highpc = *p_lowpc;
723 }
724 
725 /* Find and return exising histogram record having the same lowpc and
726    highpc as passed via the parameters.  Return NULL if nothing is found.
727    The return value is valid until any new histogram is read.  */
728 static histogram *
729 find_histogram (bfd_vma lowpc, bfd_vma highpc)
730 {
731   unsigned i;
732   for (i = 0; i < num_histograms; ++i)
733     {
734       if (histograms[i].lowpc == lowpc && histograms[i].highpc == highpc)
735 	return &histograms[i];
736     }
737   return 0;
738 }
739 
740 /* Given a PC, return histogram record which address range include this PC.
741    Return NULL if there's no such record.  */
742 static histogram *
743 find_histogram_for_pc (bfd_vma pc)
744 {
745   unsigned i;
746   for (i = 0; i < num_histograms; ++i)
747     {
748       if (histograms[i].lowpc <= pc && pc < histograms[i].highpc)
749 	return &histograms[i];
750     }
751   return 0;
752 }
753