mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-23 12:09:49 +00:00
* 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.
This commit is contained in:
parent
8e77c9de92
commit
b3296dc54c
@ -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>
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
372
gprof/hist.c
372
gprof/hist.c
@ -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;
|
||||
unsigned int profrate;
|
||||
char n_hist_dimension[15];
|
||||
char n_hist_dimension_abbrev;
|
||||
double n_hist_scale;
|
||||
|
||||
if (gmon_io_read_vma (ifp, &n_lowpc)
|
||||
|| gmon_io_read_vma (ifp, &n_highpc)
|
||||
|| gmon_io_read_32 (ifp, &ncnt)
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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. */
|
||||
|
||||
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)
|
||||
{
|
||||
fprintf (stderr, _("%s: `%s' is incompatible with first gmon file\n"),
|
||||
whoami, filename);
|
||||
done (1);
|
||||
}
|
||||
|
||||
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)
|
||||
(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;
|
||||
unsigned int i, r;
|
||||
|
||||
/* 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))
|
||||
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, (bfd_vma) 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
|
||||
@ -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;
|
||||
}
|
||||
|
29
gprof/hist.h
29
gprof/hist.h
@ -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 */
|
||||
|
14
gprof/i386.c
14
gprof/i386.c
@ -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)
|
||||
|
17
gprof/mips.c
17
gprof/mips.c
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
14
gprof/vax.c
14
gprof/vax.c
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user