Blame gprof/hist.c

Packit bbfece
/* hist.c  -  Histogram related operations.
Packit bbfece
Packit bbfece
   Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit bbfece
Packit bbfece
   This file is part of GNU Binutils.
Packit bbfece
Packit bbfece
   This program is free software; you can redistribute it and/or modify
Packit bbfece
   it under the terms of the GNU General Public License as published by
Packit bbfece
   the Free Software Foundation; either version 3 of the License, or
Packit bbfece
   (at your option) any later version.
Packit bbfece
Packit bbfece
   This program is distributed in the hope that it will be useful,
Packit bbfece
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bbfece
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit bbfece
   GNU General Public License for more details.
Packit bbfece
Packit bbfece
   You should have received a copy of the GNU General Public License
Packit bbfece
   along with this program; if not, write to the Free Software
Packit bbfece
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
Packit bbfece
   02110-1301, USA.  */
Packit bbfece

Packit bbfece
#include "gprof.h"
Packit bbfece
#include "libiberty.h"
Packit bbfece
#include "search_list.h"
Packit bbfece
#include "source.h"
Packit bbfece
#include "symtab.h"
Packit bbfece
#include "corefile.h"
Packit bbfece
#include "gmon_io.h"
Packit bbfece
#include "gmon_out.h"
Packit bbfece
#include "hist.h"
Packit bbfece
#include "sym_ids.h"
Packit bbfece
#include "utils.h"
Packit bbfece
#include "math.h"
Packit bbfece
#include "stdio.h"
Packit bbfece
#include "stdlib.h"
Packit bbfece
Packit bbfece
#define UNITS_TO_CODE (offset_to_code / sizeof(UNIT))
Packit bbfece
Packit bbfece
static void scale_and_align_entries (void);
Packit bbfece
static void print_header (int);
Packit bbfece
static void print_line (Sym *, double);
Packit bbfece
static int cmp_time (const PTR, const PTR);
Packit bbfece
Packit bbfece
/* Declarations of automatically generated functions to output blurbs.  */
Packit bbfece
extern void flat_blurb (FILE * fp);
Packit bbfece
Packit bbfece
static histogram *find_histogram (bfd_vma lowpc, bfd_vma highpc);
Packit bbfece
static histogram *find_histogram_for_pc (bfd_vma pc);
Packit bbfece
Packit bbfece
histogram * histograms;
Packit bbfece
unsigned num_histograms;
Packit bbfece
double hist_scale;
Packit bbfece
static char hist_dimension[16] = "seconds";
Packit bbfece
static char hist_dimension_abbrev = 's';
Packit bbfece
Packit bbfece
static double accum_time;	/* Accumulated time so far for print_line(). */
Packit bbfece
static double total_time;	/* Total time for all routines.  */
Packit bbfece
Packit bbfece
/* Table of SI prefixes for powers of 10 (used to automatically
Packit bbfece
   scale some of the values in the flat profile).  */
Packit bbfece
const struct
Packit bbfece
  {
Packit bbfece
    char prefix;
Packit bbfece
    double scale;
Packit bbfece
  }
Packit bbfece
SItab[] =
Packit bbfece
{
Packit bbfece
  { 'T', 1e-12 },				/* tera */
Packit bbfece
  { 'G', 1e-09 },				/* giga */
Packit bbfece
  { 'M', 1e-06 },				/* mega */
Packit bbfece
  { 'K', 1e-03 },				/* kilo */
Packit bbfece
  { ' ', 1e-00 },
Packit bbfece
  { 'm', 1e+03 },				/* milli */
Packit bbfece
  { 'u', 1e+06 },				/* micro */
Packit bbfece
  { 'n', 1e+09 },				/* nano */
Packit bbfece
  { 'p', 1e+12 },				/* pico */
Packit bbfece
  { 'f', 1e+15 },				/* femto */
Packit bbfece
  { 'a', 1e+18 }				/* ato */
Packit bbfece
};
Packit bbfece
Packit bbfece
/* Reads just the header part of histogram record into
Packit bbfece
   *RECORD from IFP.  FILENAME is the name of IFP and
Packit bbfece
   is provided for formatting error messages only.
Packit bbfece
Packit bbfece
   If FIRST is non-zero, sets global variables HZ, HIST_DIMENSION,
Packit bbfece
   HIST_DIMENSION_ABBREV, HIST_SCALE.  If FIRST is zero, checks
Packit bbfece
   that the new histogram is compatible with already-set values
Packit bbfece
   of those variables and emits an error if that's not so.  */
Packit bbfece
static void
Packit bbfece
read_histogram_header (histogram *record,
Packit bbfece
		       FILE *ifp, const char *filename,
Packit bbfece
		       int first)
Packit bbfece
{
Packit bbfece
  unsigned int profrate;
Packit bbfece
  char n_hist_dimension[15];
Packit bbfece
  char n_hist_dimension_abbrev;
Packit bbfece
  double n_hist_scale;
Packit bbfece
Packit bbfece
  if (gmon_io_read_vma (ifp, &record->lowpc)
Packit bbfece
      || gmon_io_read_vma (ifp, &record->highpc)
Packit bbfece
      || gmon_io_read_32 (ifp, &record->num_bins)
Packit bbfece
      || gmon_io_read_32 (ifp, &profrate)
Packit bbfece
      || gmon_io_read (ifp, n_hist_dimension, 15)
Packit bbfece
      || gmon_io_read (ifp, &n_hist_dimension_abbrev, 1))
Packit bbfece
    {
Packit bbfece
      fprintf (stderr, _("%s: %s: unexpected end of file\n"),
Packit bbfece
	       whoami, filename);
Packit bbfece
Packit bbfece
      done (1);
Packit bbfece
    }
Packit bbfece
Packit bbfece
  n_hist_scale = (double)((record->highpc - record->lowpc) / sizeof (UNIT))
Packit bbfece
    / record->num_bins;
Packit bbfece
Packit bbfece
  if (first)
Packit bbfece
    {
Packit bbfece
      /* We don't try to veryfy profrate is the same for all histogram
Packit bbfece
	 records.  If we have two histogram records for the same
Packit bbfece
	 address range and profiling samples is done as often
Packit bbfece
	 as possible as opposed on timer, then the actual profrate will
Packit bbfece
	 be slightly different.  Most of the time the difference does not
Packit bbfece
	 matter and insisting that profiling rate is exactly the same
Packit bbfece
	 will only create inconvenient.  */
Packit bbfece
      hz = profrate;
Packit bbfece
      memcpy (hist_dimension, n_hist_dimension, 15);
Packit bbfece
      hist_dimension_abbrev = n_hist_dimension_abbrev;
Packit bbfece
      hist_scale = n_hist_scale;
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    {
Packit bbfece
      if (strncmp (n_hist_dimension, hist_dimension, 15) != 0)
Packit bbfece
	{
Packit bbfece
	  fprintf (stderr,
Packit bbfece
		   _("%s: dimension unit changed between histogram records\n"
Packit bbfece
		     "%s: from '%s'\n"
Packit bbfece
		     "%s: to '%s'\n"),
Packit bbfece
		   whoami, whoami, hist_dimension, whoami, n_hist_dimension);
Packit bbfece
	  done (1);
Packit bbfece
	}
Packit bbfece
Packit bbfece
      if (n_hist_dimension_abbrev != hist_dimension_abbrev)
Packit bbfece
	{
Packit bbfece
	  fprintf (stderr,
Packit bbfece
		   _("%s: dimension abbreviation changed between histogram records\n"
Packit bbfece
		     "%s: from '%c'\n"
Packit bbfece
		     "%s: to '%c'\n"),
Packit bbfece
		   whoami, whoami, hist_dimension_abbrev, whoami, n_hist_dimension_abbrev);
Packit bbfece
	  done (1);
Packit bbfece
	}
Packit bbfece
Packit bbfece
      /* The only reason we require the same scale for histograms is that
Packit bbfece
	 there's code (notably printing code), that prints units,
Packit bbfece
	 and it would be very confusing to have one unit mean different
Packit bbfece
	 things for different functions.  */
Packit bbfece
      if (fabs (hist_scale - n_hist_scale) > 0.000001)
Packit bbfece
	{
Packit bbfece
	  fprintf (stderr,
Packit bbfece
		   _("%s: different scales in histogram records"),
Packit bbfece
		   whoami);
Packit bbfece
	  done (1);
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Read the histogram from file IFP.  FILENAME is the name of IFP and
Packit bbfece
   is provided for formatting error messages only.  */
Packit bbfece
Packit bbfece
void
Packit bbfece
hist_read_rec (FILE * ifp, const char *filename)
Packit bbfece
{
Packit bbfece
  bfd_vma lowpc, highpc;
Packit bbfece
  histogram n_record;
Packit bbfece
  histogram *record, *existing_record;
Packit bbfece
  unsigned i;
Packit bbfece
Packit bbfece
  /* 1. Read the header and see if there's existing record for the
Packit bbfece
     same address range and that there are no overlapping records.  */
Packit bbfece
  read_histogram_header (&n_record, ifp, filename, num_histograms == 0);
Packit bbfece
Packit bbfece
  existing_record = find_histogram (n_record.lowpc, n_record.highpc);
Packit bbfece
  if (existing_record)
Packit bbfece
    {
Packit bbfece
      record = existing_record;
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    {
Packit bbfece
      /* If this record overlaps, but does not completely match an existing
Packit bbfece
	 record, it's an error.  */
Packit bbfece
      lowpc = n_record.lowpc;
Packit bbfece
      highpc = n_record.highpc;
Packit bbfece
      hist_clip_symbol_address (&lowpc, &highpc);
Packit bbfece
      if (lowpc != highpc)
Packit bbfece
	{
Packit bbfece
	  fprintf (stderr,
Packit bbfece
		   _("%s: overlapping histogram records\n"),
Packit bbfece
		   whoami);
Packit bbfece
	  done (1);
Packit bbfece
	}
Packit bbfece
Packit bbfece
      /* This is new record.  Add it to global array and allocate space for
Packit bbfece
	 the samples.  */
Packit bbfece
      histograms = (struct histogram *)
Packit bbfece
          xrealloc (histograms, sizeof (histogram) * (num_histograms + 1));
Packit bbfece
      memcpy (histograms + num_histograms,
Packit bbfece
	      &n_record, sizeof (histogram));
Packit bbfece
      record = &histograms[num_histograms];
Packit bbfece
      ++num_histograms;
Packit bbfece
Packit bbfece
      record->sample = (int *) xmalloc (record->num_bins
Packit bbfece
					* sizeof (record->sample[0]));
Packit bbfece
      memset (record->sample, 0, record->num_bins * sizeof (record->sample[0]));
Packit bbfece
    }
Packit bbfece
Packit bbfece
  /* 2. We have either a new record (with zeroed histogram data), or an existing
Packit bbfece
     record with some data in the histogram already.  Read new data into the
Packit bbfece
     record, adding hit counts.  */
Packit bbfece
Packit bbfece
  DBG (SAMPLEDEBUG,
Packit bbfece
       printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %u\n",
Packit bbfece
	       (unsigned long) record->lowpc, (unsigned long) record->highpc,
Packit bbfece
               record->num_bins));
Packit bbfece
Packit bbfece
  for (i = 0; i < record->num_bins; ++i)
Packit bbfece
    {
Packit bbfece
      UNIT count;
Packit bbfece
      if (fread (&count[0], sizeof (count), 1, ifp) != 1)
Packit bbfece
	{
Packit bbfece
	  fprintf (stderr,
Packit bbfece
		  _("%s: %s: unexpected EOF after reading %u of %u samples\n"),
Packit bbfece
		   whoami, filename, i, record->num_bins);
Packit bbfece
	  done (1);
Packit bbfece
	}
Packit bbfece
      record->sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]);
Packit bbfece
      DBG (SAMPLEDEBUG,
Packit bbfece
	   printf ("[hist_read_rec] 0x%lx: %u\n",
Packit bbfece
		   (unsigned long) (record->lowpc
Packit bbfece
                                    + i * (record->highpc - record->lowpc)
Packit bbfece
                                    / record->num_bins),
Packit bbfece
		   record->sample[i]));
Packit bbfece
    }
Packit bbfece
}
Packit bbfece
Packit bbfece
Packit bbfece
/* Write all execution histograms file OFP.  FILENAME is the name
Packit bbfece
   of OFP and is provided for formatting error-messages only.  */
Packit bbfece
Packit bbfece
void
Packit bbfece
hist_write_hist (FILE * ofp, const char *filename)
Packit bbfece
{
Packit bbfece
  UNIT count;
Packit bbfece
  unsigned int i, r;
Packit bbfece
Packit bbfece
  for (r = 0; r < num_histograms; ++r)
Packit bbfece
    {
Packit bbfece
      histogram *record = &histograms[r];
Packit bbfece
Packit bbfece
      /* Write header.  */
Packit bbfece
Packit bbfece
      if (gmon_io_write_8 (ofp, GMON_TAG_TIME_HIST)
Packit bbfece
	  || gmon_io_write_vma (ofp, record->lowpc)
Packit bbfece
	  || gmon_io_write_vma (ofp, record->highpc)
Packit bbfece
	  || gmon_io_write_32 (ofp, record->num_bins)
Packit bbfece
	  || gmon_io_write_32 (ofp, hz)
Packit bbfece
	  || gmon_io_write (ofp, hist_dimension, 15)
Packit bbfece
	  || gmon_io_write (ofp, &hist_dimension_abbrev, 1))
Packit bbfece
	{
Packit bbfece
	  perror (filename);
Packit bbfece
	  done (1);
Packit bbfece
	}
Packit bbfece
Packit bbfece
      for (i = 0; i < record->num_bins; ++i)
Packit bbfece
	{
Packit bbfece
	  bfd_put_16 (core_bfd, (bfd_vma) record->sample[i], (bfd_byte *) &count[0]);
Packit bbfece
Packit bbfece
	  if (fwrite (&count[0], sizeof (count), 1, ofp) != 1)
Packit bbfece
	    {
Packit bbfece
	      perror (filename);
Packit bbfece
	      done (1);
Packit bbfece
	    }
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Calculate scaled entry point addresses (to save time in
Packit bbfece
   hist_assign_samples), and, on architectures that have procedure
Packit bbfece
   entry masks at the start of a function, possibly push the scaled
Packit bbfece
   entry points over the procedure entry mask, if it turns out that
Packit bbfece
   the entry point is in one bin and the code for a routine is in the
Packit bbfece
   next bin.  */
Packit bbfece
Packit bbfece
static void
Packit bbfece
scale_and_align_entries (void)
Packit bbfece
{
Packit bbfece
  Sym *sym;
Packit bbfece
  bfd_vma bin_of_entry;
Packit bbfece
  bfd_vma bin_of_code;
Packit bbfece
Packit bbfece
  for (sym = symtab.base; sym < symtab.limit; sym++)
Packit bbfece
    {
Packit bbfece
      histogram *r = find_histogram_for_pc (sym->addr);
Packit bbfece
Packit bbfece
      sym->hist.scaled_addr = sym->addr / sizeof (UNIT);
Packit bbfece
Packit bbfece
      if (r)
Packit bbfece
	{
Packit bbfece
	  bin_of_entry = (sym->hist.scaled_addr - r->lowpc) / hist_scale;
Packit bbfece
	  bin_of_code = ((sym->hist.scaled_addr + UNITS_TO_CODE - r->lowpc)
Packit bbfece
		     / hist_scale);
Packit bbfece
	  if (bin_of_entry < bin_of_code)
Packit bbfece
	    {
Packit bbfece
	      DBG (SAMPLEDEBUG,
Packit bbfece
		   printf ("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
Packit bbfece
			   (unsigned long) sym->hist.scaled_addr,
Packit bbfece
			   (unsigned long) (sym->hist.scaled_addr
Packit bbfece
					    + UNITS_TO_CODE)));
Packit bbfece
	      sym->hist.scaled_addr += UNITS_TO_CODE;
Packit bbfece
	    }
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
}
Packit bbfece
Packit bbfece
Packit bbfece
/* Assign samples to the symbol to which they belong.
Packit bbfece
Packit bbfece
   Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
Packit bbfece
   which may overlap one more symbol address ranges.  If a symbol
Packit bbfece
   overlaps with the bin's address range by O percent, then O percent
Packit bbfece
   of the bin's count is credited to that symbol.
Packit bbfece
Packit bbfece
   There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
Packit bbfece
   with respect to the symbol's address range [SYM_LOW_PC,
Packit bbfece
   SYM_HIGH_PC) as shown in the following diagram.  OVERLAP computes
Packit bbfece
   the distance (in UNITs) between the arrows, the fraction of the
Packit bbfece
   sample that is to be credited to the symbol which starts at
Packit bbfece
   SYM_LOW_PC.
Packit bbfece
Packit bbfece
	  sym_low_pc                                      sym_high_pc
Packit bbfece
	       |                                               |
Packit bbfece
	       v                                               v
Packit bbfece
Packit bbfece
	       +-----------------------------------------------+
Packit bbfece
	       |                                               |
Packit bbfece
	  |  ->|    |<-         ->|         |<-         ->|    |<-  |
Packit bbfece
	  |         |             |         |             |         |
Packit bbfece
	  +---------+             +---------+             +---------+
Packit bbfece
Packit bbfece
	  ^         ^             ^         ^             ^         ^
Packit bbfece
	  |         |             |         |             |         |
Packit bbfece
     bin_low_pc bin_high_pc  bin_low_pc bin_high_pc  bin_low_pc bin_high_pc
Packit bbfece
Packit bbfece
   For the VAX we assert that samples will never fall in the first two
Packit bbfece
   bytes of any routine, since that is the entry mask, thus we call
Packit bbfece
   scale_and_align_entries() to adjust the entry points if the entry
Packit bbfece
   mask falls in one bin but the code for the routine doesn't start
Packit bbfece
   until the next bin.  In conjunction with the alignment of routine
Packit bbfece
   addresses, this should allow us to have only one sample for every
Packit bbfece
   four bytes of text space and never have any overlap (the two end
Packit bbfece
   cases, above).  */
Packit bbfece
Packit bbfece
static void
Packit bbfece
hist_assign_samples_1 (histogram *r)
Packit bbfece
{
Packit bbfece
  bfd_vma bin_low_pc, bin_high_pc;
Packit bbfece
  bfd_vma sym_low_pc, sym_high_pc;
Packit bbfece
  bfd_vma overlap, addr;
Packit bbfece
  unsigned int bin_count;
Packit bbfece
  unsigned int i, j, k;
Packit bbfece
  double count_time, credit;
Packit bbfece
Packit bbfece
  bfd_vma lowpc = r->lowpc / sizeof (UNIT);
Packit bbfece
Packit bbfece
  /* Iterate over all sample bins.  */
Packit bbfece
  for (i = 0, k = 1; i < r->num_bins; ++i)
Packit bbfece
    {
Packit bbfece
      bin_count = r->sample[i];
Packit bbfece
      if (! bin_count)
Packit bbfece
	continue;
Packit bbfece
Packit bbfece
      bin_low_pc = lowpc + (bfd_vma) (hist_scale * i);
Packit bbfece
      bin_high_pc = lowpc + (bfd_vma) (hist_scale * (i + 1));
Packit bbfece
      count_time = bin_count;
Packit bbfece
Packit bbfece
      DBG (SAMPLEDEBUG,
Packit bbfece
	   printf (
Packit bbfece
      "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%u\n",
Packit bbfece
		    (unsigned long) (sizeof (UNIT) * bin_low_pc),
Packit bbfece
		    (unsigned long) (sizeof (UNIT) * bin_high_pc),
Packit bbfece
		    bin_count));
Packit bbfece
      total_time += count_time;
Packit bbfece
Packit bbfece
      /* Credit all symbols that are covered by bin I.
Packit bbfece
Packit bbfece
         PR gprof/13325: Make sure that K does not get decremented
Packit bbfece
	 and J will never be less than 0.  */
Packit bbfece
      for (j = k - 1; j < symtab.len; k = ++j)
Packit bbfece
	{
Packit bbfece
	  sym_low_pc = symtab.base[j].hist.scaled_addr;
Packit bbfece
	  sym_high_pc = symtab.base[j + 1].hist.scaled_addr;
Packit bbfece
Packit bbfece
	  /* If high end of bin is below entry address,
Packit bbfece
	     go for next bin.  */
Packit bbfece
	  if (bin_high_pc < sym_low_pc)
Packit bbfece
	    break;
Packit bbfece
Packit bbfece
	  /* If low end of bin is above high end of symbol,
Packit bbfece
	     go for next symbol.  */
Packit bbfece
	  if (bin_low_pc >= sym_high_pc)
Packit bbfece
	    continue;
Packit bbfece
Packit bbfece
	  overlap =
Packit bbfece
	    MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc);
Packit bbfece
	  if (overlap > 0)
Packit bbfece
	    {
Packit bbfece
	      DBG (SAMPLEDEBUG,
Packit bbfece
		   printf (
Packit bbfece
	       "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
Packit bbfece
			   (unsigned long) symtab.base[j].addr,
Packit bbfece
			   (unsigned long) (sizeof (UNIT) * sym_high_pc),
Packit bbfece
			   symtab.base[j].name, overlap * count_time / hist_scale,
Packit bbfece
			   (long) overlap));
Packit bbfece
Packit bbfece
	      addr = symtab.base[j].addr;
Packit bbfece
	      credit = overlap * count_time / hist_scale;
Packit bbfece
Packit bbfece
	      /* Credit symbol if it appears in INCL_FLAT or that
Packit bbfece
		 table is empty and it does not appear it in
Packit bbfece
		 EXCL_FLAT.  */
Packit bbfece
	      if (sym_lookup (&syms[INCL_FLAT], addr)
Packit bbfece
		  || (syms[INCL_FLAT].len == 0
Packit bbfece
		      && !sym_lookup (&syms[EXCL_FLAT], addr)))
Packit bbfece
		{
Packit bbfece
		  symtab.base[j].hist.time += credit;
Packit bbfece
		}
Packit bbfece
	      else
Packit bbfece
		{
Packit bbfece
		  total_time -= credit;
Packit bbfece
		}
Packit bbfece
	    }
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
Packit bbfece
  DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n",
Packit bbfece
			    total_time));
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Calls 'hist_assign_sampes_1' for all histogram records read so far. */
Packit bbfece
void
Packit bbfece
hist_assign_samples (void)
Packit bbfece
{
Packit bbfece
  unsigned i;
Packit bbfece
Packit bbfece
  scale_and_align_entries ();
Packit bbfece
Packit bbfece
  for (i = 0; i < num_histograms; ++i)
Packit bbfece
    hist_assign_samples_1 (&histograms[i]);
Packit bbfece
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Print header for flag histogram profile.  */
Packit bbfece
Packit bbfece
static void
Packit bbfece
print_header (int prefix)
Packit bbfece
{
Packit bbfece
  char unit[64];
Packit bbfece
Packit bbfece
  sprintf (unit, _("%c%c/call"), prefix, hist_dimension_abbrev);
Packit bbfece
Packit bbfece
  if (bsd_style_output)
Packit bbfece
    {
Packit bbfece
      printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
Packit bbfece
	      (long) hist_scale * (long) sizeof (UNIT));
Packit bbfece
      if (total_time > 0.0)
Packit bbfece
	{
Packit bbfece
	  printf (_(" for %.2f%% of %.2f %s\n\n"),
Packit bbfece
		  100.0 / total_time, total_time / hz, hist_dimension);
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    {
Packit bbfece
      printf (_("\nEach sample counts as %g %s.\n"), 1.0 / hz, hist_dimension);
Packit bbfece
    }
Packit bbfece
Packit bbfece
  if (total_time <= 0.0)
Packit bbfece
    {
Packit bbfece
      printf (_(" no time accumulated\n\n"));
Packit bbfece
Packit bbfece
      /* This doesn't hurt since all the numerators will be zero.  */
Packit bbfece
      total_time = 1.0;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
Packit bbfece
	  "%  ", _("cumulative"), _("self  "), "", _("self  "), _("total "),
Packit bbfece
	  "");
Packit bbfece
  printf ("%5.5s %9.9s  %8.8s %8.8s %8.8s %8.8s  %-8.8s\n",
Packit bbfece
	  _("time"), hist_dimension, hist_dimension, _("calls"), unit, unit,
Packit bbfece
	  _("name"));
Packit bbfece
}
Packit bbfece
Packit bbfece
Packit bbfece
static void
Packit bbfece
print_line (Sym *sym, double scale)
Packit bbfece
{
Packit bbfece
  if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0)
Packit bbfece
    return;
Packit bbfece
Packit bbfece
  accum_time += sym->hist.time;
Packit bbfece
Packit bbfece
  if (bsd_style_output)
Packit bbfece
    printf ("%5.1f %10.2f %8.2f",
Packit bbfece
	    total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
Packit bbfece
	    accum_time / hz, sym->hist.time / hz);
Packit bbfece
  else
Packit bbfece
    printf ("%6.2f %9.2f %8.2f",
Packit bbfece
	    total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
Packit bbfece
	    accum_time / hz, sym->hist.time / hz);
Packit bbfece
Packit bbfece
  if (sym->ncalls != 0)
Packit bbfece
    printf (" %8lu %8.2f %8.2f  ",
Packit bbfece
	    sym->ncalls, scale * sym->hist.time / hz / sym->ncalls,
Packit bbfece
	    scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls);
Packit bbfece
  else
Packit bbfece
    printf (" %8.8s %8.8s %8.8s  ", "", "", "");
Packit bbfece
Packit bbfece
  if (bsd_style_output)
Packit bbfece
    print_name (sym);
Packit bbfece
  else
Packit bbfece
    print_name_only (sym);
Packit bbfece
Packit bbfece
  printf ("\n");
Packit bbfece
}
Packit bbfece
Packit bbfece
Packit bbfece
/* Compare LP and RP.  The primary comparison key is execution time,
Packit bbfece
   the secondary is number of invocation, and the tertiary is the
Packit bbfece
   lexicographic order of the function names.  */
Packit bbfece
Packit bbfece
static int
Packit bbfece
cmp_time (const PTR lp, const PTR rp)
Packit bbfece
{
Packit bbfece
  const Sym *left = *(const Sym **) lp;
Packit bbfece
  const Sym *right = *(const Sym **) rp;
Packit bbfece
  double time_diff;
Packit bbfece
Packit bbfece
  time_diff = right->hist.time - left->hist.time;
Packit bbfece
Packit bbfece
  if (time_diff > 0.0)
Packit bbfece
    return 1;
Packit bbfece
Packit bbfece
  if (time_diff < 0.0)
Packit bbfece
    return -1;
Packit bbfece
Packit bbfece
  if (right->ncalls > left->ncalls)
Packit bbfece
    return 1;
Packit bbfece
Packit bbfece
  if (right->ncalls < left->ncalls)
Packit bbfece
    return -1;
Packit bbfece
Packit bbfece
  return strcmp (left->name, right->name);
Packit bbfece
}
Packit bbfece
Packit bbfece
Packit bbfece
/* Print the flat histogram profile.  */
Packit bbfece
Packit bbfece
void
Packit bbfece
hist_print (void)
Packit bbfece
{
Packit bbfece
  Sym **time_sorted_syms, *top_dog, *sym;
Packit bbfece
  unsigned int sym_index;
Packit bbfece
  unsigned log_scale;
Packit bbfece
  double top_time;
Packit bbfece
  bfd_vma addr;
Packit bbfece
Packit bbfece
  if (first_output)
Packit bbfece
    first_output = FALSE;
Packit bbfece
  else
Packit bbfece
    printf ("\f\n");
Packit bbfece
Packit bbfece
  accum_time = 0.0;
Packit bbfece
Packit bbfece
  if (bsd_style_output)
Packit bbfece
    {
Packit bbfece
      if (print_descriptions)
Packit bbfece
	{
Packit bbfece
	  printf (_("\n\n\nflat profile:\n"));
Packit bbfece
	  flat_blurb (stdout);
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    {
Packit bbfece
      printf (_("Flat profile:\n"));
Packit bbfece
    }
Packit bbfece
Packit bbfece
  /* Sort the symbol table by time (call-count and name as secondary
Packit bbfece
     and tertiary keys).  */
Packit bbfece
  time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
Packit bbfece
Packit bbfece
  for (sym_index = 0; sym_index < symtab.len; ++sym_index)
Packit bbfece
    time_sorted_syms[sym_index] = &symtab.base[sym_index];
Packit bbfece
Packit bbfece
  qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
Packit bbfece
Packit bbfece
  if (bsd_style_output)
Packit bbfece
    {
Packit bbfece
      log_scale = 5;		/* Milli-seconds is BSD-default.  */
Packit bbfece
    }
Packit bbfece
  else
Packit bbfece
    {
Packit bbfece
      /* Search for symbol with highest per-call
Packit bbfece
	 execution time and scale accordingly.  */
Packit bbfece
      log_scale = 0;
Packit bbfece
      top_dog = 0;
Packit bbfece
      top_time = 0.0;
Packit bbfece
Packit bbfece
      for (sym_index = 0; sym_index < symtab.len; ++sym_index)
Packit bbfece
	{
Packit bbfece
	  sym = time_sorted_syms[sym_index];
Packit bbfece
Packit bbfece
	  if (sym->ncalls != 0)
Packit bbfece
	    {
Packit bbfece
	      double call_time;
Packit bbfece
Packit bbfece
	      call_time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
Packit bbfece
Packit bbfece
	      if (call_time > top_time)
Packit bbfece
		{
Packit bbfece
		  top_dog = sym;
Packit bbfece
		  top_time = call_time;
Packit bbfece
		}
Packit bbfece
	    }
Packit bbfece
	}
Packit bbfece
Packit bbfece
      if (top_dog && top_dog->ncalls != 0 && top_time > 0.0)
Packit bbfece
	{
Packit bbfece
	  top_time /= hz;
Packit bbfece
Packit bbfece
	  for (log_scale = 0; log_scale < ARRAY_SIZE (SItab); log_scale ++)
Packit bbfece
	    {
Packit bbfece
	      double scaled_value = SItab[log_scale].scale * top_time;
Packit bbfece
Packit bbfece
	      if (scaled_value >= 1.0 && scaled_value < 1000.0)
Packit bbfece
		break;
Packit bbfece
	    }
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
Packit bbfece
  /* For now, the dimension is always seconds.  In the future, we
Packit bbfece
     may also want to support other (pseudo-)dimensions (such as
Packit bbfece
     I-cache misses etc.).  */
Packit bbfece
  print_header (SItab[log_scale].prefix);
Packit bbfece
Packit bbfece
  for (sym_index = 0; sym_index < symtab.len; ++sym_index)
Packit bbfece
    {
Packit bbfece
      addr = time_sorted_syms[sym_index]->addr;
Packit bbfece
Packit bbfece
      /* Print symbol if its in INCL_FLAT table or that table
Packit bbfece
	is empty and the symbol is not in EXCL_FLAT.  */
Packit bbfece
      if (sym_lookup (&syms[INCL_FLAT], addr)
Packit bbfece
	  || (syms[INCL_FLAT].len == 0
Packit bbfece
	      && !sym_lookup (&syms[EXCL_FLAT], addr)))
Packit bbfece
	print_line (time_sorted_syms[sym_index], SItab[log_scale].scale);
Packit bbfece
    }
Packit bbfece
Packit bbfece
  free (time_sorted_syms);
Packit bbfece
Packit bbfece
  if (print_descriptions && !bsd_style_output)
Packit bbfece
    flat_blurb (stdout);
Packit bbfece
}
Packit bbfece
Packit bbfece
int
Packit bbfece
hist_check_address (unsigned address)
Packit bbfece
{
Packit bbfece
  unsigned i;
Packit bbfece
Packit bbfece
  for (i = 0; i < num_histograms; ++i)
Packit bbfece
    if (histograms[i].lowpc <= address && address < histograms[i].highpc)
Packit bbfece
      return 1;
Packit bbfece
Packit bbfece
  return 0;
Packit bbfece
}
Packit bbfece
Packit bbfece
#if ! defined(min)
Packit bbfece
#define min(a,b) (((a)<(b)) ? (a) : (b))
Packit bbfece
#endif
Packit bbfece
#if ! defined(max)
Packit bbfece
#define max(a,b) (((a)>(b)) ? (a) : (b))
Packit bbfece
#endif
Packit bbfece
Packit bbfece
void
Packit bbfece
hist_clip_symbol_address (bfd_vma *p_lowpc, bfd_vma *p_highpc)
Packit bbfece
{
Packit bbfece
  unsigned i;
Packit bbfece
  int found = 0;
Packit bbfece
Packit bbfece
  if (num_histograms == 0)
Packit bbfece
    {
Packit bbfece
      *p_highpc = *p_lowpc;
Packit bbfece
      return;
Packit bbfece
    }
Packit bbfece
Packit bbfece
  for (i = 0; i < num_histograms; ++i)
Packit bbfece
    {
Packit bbfece
      bfd_vma common_low, common_high;
Packit bbfece
      common_low = max (histograms[i].lowpc, *p_lowpc);
Packit bbfece
      common_high = min (histograms[i].highpc, *p_highpc);
Packit bbfece
Packit bbfece
      if (common_low < common_high)
Packit bbfece
	{
Packit bbfece
	  if (found)
Packit bbfece
	    {
Packit bbfece
	      fprintf (stderr,
Packit bbfece
		       _("%s: found a symbol that covers "
Packit bbfece
			 "several histogram records"),
Packit bbfece
			 whoami);
Packit bbfece
	      done (1);
Packit bbfece
	    }
Packit bbfece
Packit bbfece
	  found = 1;
Packit bbfece
	  *p_lowpc = common_low;
Packit bbfece
	  *p_highpc = common_high;
Packit bbfece
	}
Packit bbfece
    }
Packit bbfece
Packit bbfece
  if (!found)
Packit bbfece
    *p_highpc = *p_lowpc;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Find and return exising histogram record having the same lowpc and
Packit bbfece
   highpc as passed via the parameters.  Return NULL if nothing is found.
Packit bbfece
   The return value is valid until any new histogram is read.  */
Packit bbfece
static histogram *
Packit bbfece
find_histogram (bfd_vma lowpc, bfd_vma highpc)
Packit bbfece
{
Packit bbfece
  unsigned i;
Packit bbfece
  for (i = 0; i < num_histograms; ++i)
Packit bbfece
    {
Packit bbfece
      if (histograms[i].lowpc == lowpc && histograms[i].highpc == highpc)
Packit bbfece
	return &histograms[i];
Packit bbfece
    }
Packit bbfece
  return 0;
Packit bbfece
}
Packit bbfece
Packit bbfece
/* Given a PC, return histogram record which address range include this PC.
Packit bbfece
   Return NULL if there's no such record.  */
Packit bbfece
static histogram *
Packit bbfece
find_histogram_for_pc (bfd_vma pc)
Packit bbfece
{
Packit bbfece
  unsigned i;
Packit bbfece
  for (i = 0; i < num_histograms; ++i)
Packit bbfece
    {
Packit bbfece
      if (histograms[i].lowpc <= pc && pc < histograms[i].highpc)
Packit bbfece
	return &histograms[i];
Packit bbfece
    }
Packit bbfece
  return 0;
Packit bbfece
}