This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [gprof] disjoint histograms


On Friday 23 February 2007 14:52, Daniel Jacobowitz wrote:
> On Fri, Feb 23, 2007 at 11:15:50AM +0300, Vladimir Prus wrote:
> > I certainly can update both NEWS and gprof.texi and post a new patch.
> > I'll do that in a couple of days provided no objections to the
> > code patch itself will show up.
> 
> It looks fine to me, except for two things: one "// FIXME" and two places
> where you use malloc or realloc instead of xmalloc / xrealloc.  You
> can also delete the casts of the malloc return value - now that we
> assume c89 they're no longer necessary.

Here's a patch that addresses the above points, and adds
a note to NEWS and modifies gprof.texi.

OK?

- Volodya


Attachment: multiple_histograms.ChangeLog
Description: Text document

Index: gprof/alpha.c
===================================================================
RCS file: /cvs/src/src/gprof/alpha.c,v
retrieving revision 1.9
diff -u -p -r1.9 alpha.c
--- gprof/alpha.c	20 Jan 2005 23:37:57 -0000	1.9
+++ gprof/alpha.c	15 Mar 2007 12:56:08 -0000
@@ -104,18 +104,6 @@ alpha_find_call (Sym *parent, bfd_vma p_
       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_
 	   */
 	  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: gprof/corefile.c
===================================================================
RCS file: /cvs/src/src/gprof/corefile.c,v
retrieving revision 1.25
diff -u -p -r1.25 corefile.c
--- gprof/corefile.c	15 Jan 2007 23:26:08 -0000	1.25
+++ gprof/corefile.c	15 Mar 2007 12:56:10 -0000
@@ -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: gprof/gmon_io.c
===================================================================
RCS file: /cvs/src/src/gprof/gmon_io.c,v
retrieving revision 1.22
diff -u -p -r1.22 gmon_io.c
--- gprof/gmon_io.c	9 May 2005 06:55:24 -0000	1.22
+++ gprof/gmon_io.c	15 Mar 2007 12:56:10 -0000
@@ -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: gprof/gprof.texi
===================================================================
RCS file: /cvs/src/src/gprof/gprof.texi,v
retrieving revision 1.21
diff -u -p -r1.21 gprof.texi
--- gprof/gprof.texi	17 Oct 2006 16:19:19 -0000	1.21
+++ gprof/gprof.texi	15 Mar 2007 12:56:12 -0000
@@ -2067,11 +2067,12 @@ New-style histogram records are read by 
 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: gprof/hist.c
===================================================================
RCS file: /cvs/src/src/gprof/hist.c,v
retrieving revision 1.15
diff -u -p -r1.15 hist.c
--- gprof/hist.c	9 May 2005 06:55:25 -0000	1.15
+++ gprof/hist.c	15 Mar 2007 12:56:12 -0000
@@ -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 PT
 /* 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 */
 };
 
-
-/* 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)
+/* 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 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 *f
       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;      
     }
+  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);
+	}
 
-  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_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);	  
+	}
 
-  if (n_lowpc != s_lowpc || n_highpc != s_highpc
-      || ncnt != hist_num_bins || hz != (int) profrate)
-    {
-      fprintf (stderr, _("%s: `%s' is incompatible with first gmon file\n"),
-	       whoami, filename);
-      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]));
+    }
+
+  /* 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.  */
 
-  for (i = 0; i < hist_num_bins; ++i)
+  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.  */
-
-  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))
-    {
-      perror (filename);
-      done (1);
-    }
+  unsigned int i, r;
 
-  for (i = 0; i < hist_num_bins; ++i)
+  for (r = 0; r < num_histograms; ++r)
     {
-      bfd_put_16 (core_bfd, (bfd_vma) hist_sample[i], (bfd_byte *) &count[0]);
+      histogram *record = &histograms[r];
 
-      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
@@ -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: gprof/hist.h
===================================================================
RCS file: /cvs/src/src/gprof/hist.h,v
retrieving revision 1.8
diff -u -p -r1.8 hist.h
--- gprof/hist.h	9 May 2005 06:55:25 -0000	1.8
+++ gprof/hist.h	15 Mar 2007 12:56:12 -0000
@@ -21,20 +21,37 @@ Foundation, Inc., 51 Franklin Street - F
 #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: gprof/i386.c
===================================================================
RCS file: /cvs/src/src/gprof/i386.c,v
retrieving revision 1.9
diff -u -p -r1.9 i386.c
--- gprof/i386.c	26 May 2004 04:55:55 -0000	1.9
+++ gprof/i386.c	15 Mar 2007 12:56:12 -0000
@@ -53,18 +53,6 @@ i386_find_call (Sym *parent, bfd_vma p_l
   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_l
 	   */
 
 	  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: gprof/mips.c
===================================================================
RCS file: /cvs/src/src/gprof/mips.c,v
retrieving revision 1.7
diff -u -p -r1.7 mips.c
--- gprof/mips.c	26 May 2004 04:55:55 -0000	1.7
+++ gprof/mips.c	15 Mar 2007 12:56:13 -0000
@@ -56,24 +56,13 @@ mips_find_call (Sym *parent, bfd_vma p_l
       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_l
 	       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: gprof/sparc.c
===================================================================
RCS file: /cvs/src/src/gprof/sparc.c,v
retrieving revision 1.8
diff -u -p -r1.8 sparc.c
--- gprof/sparc.c	26 May 2004 04:55:55 -0000	1.8
+++ gprof/sparc.c	15 Mar 2007 12:56:13 -0000
@@ -48,18 +48,6 @@ sparc_find_call (Sym *parent, bfd_vma p_
   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_
 	   */
 	  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: gprof/tahoe.c
===================================================================
RCS file: /cvs/src/src/gprof/tahoe.c,v
retrieving revision 1.11
diff -u -p -r1.11 tahoe.c
--- gprof/tahoe.c	26 May 2004 04:55:55 -0000	1.11
+++ gprof/tahoe.c	15 Mar 2007 12:56:13 -0000
@@ -235,18 +235,6 @@ tahoe_find_call (Sym *parent, bfd_vma p_
       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_
 	       *      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: gprof/vax.c
===================================================================
RCS file: /cvs/src/src/gprof/vax.c,v
retrieving revision 1.12
diff -u -p -r1.12 vax.c
--- gprof/vax.c	20 Jan 2005 23:37:57 -0000	1.12
+++ gprof/vax.c	15 Mar 2007 12:56:13 -0000
@@ -247,18 +247,6 @@ vax_find_call (Sym *parent, bfd_vma p_lo
       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_lo
 	       *      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,
Index: binutils/NEWS
===================================================================
RCS file: /cvs/src/src/binutils/NEWS,v
retrieving revision 1.57
diff -u -p -r1.57 NEWS
--- binutils/NEWS	14 Nov 2005 15:00:30 -0000	1.57
+++ binutils/NEWS	15 Mar 2007 12:56:13 -0000
@@ -30,6 +30,9 @@
 
 * Add "--globalize-symbol <name>" and "--globalize-symbols <filename>" switches
   to objcopy to convert local symbols into global symbols.
+  
+* gprof now allows input files to have histogram records for
+  several memory ranges, provided those ranges are disjoint.  
 
 Changes in 2.16:
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]