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