xref: /netbsd-src/external/gpl3/binutils.old/dist/gprof/hist.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
175fd0b74Schristos /* hist.c  -  Histogram related operations.
275fd0b74Schristos 
3*e992f068Schristos    Copyright (C) 1999-2022 Free Software Foundation, Inc.
475fd0b74Schristos 
575fd0b74Schristos    This file is part of GNU Binutils.
675fd0b74Schristos 
775fd0b74Schristos    This program is free software; you can redistribute it and/or modify
875fd0b74Schristos    it under the terms of the GNU General Public License as published by
975fd0b74Schristos    the Free Software Foundation; either version 3 of the License, or
1075fd0b74Schristos    (at your option) any later version.
1175fd0b74Schristos 
1275fd0b74Schristos    This program is distributed in the hope that it will be useful,
1375fd0b74Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1475fd0b74Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1575fd0b74Schristos    GNU General Public License for more details.
1675fd0b74Schristos 
1775fd0b74Schristos    You should have received a copy of the GNU General Public License
1875fd0b74Schristos    along with this program; if not, write to the Free Software
1975fd0b74Schristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
2075fd0b74Schristos    02110-1301, USA.  */
2175fd0b74Schristos 
2275fd0b74Schristos #include "gprof.h"
2375fd0b74Schristos #include "libiberty.h"
2475fd0b74Schristos #include "search_list.h"
2575fd0b74Schristos #include "source.h"
2675fd0b74Schristos #include "symtab.h"
2775fd0b74Schristos #include "corefile.h"
2875fd0b74Schristos #include "gmon_io.h"
2975fd0b74Schristos #include "gmon_out.h"
3075fd0b74Schristos #include "hist.h"
3175fd0b74Schristos #include "sym_ids.h"
3275fd0b74Schristos #include "utils.h"
3375fd0b74Schristos #include "math.h"
3475fd0b74Schristos #include "stdio.h"
3575fd0b74Schristos #include "stdlib.h"
3675fd0b74Schristos 
3775fd0b74Schristos #define UNITS_TO_CODE (offset_to_code / sizeof(UNIT))
3875fd0b74Schristos 
3975fd0b74Schristos static void scale_and_align_entries (void);
4075fd0b74Schristos static void print_header (int);
4175fd0b74Schristos static void print_line (Sym *, double);
42*e992f068Schristos static int cmp_time (const void *, const void *);
4375fd0b74Schristos 
4475fd0b74Schristos /* Declarations of automatically generated functions to output blurbs.  */
4575fd0b74Schristos extern void flat_blurb (FILE * fp);
4675fd0b74Schristos 
4775fd0b74Schristos static histogram *find_histogram (bfd_vma lowpc, bfd_vma highpc);
4875fd0b74Schristos static histogram *find_histogram_for_pc (bfd_vma pc);
4975fd0b74Schristos 
5075fd0b74Schristos histogram * histograms;
5175fd0b74Schristos unsigned num_histograms;
5275fd0b74Schristos double hist_scale;
5375fd0b74Schristos static char hist_dimension[16] = "seconds";
5475fd0b74Schristos static char hist_dimension_abbrev = 's';
5575fd0b74Schristos 
5675fd0b74Schristos static double accum_time;	/* Accumulated time so far for print_line(). */
5775fd0b74Schristos static double total_time;	/* Total time for all routines.  */
5875fd0b74Schristos 
5975fd0b74Schristos /* Table of SI prefixes for powers of 10 (used to automatically
6075fd0b74Schristos    scale some of the values in the flat profile).  */
6175fd0b74Schristos const struct
6275fd0b74Schristos   {
6375fd0b74Schristos     char prefix;
6475fd0b74Schristos     double scale;
6575fd0b74Schristos   }
6675fd0b74Schristos SItab[] =
6775fd0b74Schristos {
6875fd0b74Schristos   { 'T', 1e-12 },				/* tera */
6975fd0b74Schristos   { 'G', 1e-09 },				/* giga */
7075fd0b74Schristos   { 'M', 1e-06 },				/* mega */
7175fd0b74Schristos   { 'K', 1e-03 },				/* kilo */
7275fd0b74Schristos   { ' ', 1e-00 },
7375fd0b74Schristos   { 'm', 1e+03 },				/* milli */
7475fd0b74Schristos   { 'u', 1e+06 },				/* micro */
7575fd0b74Schristos   { 'n', 1e+09 },				/* nano */
7675fd0b74Schristos   { 'p', 1e+12 },				/* pico */
7775fd0b74Schristos   { 'f', 1e+15 },				/* femto */
7875fd0b74Schristos   { 'a', 1e+18 }				/* ato */
7975fd0b74Schristos };
8075fd0b74Schristos 
8175fd0b74Schristos /* Reads just the header part of histogram record into
8275fd0b74Schristos    *RECORD from IFP.  FILENAME is the name of IFP and
8375fd0b74Schristos    is provided for formatting error messages only.
8475fd0b74Schristos 
8575fd0b74Schristos    If FIRST is non-zero, sets global variables HZ, HIST_DIMENSION,
8675fd0b74Schristos    HIST_DIMENSION_ABBREV, HIST_SCALE.  If FIRST is zero, checks
8775fd0b74Schristos    that the new histogram is compatible with already-set values
8875fd0b74Schristos    of those variables and emits an error if that's not so.  */
8975fd0b74Schristos static void
read_histogram_header(histogram * record,FILE * ifp,const char * filename,int first)9075fd0b74Schristos read_histogram_header (histogram *record,
9175fd0b74Schristos 		       FILE *ifp, const char *filename,
9275fd0b74Schristos 		       int first)
9375fd0b74Schristos {
9475fd0b74Schristos   unsigned int profrate;
9575fd0b74Schristos   char n_hist_dimension[15];
9675fd0b74Schristos   char n_hist_dimension_abbrev;
9775fd0b74Schristos   double n_hist_scale;
9875fd0b74Schristos 
9975fd0b74Schristos   if (gmon_io_read_vma (ifp, &record->lowpc)
10075fd0b74Schristos       || gmon_io_read_vma (ifp, &record->highpc)
10175fd0b74Schristos       || gmon_io_read_32 (ifp, &record->num_bins)
10275fd0b74Schristos       || gmon_io_read_32 (ifp, &profrate)
10375fd0b74Schristos       || gmon_io_read (ifp, n_hist_dimension, 15)
10475fd0b74Schristos       || gmon_io_read (ifp, &n_hist_dimension_abbrev, 1))
10575fd0b74Schristos     {
10675fd0b74Schristos       fprintf (stderr, _("%s: %s: unexpected end of file\n"),
10775fd0b74Schristos 	       whoami, filename);
10875fd0b74Schristos 
10975fd0b74Schristos       done (1);
11075fd0b74Schristos     }
11175fd0b74Schristos 
11275fd0b74Schristos   n_hist_scale = (double)((record->highpc - record->lowpc) / sizeof (UNIT))
11375fd0b74Schristos     / record->num_bins;
11475fd0b74Schristos 
11575fd0b74Schristos   if (first)
11675fd0b74Schristos     {
11775fd0b74Schristos       /* We don't try to veryfy profrate is the same for all histogram
11875fd0b74Schristos 	 records.  If we have two histogram records for the same
11975fd0b74Schristos 	 address range and profiling samples is done as often
12075fd0b74Schristos 	 as possible as opposed on timer, then the actual profrate will
12175fd0b74Schristos 	 be slightly different.  Most of the time the difference does not
12275fd0b74Schristos 	 matter and insisting that profiling rate is exactly the same
12375fd0b74Schristos 	 will only create inconvenient.  */
12475fd0b74Schristos       hz = profrate;
12575fd0b74Schristos       memcpy (hist_dimension, n_hist_dimension, 15);
12675fd0b74Schristos       hist_dimension_abbrev = n_hist_dimension_abbrev;
12775fd0b74Schristos       hist_scale = n_hist_scale;
12875fd0b74Schristos     }
12975fd0b74Schristos   else
13075fd0b74Schristos     {
13175fd0b74Schristos       if (strncmp (n_hist_dimension, hist_dimension, 15) != 0)
13275fd0b74Schristos 	{
13375fd0b74Schristos 	  fprintf (stderr,
13475fd0b74Schristos 		   _("%s: dimension unit changed between histogram records\n"
13575fd0b74Schristos 		     "%s: from '%s'\n"
13675fd0b74Schristos 		     "%s: to '%s'\n"),
13775fd0b74Schristos 		   whoami, whoami, hist_dimension, whoami, n_hist_dimension);
13875fd0b74Schristos 	  done (1);
13975fd0b74Schristos 	}
14075fd0b74Schristos 
14175fd0b74Schristos       if (n_hist_dimension_abbrev != hist_dimension_abbrev)
14275fd0b74Schristos 	{
14375fd0b74Schristos 	  fprintf (stderr,
14475fd0b74Schristos 		   _("%s: dimension abbreviation changed between histogram records\n"
14575fd0b74Schristos 		     "%s: from '%c'\n"
14675fd0b74Schristos 		     "%s: to '%c'\n"),
14775fd0b74Schristos 		   whoami, whoami, hist_dimension_abbrev, whoami, n_hist_dimension_abbrev);
14875fd0b74Schristos 	  done (1);
14975fd0b74Schristos 	}
15075fd0b74Schristos 
15175fd0b74Schristos       /* The only reason we require the same scale for histograms is that
15275fd0b74Schristos 	 there's code (notably printing code), that prints units,
15375fd0b74Schristos 	 and it would be very confusing to have one unit mean different
15475fd0b74Schristos 	 things for different functions.  */
15575fd0b74Schristos       if (fabs (hist_scale - n_hist_scale) > 0.000001)
15675fd0b74Schristos 	{
15775fd0b74Schristos 	  fprintf (stderr,
15875fd0b74Schristos 		   _("%s: different scales in histogram records"),
15975fd0b74Schristos 		   whoami);
16075fd0b74Schristos 	  done (1);
16175fd0b74Schristos 	}
16275fd0b74Schristos     }
16375fd0b74Schristos }
16475fd0b74Schristos 
16575fd0b74Schristos /* Read the histogram from file IFP.  FILENAME is the name of IFP and
16675fd0b74Schristos    is provided for formatting error messages only.  */
16775fd0b74Schristos 
16875fd0b74Schristos void
hist_read_rec(FILE * ifp,const char * filename)16975fd0b74Schristos hist_read_rec (FILE * ifp, const char *filename)
17075fd0b74Schristos {
17175fd0b74Schristos   bfd_vma lowpc, highpc;
17275fd0b74Schristos   histogram n_record;
17375fd0b74Schristos   histogram *record, *existing_record;
17475fd0b74Schristos   unsigned i;
17575fd0b74Schristos 
17675fd0b74Schristos   /* 1. Read the header and see if there's existing record for the
17775fd0b74Schristos      same address range and that there are no overlapping records.  */
17875fd0b74Schristos   read_histogram_header (&n_record, ifp, filename, num_histograms == 0);
17975fd0b74Schristos 
18075fd0b74Schristos   existing_record = find_histogram (n_record.lowpc, n_record.highpc);
18175fd0b74Schristos   if (existing_record)
18275fd0b74Schristos     {
18375fd0b74Schristos       record = existing_record;
18475fd0b74Schristos     }
18575fd0b74Schristos   else
18675fd0b74Schristos     {
18775fd0b74Schristos       /* If this record overlaps, but does not completely match an existing
18875fd0b74Schristos 	 record, it's an error.  */
18975fd0b74Schristos       lowpc = n_record.lowpc;
19075fd0b74Schristos       highpc = n_record.highpc;
19175fd0b74Schristos       hist_clip_symbol_address (&lowpc, &highpc);
19275fd0b74Schristos       if (lowpc != highpc)
19375fd0b74Schristos 	{
19475fd0b74Schristos 	  fprintf (stderr,
19575fd0b74Schristos 		   _("%s: overlapping histogram records\n"),
19675fd0b74Schristos 		   whoami);
19775fd0b74Schristos 	  done (1);
19875fd0b74Schristos 	}
19975fd0b74Schristos 
20075fd0b74Schristos       /* This is new record.  Add it to global array and allocate space for
20175fd0b74Schristos 	 the samples.  */
20275fd0b74Schristos       histograms = (struct histogram *)
20375fd0b74Schristos           xrealloc (histograms, sizeof (histogram) * (num_histograms + 1));
20475fd0b74Schristos       memcpy (histograms + num_histograms,
20575fd0b74Schristos 	      &n_record, sizeof (histogram));
20675fd0b74Schristos       record = &histograms[num_histograms];
20775fd0b74Schristos       ++num_histograms;
20875fd0b74Schristos 
20975fd0b74Schristos       record->sample = (int *) xmalloc (record->num_bins
21075fd0b74Schristos 					* sizeof (record->sample[0]));
21175fd0b74Schristos       memset (record->sample, 0, record->num_bins * sizeof (record->sample[0]));
21275fd0b74Schristos     }
21375fd0b74Schristos 
21475fd0b74Schristos   /* 2. We have either a new record (with zeroed histogram data), or an existing
21575fd0b74Schristos      record with some data in the histogram already.  Read new data into the
21675fd0b74Schristos      record, adding hit counts.  */
21775fd0b74Schristos 
21875fd0b74Schristos   DBG (SAMPLEDEBUG,
21975fd0b74Schristos        printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %u\n",
22075fd0b74Schristos 	       (unsigned long) record->lowpc, (unsigned long) record->highpc,
22175fd0b74Schristos                record->num_bins));
22275fd0b74Schristos 
22375fd0b74Schristos   for (i = 0; i < record->num_bins; ++i)
22475fd0b74Schristos     {
22575fd0b74Schristos       UNIT count;
22675fd0b74Schristos       if (fread (&count[0], sizeof (count), 1, ifp) != 1)
22775fd0b74Schristos 	{
22875fd0b74Schristos 	  fprintf (stderr,
22975fd0b74Schristos 		  _("%s: %s: unexpected EOF after reading %u of %u samples\n"),
23075fd0b74Schristos 		   whoami, filename, i, record->num_bins);
23175fd0b74Schristos 	  done (1);
23275fd0b74Schristos 	}
23375fd0b74Schristos       record->sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]);
23475fd0b74Schristos       DBG (SAMPLEDEBUG,
23575fd0b74Schristos 	   printf ("[hist_read_rec] 0x%lx: %u\n",
23675fd0b74Schristos 		   (unsigned long) (record->lowpc
23775fd0b74Schristos                                     + i * (record->highpc - record->lowpc)
23875fd0b74Schristos                                     / record->num_bins),
23975fd0b74Schristos 		   record->sample[i]));
24075fd0b74Schristos     }
24175fd0b74Schristos }
24275fd0b74Schristos 
24375fd0b74Schristos 
24475fd0b74Schristos /* Write all execution histograms file OFP.  FILENAME is the name
24575fd0b74Schristos    of OFP and is provided for formatting error-messages only.  */
24675fd0b74Schristos 
24775fd0b74Schristos void
hist_write_hist(FILE * ofp,const char * filename)24875fd0b74Schristos hist_write_hist (FILE * ofp, const char *filename)
24975fd0b74Schristos {
25075fd0b74Schristos   UNIT count;
25175fd0b74Schristos   unsigned int i, r;
25275fd0b74Schristos 
25375fd0b74Schristos   for (r = 0; r < num_histograms; ++r)
25475fd0b74Schristos     {
25575fd0b74Schristos       histogram *record = &histograms[r];
25675fd0b74Schristos 
25775fd0b74Schristos       /* Write header.  */
25875fd0b74Schristos 
25975fd0b74Schristos       if (gmon_io_write_8 (ofp, GMON_TAG_TIME_HIST)
26075fd0b74Schristos 	  || gmon_io_write_vma (ofp, record->lowpc)
26175fd0b74Schristos 	  || gmon_io_write_vma (ofp, record->highpc)
26275fd0b74Schristos 	  || gmon_io_write_32 (ofp, record->num_bins)
26375fd0b74Schristos 	  || gmon_io_write_32 (ofp, hz)
26475fd0b74Schristos 	  || gmon_io_write (ofp, hist_dimension, 15)
26575fd0b74Schristos 	  || gmon_io_write (ofp, &hist_dimension_abbrev, 1))
26675fd0b74Schristos 	{
26775fd0b74Schristos 	  perror (filename);
26875fd0b74Schristos 	  done (1);
26975fd0b74Schristos 	}
27075fd0b74Schristos 
27175fd0b74Schristos       for (i = 0; i < record->num_bins; ++i)
27275fd0b74Schristos 	{
27375fd0b74Schristos 	  bfd_put_16 (core_bfd, (bfd_vma) record->sample[i], (bfd_byte *) &count[0]);
27475fd0b74Schristos 
27575fd0b74Schristos 	  if (fwrite (&count[0], sizeof (count), 1, ofp) != 1)
27675fd0b74Schristos 	    {
27775fd0b74Schristos 	      perror (filename);
27875fd0b74Schristos 	      done (1);
27975fd0b74Schristos 	    }
28075fd0b74Schristos 	}
28175fd0b74Schristos     }
28275fd0b74Schristos }
28375fd0b74Schristos 
28475fd0b74Schristos /* Calculate scaled entry point addresses (to save time in
28575fd0b74Schristos    hist_assign_samples), and, on architectures that have procedure
28675fd0b74Schristos    entry masks at the start of a function, possibly push the scaled
28775fd0b74Schristos    entry points over the procedure entry mask, if it turns out that
28875fd0b74Schristos    the entry point is in one bin and the code for a routine is in the
28975fd0b74Schristos    next bin.  */
29075fd0b74Schristos 
29175fd0b74Schristos static void
scale_and_align_entries(void)29275fd0b74Schristos scale_and_align_entries (void)
29375fd0b74Schristos {
29475fd0b74Schristos   Sym *sym;
29575fd0b74Schristos   bfd_vma bin_of_entry;
29675fd0b74Schristos   bfd_vma bin_of_code;
29775fd0b74Schristos 
29875fd0b74Schristos   for (sym = symtab.base; sym < symtab.limit; sym++)
29975fd0b74Schristos     {
30075fd0b74Schristos       histogram *r = find_histogram_for_pc (sym->addr);
30175fd0b74Schristos 
30275fd0b74Schristos       sym->hist.scaled_addr = sym->addr / sizeof (UNIT);
30375fd0b74Schristos 
30475fd0b74Schristos       if (r)
30575fd0b74Schristos 	{
30675fd0b74Schristos 	  bin_of_entry = (sym->hist.scaled_addr - r->lowpc) / hist_scale;
30775fd0b74Schristos 	  bin_of_code = ((sym->hist.scaled_addr + UNITS_TO_CODE - r->lowpc)
30875fd0b74Schristos 		     / hist_scale);
30975fd0b74Schristos 	  if (bin_of_entry < bin_of_code)
31075fd0b74Schristos 	    {
31175fd0b74Schristos 	      DBG (SAMPLEDEBUG,
31275fd0b74Schristos 		   printf ("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
31375fd0b74Schristos 			   (unsigned long) sym->hist.scaled_addr,
31475fd0b74Schristos 			   (unsigned long) (sym->hist.scaled_addr
31575fd0b74Schristos 					    + UNITS_TO_CODE)));
31675fd0b74Schristos 	      sym->hist.scaled_addr += UNITS_TO_CODE;
31775fd0b74Schristos 	    }
31875fd0b74Schristos 	}
31975fd0b74Schristos     }
32075fd0b74Schristos }
32175fd0b74Schristos 
32275fd0b74Schristos 
32375fd0b74Schristos /* Assign samples to the symbol to which they belong.
32475fd0b74Schristos 
32575fd0b74Schristos    Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
32675fd0b74Schristos    which may overlap one more symbol address ranges.  If a symbol
32775fd0b74Schristos    overlaps with the bin's address range by O percent, then O percent
32875fd0b74Schristos    of the bin's count is credited to that symbol.
32975fd0b74Schristos 
33075fd0b74Schristos    There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
33175fd0b74Schristos    with respect to the symbol's address range [SYM_LOW_PC,
33275fd0b74Schristos    SYM_HIGH_PC) as shown in the following diagram.  OVERLAP computes
33375fd0b74Schristos    the distance (in UNITs) between the arrows, the fraction of the
33475fd0b74Schristos    sample that is to be credited to the symbol which starts at
33575fd0b74Schristos    SYM_LOW_PC.
33675fd0b74Schristos 
33775fd0b74Schristos 	  sym_low_pc                                      sym_high_pc
33875fd0b74Schristos 	       |                                               |
33975fd0b74Schristos 	       v                                               v
34075fd0b74Schristos 
34175fd0b74Schristos 	       +-----------------------------------------------+
34275fd0b74Schristos 	       |                                               |
34375fd0b74Schristos 	  |  ->|    |<-         ->|         |<-         ->|    |<-  |
34475fd0b74Schristos 	  |         |             |         |             |         |
34575fd0b74Schristos 	  +---------+             +---------+             +---------+
34675fd0b74Schristos 
34775fd0b74Schristos 	  ^         ^             ^         ^             ^         ^
34875fd0b74Schristos 	  |         |             |         |             |         |
34975fd0b74Schristos      bin_low_pc bin_high_pc  bin_low_pc bin_high_pc  bin_low_pc bin_high_pc
35075fd0b74Schristos 
35175fd0b74Schristos    For the VAX we assert that samples will never fall in the first two
35275fd0b74Schristos    bytes of any routine, since that is the entry mask, thus we call
35375fd0b74Schristos    scale_and_align_entries() to adjust the entry points if the entry
35475fd0b74Schristos    mask falls in one bin but the code for the routine doesn't start
35575fd0b74Schristos    until the next bin.  In conjunction with the alignment of routine
35675fd0b74Schristos    addresses, this should allow us to have only one sample for every
35775fd0b74Schristos    four bytes of text space and never have any overlap (the two end
35875fd0b74Schristos    cases, above).  */
35975fd0b74Schristos 
36075fd0b74Schristos static void
hist_assign_samples_1(histogram * r)36175fd0b74Schristos hist_assign_samples_1 (histogram *r)
36275fd0b74Schristos {
36375fd0b74Schristos   bfd_vma bin_low_pc, bin_high_pc;
36475fd0b74Schristos   bfd_vma sym_low_pc, sym_high_pc;
36575fd0b74Schristos   bfd_vma overlap, addr;
36675fd0b74Schristos   unsigned int bin_count;
36775fd0b74Schristos   unsigned int i, j, k;
36875fd0b74Schristos   double count_time, credit;
36975fd0b74Schristos 
37075fd0b74Schristos   bfd_vma lowpc = r->lowpc / sizeof (UNIT);
37175fd0b74Schristos 
37275fd0b74Schristos   /* Iterate over all sample bins.  */
37375fd0b74Schristos   for (i = 0, k = 1; i < r->num_bins; ++i)
37475fd0b74Schristos     {
37575fd0b74Schristos       bin_count = r->sample[i];
37675fd0b74Schristos       if (! bin_count)
37775fd0b74Schristos 	continue;
37875fd0b74Schristos 
37975fd0b74Schristos       bin_low_pc = lowpc + (bfd_vma) (hist_scale * i);
38075fd0b74Schristos       bin_high_pc = lowpc + (bfd_vma) (hist_scale * (i + 1));
38175fd0b74Schristos       count_time = bin_count;
38275fd0b74Schristos 
38375fd0b74Schristos       DBG (SAMPLEDEBUG,
38475fd0b74Schristos 	   printf (
38575fd0b74Schristos       "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%u\n",
38675fd0b74Schristos 		    (unsigned long) (sizeof (UNIT) * bin_low_pc),
38775fd0b74Schristos 		    (unsigned long) (sizeof (UNIT) * bin_high_pc),
38875fd0b74Schristos 		    bin_count));
38975fd0b74Schristos       total_time += count_time;
39075fd0b74Schristos 
39175fd0b74Schristos       /* Credit all symbols that are covered by bin I.
39275fd0b74Schristos 
39375fd0b74Schristos          PR gprof/13325: Make sure that K does not get decremented
39475fd0b74Schristos 	 and J will never be less than 0.  */
39575fd0b74Schristos       for (j = k - 1; j < symtab.len; k = ++j)
39675fd0b74Schristos 	{
39775fd0b74Schristos 	  sym_low_pc = symtab.base[j].hist.scaled_addr;
39875fd0b74Schristos 	  sym_high_pc = symtab.base[j + 1].hist.scaled_addr;
39975fd0b74Schristos 
40075fd0b74Schristos 	  /* If high end of bin is below entry address,
40175fd0b74Schristos 	     go for next bin.  */
40275fd0b74Schristos 	  if (bin_high_pc < sym_low_pc)
40375fd0b74Schristos 	    break;
40475fd0b74Schristos 
40575fd0b74Schristos 	  /* If low end of bin is above high end of symbol,
40675fd0b74Schristos 	     go for next symbol.  */
40775fd0b74Schristos 	  if (bin_low_pc >= sym_high_pc)
40875fd0b74Schristos 	    continue;
40975fd0b74Schristos 
41075fd0b74Schristos 	  overlap =
41175fd0b74Schristos 	    MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc);
41275fd0b74Schristos 	  if (overlap > 0)
41375fd0b74Schristos 	    {
41475fd0b74Schristos 	      DBG (SAMPLEDEBUG,
41575fd0b74Schristos 		   printf (
41675fd0b74Schristos 	       "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
41775fd0b74Schristos 			   (unsigned long) symtab.base[j].addr,
41875fd0b74Schristos 			   (unsigned long) (sizeof (UNIT) * sym_high_pc),
41975fd0b74Schristos 			   symtab.base[j].name, overlap * count_time / hist_scale,
42075fd0b74Schristos 			   (long) overlap));
42175fd0b74Schristos 
42275fd0b74Schristos 	      addr = symtab.base[j].addr;
42375fd0b74Schristos 	      credit = overlap * count_time / hist_scale;
42475fd0b74Schristos 
42575fd0b74Schristos 	      /* Credit symbol if it appears in INCL_FLAT or that
42675fd0b74Schristos 		 table is empty and it does not appear it in
42775fd0b74Schristos 		 EXCL_FLAT.  */
42875fd0b74Schristos 	      if (sym_lookup (&syms[INCL_FLAT], addr)
42975fd0b74Schristos 		  || (syms[INCL_FLAT].len == 0
43075fd0b74Schristos 		      && !sym_lookup (&syms[EXCL_FLAT], addr)))
43175fd0b74Schristos 		{
43275fd0b74Schristos 		  symtab.base[j].hist.time += credit;
43375fd0b74Schristos 		}
43475fd0b74Schristos 	      else
43575fd0b74Schristos 		{
43675fd0b74Schristos 		  total_time -= credit;
43775fd0b74Schristos 		}
43875fd0b74Schristos 	    }
43975fd0b74Schristos 	}
44075fd0b74Schristos     }
44175fd0b74Schristos 
44275fd0b74Schristos   DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n",
44375fd0b74Schristos 			    total_time));
44475fd0b74Schristos }
44575fd0b74Schristos 
44675fd0b74Schristos /* Calls 'hist_assign_sampes_1' for all histogram records read so far. */
44775fd0b74Schristos void
hist_assign_samples(void)44875fd0b74Schristos hist_assign_samples (void)
44975fd0b74Schristos {
45075fd0b74Schristos   unsigned i;
45175fd0b74Schristos 
45275fd0b74Schristos   scale_and_align_entries ();
45375fd0b74Schristos 
45475fd0b74Schristos   for (i = 0; i < num_histograms; ++i)
45575fd0b74Schristos     hist_assign_samples_1 (&histograms[i]);
45675fd0b74Schristos 
45775fd0b74Schristos }
45875fd0b74Schristos 
45975fd0b74Schristos /* Print header for flag histogram profile.  */
46075fd0b74Schristos 
46175fd0b74Schristos static void
print_header(int prefix)46275fd0b74Schristos print_header (int prefix)
46375fd0b74Schristos {
46475fd0b74Schristos   char unit[64];
46575fd0b74Schristos 
46675fd0b74Schristos   sprintf (unit, _("%c%c/call"), prefix, hist_dimension_abbrev);
46775fd0b74Schristos 
46875fd0b74Schristos   if (bsd_style_output)
46975fd0b74Schristos     {
47075fd0b74Schristos       printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
47175fd0b74Schristos 	      (long) hist_scale * (long) sizeof (UNIT));
47275fd0b74Schristos       if (total_time > 0.0)
47375fd0b74Schristos 	{
47475fd0b74Schristos 	  printf (_(" for %.2f%% of %.2f %s\n\n"),
47575fd0b74Schristos 		  100.0 / total_time, total_time / hz, hist_dimension);
47675fd0b74Schristos 	}
47775fd0b74Schristos     }
47875fd0b74Schristos   else
47975fd0b74Schristos     {
48075fd0b74Schristos       printf (_("\nEach sample counts as %g %s.\n"), 1.0 / hz, hist_dimension);
48175fd0b74Schristos     }
48275fd0b74Schristos 
48375fd0b74Schristos   if (total_time <= 0.0)
48475fd0b74Schristos     {
48575fd0b74Schristos       printf (_(" no time accumulated\n\n"));
48675fd0b74Schristos 
48775fd0b74Schristos       /* This doesn't hurt since all the numerators will be zero.  */
48875fd0b74Schristos       total_time = 1.0;
48975fd0b74Schristos     }
49075fd0b74Schristos 
49175fd0b74Schristos   printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
49275fd0b74Schristos 	  "%  ", _("cumulative"), _("self  "), "", _("self  "), _("total "),
49375fd0b74Schristos 	  "");
49475fd0b74Schristos   printf ("%5.5s %9.9s  %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
49575fd0b74Schristos 	  _("time"), hist_dimension, hist_dimension, _("calls"), unit, unit,
49675fd0b74Schristos 	  _("name"));
49775fd0b74Schristos }
49875fd0b74Schristos 
49975fd0b74Schristos 
50075fd0b74Schristos static void
print_line(Sym * sym,double scale)50175fd0b74Schristos print_line (Sym *sym, double scale)
50275fd0b74Schristos {
50375fd0b74Schristos   if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0)
50475fd0b74Schristos     return;
50575fd0b74Schristos 
50675fd0b74Schristos   accum_time += sym->hist.time;
50775fd0b74Schristos 
50875fd0b74Schristos   if (bsd_style_output)
50975fd0b74Schristos     printf ("%5.1f %10.2f %8.2f",
51075fd0b74Schristos 	    total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
51175fd0b74Schristos 	    accum_time / hz, sym->hist.time / hz);
51275fd0b74Schristos   else
51375fd0b74Schristos     printf ("%6.2f %9.2f %8.2f",
51475fd0b74Schristos 	    total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
51575fd0b74Schristos 	    accum_time / hz, sym->hist.time / hz);
51675fd0b74Schristos 
51775fd0b74Schristos   if (sym->ncalls != 0)
51875fd0b74Schristos     printf (" %8lu %8.2f %8.2f  ",
51975fd0b74Schristos 	    sym->ncalls, scale * sym->hist.time / hz / sym->ncalls,
52075fd0b74Schristos 	    scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls);
52175fd0b74Schristos   else
52275fd0b74Schristos     printf (" %8.8s %8.8s %8.8s  ", "", "", "");
52375fd0b74Schristos 
52475fd0b74Schristos   if (bsd_style_output)
52575fd0b74Schristos     print_name (sym);
52675fd0b74Schristos   else
52775fd0b74Schristos     print_name_only (sym);
52875fd0b74Schristos 
52975fd0b74Schristos   printf ("\n");
53075fd0b74Schristos }
53175fd0b74Schristos 
53275fd0b74Schristos 
53375fd0b74Schristos /* Compare LP and RP.  The primary comparison key is execution time,
53475fd0b74Schristos    the secondary is number of invocation, and the tertiary is the
53575fd0b74Schristos    lexicographic order of the function names.  */
53675fd0b74Schristos 
53775fd0b74Schristos static int
cmp_time(const void * lp,const void * rp)538*e992f068Schristos cmp_time (const void *lp, const void *rp)
53975fd0b74Schristos {
54075fd0b74Schristos   const Sym *left = *(const Sym **) lp;
54175fd0b74Schristos   const Sym *right = *(const Sym **) rp;
54275fd0b74Schristos   double time_diff;
54375fd0b74Schristos 
54475fd0b74Schristos   time_diff = right->hist.time - left->hist.time;
54575fd0b74Schristos 
54675fd0b74Schristos   if (time_diff > 0.0)
54775fd0b74Schristos     return 1;
54875fd0b74Schristos 
54975fd0b74Schristos   if (time_diff < 0.0)
55075fd0b74Schristos     return -1;
55175fd0b74Schristos 
55275fd0b74Schristos   if (right->ncalls > left->ncalls)
55375fd0b74Schristos     return 1;
55475fd0b74Schristos 
55575fd0b74Schristos   if (right->ncalls < left->ncalls)
55675fd0b74Schristos     return -1;
55775fd0b74Schristos 
55875fd0b74Schristos   return strcmp (left->name, right->name);
55975fd0b74Schristos }
56075fd0b74Schristos 
56175fd0b74Schristos 
56275fd0b74Schristos /* Print the flat histogram profile.  */
56375fd0b74Schristos 
56475fd0b74Schristos void
hist_print(void)56575fd0b74Schristos hist_print (void)
56675fd0b74Schristos {
56775fd0b74Schristos   Sym **time_sorted_syms, *top_dog, *sym;
56875fd0b74Schristos   unsigned int sym_index;
56975fd0b74Schristos   unsigned log_scale;
57075fd0b74Schristos   double top_time;
57175fd0b74Schristos   bfd_vma addr;
57275fd0b74Schristos 
57375fd0b74Schristos   if (first_output)
574*e992f068Schristos     first_output = false;
57575fd0b74Schristos   else
57675fd0b74Schristos     printf ("\f\n");
57775fd0b74Schristos 
57875fd0b74Schristos   accum_time = 0.0;
57975fd0b74Schristos 
58075fd0b74Schristos   if (bsd_style_output)
58175fd0b74Schristos     {
58275fd0b74Schristos       if (print_descriptions)
58375fd0b74Schristos 	{
58475fd0b74Schristos 	  printf (_("\n\n\nflat profile:\n"));
58575fd0b74Schristos 	  flat_blurb (stdout);
58675fd0b74Schristos 	}
58775fd0b74Schristos     }
58875fd0b74Schristos   else
58975fd0b74Schristos     {
59075fd0b74Schristos       printf (_("Flat profile:\n"));
59175fd0b74Schristos     }
59275fd0b74Schristos 
59375fd0b74Schristos   /* Sort the symbol table by time (call-count and name as secondary
59475fd0b74Schristos      and tertiary keys).  */
59575fd0b74Schristos   time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
59675fd0b74Schristos 
59775fd0b74Schristos   for (sym_index = 0; sym_index < symtab.len; ++sym_index)
59875fd0b74Schristos     time_sorted_syms[sym_index] = &symtab.base[sym_index];
59975fd0b74Schristos 
60075fd0b74Schristos   qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
60175fd0b74Schristos 
60275fd0b74Schristos   if (bsd_style_output)
60375fd0b74Schristos     {
60475fd0b74Schristos       log_scale = 5;		/* Milli-seconds is BSD-default.  */
60575fd0b74Schristos     }
60675fd0b74Schristos   else
60775fd0b74Schristos     {
60875fd0b74Schristos       /* Search for symbol with highest per-call
60975fd0b74Schristos 	 execution time and scale accordingly.  */
61075fd0b74Schristos       log_scale = 0;
61175fd0b74Schristos       top_dog = 0;
61275fd0b74Schristos       top_time = 0.0;
61375fd0b74Schristos 
61475fd0b74Schristos       for (sym_index = 0; sym_index < symtab.len; ++sym_index)
61575fd0b74Schristos 	{
61675fd0b74Schristos 	  sym = time_sorted_syms[sym_index];
61775fd0b74Schristos 
61875fd0b74Schristos 	  if (sym->ncalls != 0)
61975fd0b74Schristos 	    {
62075fd0b74Schristos 	      double call_time;
62175fd0b74Schristos 
62275fd0b74Schristos 	      call_time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
62375fd0b74Schristos 
62475fd0b74Schristos 	      if (call_time > top_time)
62575fd0b74Schristos 		{
62675fd0b74Schristos 		  top_dog = sym;
62775fd0b74Schristos 		  top_time = call_time;
62875fd0b74Schristos 		}
62975fd0b74Schristos 	    }
63075fd0b74Schristos 	}
63175fd0b74Schristos 
63275fd0b74Schristos       if (top_dog && top_dog->ncalls != 0 && top_time > 0.0)
63375fd0b74Schristos 	{
63475fd0b74Schristos 	  top_time /= hz;
63575fd0b74Schristos 
63675fd0b74Schristos 	  for (log_scale = 0; log_scale < ARRAY_SIZE (SItab); log_scale ++)
63775fd0b74Schristos 	    {
63875fd0b74Schristos 	      double scaled_value = SItab[log_scale].scale * top_time;
63975fd0b74Schristos 
64075fd0b74Schristos 	      if (scaled_value >= 1.0 && scaled_value < 1000.0)
64175fd0b74Schristos 		break;
64275fd0b74Schristos 	    }
64375fd0b74Schristos 	}
64475fd0b74Schristos     }
64575fd0b74Schristos 
64675fd0b74Schristos   /* For now, the dimension is always seconds.  In the future, we
64775fd0b74Schristos      may also want to support other (pseudo-)dimensions (such as
64875fd0b74Schristos      I-cache misses etc.).  */
64975fd0b74Schristos   print_header (SItab[log_scale].prefix);
65075fd0b74Schristos 
65175fd0b74Schristos   for (sym_index = 0; sym_index < symtab.len; ++sym_index)
65275fd0b74Schristos     {
65375fd0b74Schristos       addr = time_sorted_syms[sym_index]->addr;
65475fd0b74Schristos 
65575fd0b74Schristos       /* Print symbol if its in INCL_FLAT table or that table
65675fd0b74Schristos 	is empty and the symbol is not in EXCL_FLAT.  */
65775fd0b74Schristos       if (sym_lookup (&syms[INCL_FLAT], addr)
65875fd0b74Schristos 	  || (syms[INCL_FLAT].len == 0
65975fd0b74Schristos 	      && !sym_lookup (&syms[EXCL_FLAT], addr)))
66075fd0b74Schristos 	print_line (time_sorted_syms[sym_index], SItab[log_scale].scale);
66175fd0b74Schristos     }
66275fd0b74Schristos 
66375fd0b74Schristos   free (time_sorted_syms);
66475fd0b74Schristos 
66575fd0b74Schristos   if (print_descriptions && !bsd_style_output)
66675fd0b74Schristos     flat_blurb (stdout);
66775fd0b74Schristos }
66875fd0b74Schristos 
66975fd0b74Schristos int
hist_check_address(unsigned address)67075fd0b74Schristos hist_check_address (unsigned address)
67175fd0b74Schristos {
67275fd0b74Schristos   unsigned i;
67375fd0b74Schristos 
67475fd0b74Schristos   for (i = 0; i < num_histograms; ++i)
67575fd0b74Schristos     if (histograms[i].lowpc <= address && address < histograms[i].highpc)
67675fd0b74Schristos       return 1;
67775fd0b74Schristos 
67875fd0b74Schristos   return 0;
67975fd0b74Schristos }
68075fd0b74Schristos 
68175fd0b74Schristos #if ! defined(min)
68275fd0b74Schristos #define min(a,b) (((a)<(b)) ? (a) : (b))
68375fd0b74Schristos #endif
68475fd0b74Schristos #if ! defined(max)
68575fd0b74Schristos #define max(a,b) (((a)>(b)) ? (a) : (b))
68675fd0b74Schristos #endif
68775fd0b74Schristos 
68875fd0b74Schristos void
hist_clip_symbol_address(bfd_vma * p_lowpc,bfd_vma * p_highpc)68975fd0b74Schristos hist_clip_symbol_address (bfd_vma *p_lowpc, bfd_vma *p_highpc)
69075fd0b74Schristos {
69175fd0b74Schristos   unsigned i;
69275fd0b74Schristos   int found = 0;
69375fd0b74Schristos 
69475fd0b74Schristos   if (num_histograms == 0)
69575fd0b74Schristos     {
69675fd0b74Schristos       *p_highpc = *p_lowpc;
69775fd0b74Schristos       return;
69875fd0b74Schristos     }
69975fd0b74Schristos 
70075fd0b74Schristos   for (i = 0; i < num_histograms; ++i)
70175fd0b74Schristos     {
70275fd0b74Schristos       bfd_vma common_low, common_high;
70375fd0b74Schristos       common_low = max (histograms[i].lowpc, *p_lowpc);
70475fd0b74Schristos       common_high = min (histograms[i].highpc, *p_highpc);
70575fd0b74Schristos 
70675fd0b74Schristos       if (common_low < common_high)
70775fd0b74Schristos 	{
70875fd0b74Schristos 	  if (found)
70975fd0b74Schristos 	    {
71075fd0b74Schristos 	      fprintf (stderr,
71175fd0b74Schristos 		       _("%s: found a symbol that covers "
71275fd0b74Schristos 			 "several histogram records"),
71375fd0b74Schristos 			 whoami);
71475fd0b74Schristos 	      done (1);
71575fd0b74Schristos 	    }
71675fd0b74Schristos 
71775fd0b74Schristos 	  found = 1;
71875fd0b74Schristos 	  *p_lowpc = common_low;
71975fd0b74Schristos 	  *p_highpc = common_high;
72075fd0b74Schristos 	}
72175fd0b74Schristos     }
72275fd0b74Schristos 
72375fd0b74Schristos   if (!found)
72475fd0b74Schristos     *p_highpc = *p_lowpc;
72575fd0b74Schristos }
72675fd0b74Schristos 
72775fd0b74Schristos /* Find and return exising histogram record having the same lowpc and
72875fd0b74Schristos    highpc as passed via the parameters.  Return NULL if nothing is found.
72975fd0b74Schristos    The return value is valid until any new histogram is read.  */
73075fd0b74Schristos static histogram *
find_histogram(bfd_vma lowpc,bfd_vma highpc)73175fd0b74Schristos find_histogram (bfd_vma lowpc, bfd_vma highpc)
73275fd0b74Schristos {
73375fd0b74Schristos   unsigned i;
73475fd0b74Schristos   for (i = 0; i < num_histograms; ++i)
73575fd0b74Schristos     {
73675fd0b74Schristos       if (histograms[i].lowpc == lowpc && histograms[i].highpc == highpc)
73775fd0b74Schristos 	return &histograms[i];
73875fd0b74Schristos     }
73975fd0b74Schristos   return 0;
74075fd0b74Schristos }
74175fd0b74Schristos 
74275fd0b74Schristos /* Given a PC, return histogram record which address range include this PC.
74375fd0b74Schristos    Return NULL if there's no such record.  */
74475fd0b74Schristos static histogram *
find_histogram_for_pc(bfd_vma pc)74575fd0b74Schristos find_histogram_for_pc (bfd_vma pc)
74675fd0b74Schristos {
74775fd0b74Schristos   unsigned i;
74875fd0b74Schristos   for (i = 0; i < num_histograms; ++i)
74975fd0b74Schristos     {
75075fd0b74Schristos       if (histograms[i].lowpc <= pc && pc < histograms[i].highpc)
75175fd0b74Schristos 	return &histograms[i];
75275fd0b74Schristos     }
75375fd0b74Schristos   return 0;
75475fd0b74Schristos }
755