* hist.h (struct histogram)
authorVladimir Prus <vladimir@codesourcery.com>
Tue, 10 Apr 2007 07:57:31 +0000 (07:57 +0000)
committerVladimir Prus <vladimir@codesourcery.com>
Tue, 10 Apr 2007 07:57:31 +0000 (07:57 +0000)
(histograms, num_histograms): New.
* hist.c (find_histogram, find_histogram_for_pc)
(read_histogram_header): New.
(s_lowpc, s_highpc, lowpc, highpc, hist_num_bins)
(hist_sample): Remove.
(hist_read_rec): Use the above, and handle multiple
histogram records with disjoint address ranges.
(hist_write_hist): Support several histogram records.
(scale_and_align_entries): Adjust for multiple histograms.
(hist_assign_samples_1): New.
(hist_assign_samples): Use the above.
(hist_clip_symbol_address): New.
* hist.h (hist_check_address)
(hist_clip_symbol_address): Declare.
* gmon_io.c (gmon_out_read, gmon_out_write): Adjust handling
of legacy format for multiple histogram changes.
* corefile.c (find_call): Check for core_text_space and
clip symbol address range here.
* vax.c (vax_find_call): Don't check for
core_text_space, or clip the symbol's address range here.
Use hist_check_address to check call's target address.
* sparc.c: Likewise.
* tahoe.c: Likewise.
* i386.c: Likewise.
* mips.c: Likewise. Also use core_text_sect->vma as the base
address for code accesses, just like other machine-specific
routines do.
* gprof.texi: Adjust for the new logic.

12 files changed:
gprof/ChangeLog
gprof/alpha.c
gprof/corefile.c
gprof/gmon_io.c
gprof/gprof.texi
gprof/hist.c
gprof/hist.h
gprof/i386.c
gprof/mips.c
gprof/sparc.c
gprof/tahoe.c
gprof/vax.c

index 1cbb54c..842117f 100644 (file)
@@ -1,3 +1,35 @@
+2007-04-10  Vladimir Prus  <vladimir@codesourcery.com>
+
+       * hist.h (struct histogram)
+       (histograms, num_histograms): New.
+       * hist.c (find_histogram, find_histogram_for_pc)
+       (read_histogram_header): New.
+       (s_lowpc, s_highpc, lowpc, highpc, hist_num_bins)
+       (hist_sample): Remove.
+       (hist_read_rec): Use the above, and handle multiple
+       histogram records with disjoint address ranges.
+       (hist_write_hist): Support several histogram records.
+       (scale_and_align_entries): Adjust for multiple histograms.
+       (hist_assign_samples_1): New.
+       (hist_assign_samples): Use the above.
+       (hist_clip_symbol_address): New.
+       * hist.h (hist_check_address)
+       (hist_clip_symbol_address): Declare.
+       * gmon_io.c (gmon_out_read, gmon_out_write): Adjust handling
+       of legacy format for multiple histogram changes.
+       * corefile.c (find_call): Check for core_text_space and
+       clip symbol address range here.
+       * vax.c (vax_find_call): Don't check for
+       core_text_space, or clip the symbol's address range here.
+       Use hist_check_address to check call's target address.  
+       * sparc.c: Likewise.
+       * tahoe.c: Likewise.
+       * i386.c: Likewise.
+       * mips.c: Likewise. Also use core_text_sect->vma as the base
+       address for code accesses, just like other machine-specific
+       routines do.
+       * gprof.texi: Adjust for the new logic.
+       
 2007-03-28  Richard Sandiford  <richard@codesourcery.com>
            Phil Edwards  <phil@codesourcery.com>
 
index b89e9cc..b14e842 100644 (file)
@@ -104,18 +104,6 @@ alpha_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
       indirect_child.cg.cyc.head = &indirect_child;
     }
 
-  if (!core_text_space)
-    {
-      return;
-    }
-  if (p_lowpc < s_lowpc)
-    {
-      p_lowpc = s_lowpc;
-    }
-  if (p_highpc > s_highpc)
-    {
-      p_highpc = s_highpc;
-    }
   DBG (CALLDEBUG, printf (_("[find_call] %s: 0x%lx to 0x%lx\n"),
                          parent->name, (unsigned long) p_lowpc,
                          (unsigned long) p_highpc));
@@ -157,7 +145,7 @@ alpha_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
           */
          dest_pc = pc + 4 + (((bfd_signed_vma) (insn & 0x1fffff)
                               ^ 0x100000) - 0x100000);
-         if (dest_pc >= s_lowpc && dest_pc <= s_highpc)
+         if (hist_check_address (dest_pc))
            {
              child = sym_lookup (&symtab, dest_pc);
              DBG (CALLDEBUG,
index 0d90b06..7ad18f1 100644 (file)
@@ -25,6 +25,7 @@
 #include "search_list.h"
 #include "source.h"
 #include "symtab.h"
+#include "hist.h"
 #include "corefile.h"
 
 bfd *core_bfd;
@@ -269,6 +270,11 @@ core_get_text_space (bfd *cbfd)
 void
 find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
 {
+  if (core_text_space == 0)
+    return;
+
+  hist_clip_symbol_address (&p_lowpc, &p_highpc);
+
   switch (bfd_get_arch (core_bfd))
     {
     case bfd_arch_i386:
index e56ab7a..1abf427 100644 (file)
@@ -388,10 +388,10 @@ gmon_out_read (const char *filename)
       int samp_bytes, header_size = 0;
       unsigned long count;
       bfd_vma from_pc, self_pc;
-      static struct hdr h;
       UNIT raw_bin_count;
       struct hdr tmp;
       unsigned int version;
+      unsigned int hist_num_bins;
 
       /* Information from a gmon.out file is in two parts: an array of
         sampling hits within pc ranges, and the arcs.  */
@@ -430,7 +430,7 @@ gmon_out_read (const char *filename)
           if (gmon_io_read_32 (ifp, &profrate))
            goto bad_gmon_file;
 
-         if (!s_highpc)
+         if (!histograms)
            hz = profrate;
          else if (hz != (int) profrate)
            {
@@ -480,35 +480,37 @@ gmon_out_read (const char *filename)
          done (1);
        }
 
-      if (s_highpc && (tmp.low_pc != h.low_pc
-                      || tmp.high_pc != h.high_pc || tmp.ncnt != h.ncnt))
+      samp_bytes = tmp.ncnt - header_size;
+      hist_num_bins = samp_bytes / sizeof (UNIT);
+      if (histograms && (tmp.low_pc != histograms->lowpc
+                        || tmp.high_pc != histograms->highpc
+                        || (hist_num_bins != histograms->num_bins)))
        {
          fprintf (stderr, _("%s: incompatible with first gmon file\n"),
                   filename);
          done (1);
        }
 
-      h = tmp;
-      s_lowpc = (bfd_vma) h.low_pc;
-      s_highpc = (bfd_vma) h.high_pc;
-      lowpc = (bfd_vma) h.low_pc / sizeof (UNIT);
-      highpc = (bfd_vma) h.high_pc / sizeof (UNIT);
-      samp_bytes = h.ncnt - header_size;
-      hist_num_bins = samp_bytes / sizeof (UNIT);
+      if (!histograms)
+       {
+         histograms = xmalloc (sizeof (struct histogram));
+         histograms->lowpc = tmp.low_pc;
+         histograms->highpc = tmp.high_pc;
+         histograms->num_bins = hist_num_bins;
+         histograms->sample = xmalloc (hist_num_bins * sizeof (int));
+         memset (histograms->sample, 0, 
+                 hist_num_bins * sizeof (int));
+       }
 
       DBG (SAMPLEDEBUG,
           printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
-                  (unsigned long) h.low_pc, (unsigned long) h.high_pc,
-                  h.ncnt);
-          printf ("[gmon_out_read]   s_lowpc 0x%lx   s_highpc 0x%lx\n",
-                  (unsigned long) s_lowpc, (unsigned long) s_highpc);
-          printf ("[gmon_out_read]     lowpc 0x%lx     highpc 0x%lx\n",
-                  (unsigned long) lowpc, (unsigned long) highpc);
+                  (unsigned long) tmp.low_pc, (unsigned long) tmp.high_pc,
+                  tmp.ncnt);
           printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
                   samp_bytes, hist_num_bins));
 
       /* Make sure that we have sensible values.  */
-      if (samp_bytes < 0 || lowpc > highpc)
+      if (samp_bytes < 0 || histograms->lowpc > histograms->highpc)
        {
          fprintf (stderr,
            _("%s: file '%s' does not appear to be in gmon.out format\n"),
@@ -519,14 +521,6 @@ gmon_out_read (const char *filename)
       if (hist_num_bins)
        ++nhist;
 
-      if (!hist_sample)
-       {
-         hist_sample =
-           (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0]));
-
-         memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0]));
-       }
-
       for (i = 0; i < hist_num_bins; ++i)
        {
          if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1)
@@ -537,7 +531,8 @@ gmon_out_read (const char *filename)
              done (1);
            }
 
-         hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count);
+         histograms->sample[i] 
+           += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count);
        }
 
       /* The rest of the file consists of a bunch of
@@ -684,9 +679,10 @@ gmon_out_write (const char *filename)
 
       /* Write the parts of the headers that are common to both the
         old BSD and 4.4BSD formats.  */
-      if (gmon_io_write_vma (ofp, s_lowpc)
-          || gmon_io_write_vma (ofp, s_highpc)
-          || gmon_io_write_32 (ofp, hist_num_bins * sizeof (UNIT) + hdrsize))
+      if (gmon_io_write_vma (ofp, histograms->lowpc)
+          || gmon_io_write_vma (ofp, histograms->highpc)
+          || gmon_io_write_32 (ofp, histograms->num_bins 
+                              * sizeof (UNIT) + hdrsize))
        {
          perror (filename);
          done (1);
@@ -714,9 +710,9 @@ gmon_out_write (const char *filename)
        }
 
       /* Dump the samples.  */
-      for (i = 0; i < hist_num_bins; ++i)
+      for (i = 0; i < histograms->num_bins; ++i)
        {
-         bfd_put_16 (core_bfd, (bfd_vma) hist_sample[i],
+         bfd_put_16 (core_bfd, (bfd_vma) histograms->sample[i],
                      (bfd_byte *) &raw_bin_count[0]);
          if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1)
            {
index f8be278..969d60e 100644 (file)
@@ -2082,11 +2082,12 @@ New-style histogram records are read by @code{hist.c:@-hist_read_rec}.
 For the first histogram record, allocate a memory array to hold
 all the bins, and read them in.
 When multiple profile data files (or files with multiple histogram
-records) are read, the starting address, ending address, number
-of bins and sampling rate must match between the various histograms,
-or a fatal error will result.
-If everything matches, just sum the additional histograms into
-the existing in-memory array.
+records) are read, the memory ranges of each pair of histogram records
+must be either equal, or non-overlapping.  For each pair of histogram
+records, the resolution (memory region size divided by the number of
+bins) must be the same.  The time unit must be the same for all 
+histogram records. If the above containts are met, all histograms
+for the same memory range are merged.
 
 As each call graph record is read (@code{call_graph.c:@-cg_read_rec}),
 the parent and child addresses
index 024f665..465655e 100644 (file)
@@ -31,6 +31,9 @@
 #include "hist.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))
 
@@ -42,11 +45,9 @@ static int cmp_time (const PTR, const PTR);
 /* 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.  */
-unsigned 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);
+
 double hist_scale;
 static char hist_dimension[16] = "seconds";
 static char hist_dimension_abbrev = 's';
@@ -76,23 +77,30 @@ SItab[] =
   { 'a', 1e+18 }                               /* ato */
 };
 
+/* 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.  
 
-/* 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)
+   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)
 {
-  bfd_vma n_lowpc, n_highpc;
-  unsigned int i, ncnt, profrate;
-  UNIT count;
-
-  if (gmon_io_read_vma (ifp, &n_lowpc)
-      || gmon_io_read_vma (ifp, &n_highpc)
-      || gmon_io_read_32 (ifp, &ncnt)
+  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, hist_dimension, 15)
-      || gmon_io_read (ifp, &hist_dimension_abbrev, 1))
+      || 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);
@@ -100,94 +108,178 @@ hist_read_rec (FILE * ifp, const char *filename)
       done (1);
     }
 
-  if (!s_highpc)
+  n_hist_scale = (double)((record->highpc - record->lowpc) / sizeof (UNIT)) 
+    / record->num_bins;
+
+  if (first)
     {
-      /* This is the first histogram record.  */
-      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;
+      /* 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;      
     }
-
-  DBG (SAMPLEDEBUG,
-       printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %u\n",
-              (unsigned long) n_lowpc, (unsigned long) n_highpc, ncnt);
-       printf ("[hist_read_rec] s_lowpc 0x%lx s_highpc 0x%lx nsamples %u\n",
-              (unsigned long) s_lowpc, (unsigned long) s_highpc,
-              hist_num_bins);
-       printf ("[hist_read_rec]   lowpc 0x%lx   highpc 0x%lx\n",
-              (unsigned long) lowpc, (unsigned long) highpc));
-
-  if (n_lowpc != s_lowpc || n_highpc != s_highpc
-      || ncnt != hist_num_bins || hz != (int) profrate)
+  else
     {
-      fprintf (stderr, _("%s: `%s' is incompatible with first gmon file\n"),
-              whoami, filename);
-      done (1);
+      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);
+       }
+
+      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);       
+       }
+
+      /* 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);      
+       }
     }
+}
 
-  if (!hist_sample)
+/* 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)
     {
-      hist_sample = (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0]));
-      memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0]));
+      record = existing_record;
+    }
+  else
+    {
+      /* 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 = 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 %u of %u samples\n"),
-                  whoami, filename, i, hist_num_bins);
+                  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) (n_lowpc + i * (n_highpc - n_lowpc) / ncnt),
-                  hist_sample[i]));
+                  (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
+/* Write all execution histograms file OFP.  FILENAME is the name
    of OFP and is provided for formatting error-messages only.  */
 
 void
 hist_write_hist (FILE * ofp, const char *filename)
 {
   UNIT count;
-  unsigned int i;
-
-  /* Write header.  */
+  unsigned int i, r;
 
-  if (gmon_io_write_8 (ofp, GMON_TAG_TIME_HIST)
-      || gmon_io_write_vma (ofp, s_lowpc)
-      || gmon_io_write_vma (ofp, s_highpc)
-      || gmon_io_write_32 (ofp, hist_num_bins)
-      || gmon_io_write_32 (ofp, hz)
-      || gmon_io_write (ofp, hist_dimension, 15)
-      || gmon_io_write (ofp, &hist_dimension_abbrev, 1))
+  for (r = 0; r < num_histograms; ++r)
     {
-      perror (filename);
-      done (1);
-    }
-
-  for (i = 0; i < hist_num_bins; ++i)
-    {
-      bfd_put_16 (core_bfd, (bfd_vma) hist_sample[i], (bfd_byte *) &count[0]);
-
-      if (fwrite (&count[0], sizeof (count), 1, ofp) != 1)
+      histogram *record = &histograms[r];
+
+      /* 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
@@ -205,17 +297,23 @@ scale_and_align_entries ()
   for (sym = symtab.base; sym < symtab.limit; sym++)
     {
       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)
+
+      histogram *r = find_histogram_for_pc (sym->addr);
+
+      if (r)
        {
-         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;
+         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;
+           }
        }
     }
 }
@@ -258,8 +356,8 @@ scale_and_align_entries ()
    four bytes of text space and never have any overlap (the two end
    cases, above).  */
 
-void
-hist_assign_samples ()
+static void
+hist_assign_samples_1 (histogram *r)
 {
   bfd_vma bin_low_pc, bin_high_pc;
   bfd_vma sym_low_pc, sym_high_pc;
@@ -268,15 +366,12 @@ hist_assign_samples ()
   unsigned int i, j;
   double time, credit;
 
-  /* Read samples and assign to symbols.  */
-  hist_scale = highpc - lowpc;
-  hist_scale /= hist_num_bins;
-  scale_and_align_entries ();
+  bfd_vma lowpc = r->lowpc / sizeof (UNIT);
 
   /* Iterate over all sample bins.  */
-  for (i = 0, j = 1; i < hist_num_bins; ++i)
+  for (i = 0, j = 1; i < r->num_bins; ++i)
     {
-      bin_count = hist_sample[i];
+      bin_count = r->sample[i];
       if (! bin_count)
        continue;
 
@@ -344,6 +439,18 @@ hist_assign_samples ()
                            total_time));
 }
 
+/* Calls 'hist_assign_sampes_1' for all histogram records read so far. */
+void
+hist_assign_samples ()
+{
+  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.  */
 
@@ -552,3 +659,90 @@ hist_print ()
   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)
+    {
+      if (histograms[i].lowpc <= pc && pc < histograms[i].highpc)
+       return &histograms[i];
+    }
+  return 0;  
+}
index 96624c6..4ed6958 100644 (file)
@@ -21,20 +21,37 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
 #ifndef hist_h
 #define hist_h
 
-extern bfd_vma s_lowpc;                /* Lowpc from the profile file.  */
-extern bfd_vma s_highpc;       /* Highpc from the profile file.  */
-extern bfd_vma lowpc, highpc;  /* Range profiled, in UNIT's.  */
-extern unsigned int hist_num_bins; /* Number of histogram bins.  */
-extern int *hist_sample;       /* Code histogram.  */
+typedef struct histogram
+{
+  bfd_vma lowpc;
+  bfd_vma highpc;
+  unsigned int num_bins;
+  int *sample;           /* Histogram samples (shorts in the file!).  */
+} histogram;
+
+histogram *histograms;
+unsigned num_histograms;
 
 /* Scale factor converting samples to pc values:
    each sample covers HIST_SCALE bytes.  */
 extern double hist_scale;
 
-
 extern void hist_read_rec        (FILE *, const char *);
 extern void hist_write_hist      (FILE *, const char *);
 extern void hist_assign_samples  (void);
 extern void hist_print           (void);
 
+/* Checks if ADDRESS is within the range of addresses for which
+   we have histogram data.  Returns 1 if so and 0 otherwise.  */
+extern int hist_check_address (unsigned address);
+
+/* Given a range of addresses for a symbol, find a histogram record 
+   that intersects with this range, and clips the range to that
+   histogram record, modifying *P_LOWPC and *P_HIGHPC.
+   
+   If no intersection is found, *P_LOWPC and *P_HIGHPC will be set to
+   one unspecified value.  If more that one intersection is found,
+   an error is emitted.  */
+extern void hist_clip_symbol_address (bfd_vma *p_lowpc, bfd_vma *p_highpc);
+
 #endif /* hist_h */
index 91d38fa..bdf8bd1 100644 (file)
@@ -53,18 +53,6 @@ i386_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
   Sym *child;
   bfd_vma pc, destpc;
 
-  if (core_text_space == 0)
-    {
-      return;
-    }
-  if (p_lowpc < s_lowpc)
-    {
-      p_lowpc = s_lowpc;
-    }
-  if (p_highpc > s_highpc)
-    {
-      p_highpc = s_highpc;
-    }
   DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
                          parent->name, (unsigned long) p_lowpc,
                          (unsigned long) p_highpc));
@@ -83,7 +71,7 @@ i386_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
           */
 
          destpc = bfd_get_32 (core_bfd, instructp + 1) + pc + 5;
-         if (destpc >= s_lowpc && destpc <= s_highpc)
+         if (hist_check_address (destpc))
            {
              child = sym_lookup (&symtab, destpc);
              if (child && child->addr == destpc)
index 96d2707..7a7344d 100644 (file)
@@ -56,24 +56,13 @@ mips_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
       indirect_child.cg.cyc.head = &indirect_child;
     }
 
-  if (!core_text_space)
-    {
-      return;
-    }
-  if (p_lowpc < s_lowpc)
-    {
-      p_lowpc = s_lowpc;
-    }
-  if (p_highpc > s_highpc)
-    {
-      p_highpc = s_highpc;
-    }
   DBG (CALLDEBUG, printf (_("[find_call] %s: 0x%lx to 0x%lx\n"),
                          parent->name, (unsigned long) p_lowpc,
                          (unsigned long) p_highpc));
   for (pc = p_lowpc; pc < p_highpc; pc += 4)
     {
-      op = bfd_get_32 (core_bfd, &((char *)core_text_space)[pc - s_lowpc]);
+      op = bfd_get_32 (core_bfd, ((unsigned char *)core_text_space
+                                 + pc - core_text_sect->vma));
       if ((op & 0xfc000000) == 0x0c000000)
        {
          /* This is a "jal" instruction.  Check that the destination
@@ -82,7 +71,7 @@ mips_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
               printf (_("[find_call] 0x%lx: jal"), (unsigned long) pc));
           offset = (op & 0x03ffffff) << 2;
          dest_pc = (pc & ~(bfd_vma) 0xfffffff) | offset;
-         if (dest_pc >= s_lowpc && dest_pc <= s_highpc)
+         if (hist_check_address (dest_pc))
            {
              child = sym_lookup (&symtab, dest_pc);
              DBG (CALLDEBUG,
index 685db2f..47592d8 100644 (file)
@@ -48,18 +48,6 @@ sparc_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
   unsigned int insn;
   Sym *child;
 
-  if (core_text_space == 0)
-    {
-      return;
-    }
-  if (p_lowpc < s_lowpc)
-    {
-      p_lowpc = s_lowpc;
-    }
-  if (p_highpc > s_highpc)
-    {
-      p_highpc = s_highpc;
-    }
   DBG (CALLDEBUG, printf ("[find_call] %s: 0x%lx to 0x%lx\n",
                          parent->name, (unsigned long) p_lowpc,
                          (unsigned long) p_highpc));
@@ -77,7 +65,7 @@ sparc_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
           */
          dest_pc = pc + (((bfd_signed_vma) (insn & 0x3fffffff)
                           ^ 0x20000000) - 0x20000000);
-         if (dest_pc >= s_lowpc && dest_pc <= s_highpc)
+         if (hist_check_address (dest_pc))
            {
              child = sym_lookup (&symtab, dest_pc);
              DBG (CALLDEBUG,
index de94db6..c1d9c42 100644 (file)
@@ -235,18 +235,6 @@ tahoe_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
       indirectchild.cg.cyc.head = &indirectchild;
     }
 
-  if (core_text_space == 0)
-    {
-      return;
-    }
-  if (p_lowpc < s_lowpc)
-    {
-      p_lowpc = s_lowpc;
-    }
-  if (p_highpc > s_highpc)
-    {
-      p_highpc = s_highpc;
-    }
   DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
                          parent->name, (unsigned long) p_lowpc,
                          (unsigned long) p_highpc));
@@ -307,7 +295,7 @@ tahoe_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
               *      a function.
               */
              destpc = pc + tahoe_offset (instructp + length);
-             if (destpc >= s_lowpc && destpc <= s_highpc)
+             if (hist_check_address (destpc))
                {
                  child = sym_lookup (&symtab, destpc);
                  DBG (CALLDEBUG,
index 6216589..a6904c1 100644 (file)
@@ -247,18 +247,6 @@ vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
       indirectchild.cg.cyc.head = &indirectchild;
     }
 
-  if (core_text_space == 0)
-    {
-      return;
-    }
-  if (p_lowpc < s_lowpc)
-    {
-      p_lowpc = s_lowpc;
-    }
-  if (p_highpc > s_highpc)
-    {
-      p_highpc = s_highpc;
-    }
   DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
                          parent->name, (unsigned long) p_lowpc,
                          (unsigned long) p_highpc));
@@ -318,7 +306,7 @@ vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
               *      a function.
               */
              destpc = pc + vax_offset (instructp + length);
-             if (destpc >= s_lowpc && destpc <= s_highpc)
+             if (hist_check_address (destpc))
                {
                  child = sym_lookup (&symtab, destpc);
                  DBG (CALLDEBUG,