1*3d8817e4Smiod /* hist.c - Histogram related operations.
2*3d8817e4Smiod
3*3d8817e4Smiod Copyright 1999, 2000, 2001, 2002, 2004, 2005
4*3d8817e4Smiod Free Software Foundation, Inc.
5*3d8817e4Smiod
6*3d8817e4Smiod This file is part of GNU Binutils.
7*3d8817e4Smiod
8*3d8817e4Smiod This program is free software; you can redistribute it and/or modify
9*3d8817e4Smiod it under the terms of the GNU General Public License as published by
10*3d8817e4Smiod the Free Software Foundation; either version 2 of the License, or
11*3d8817e4Smiod (at your option) any later version.
12*3d8817e4Smiod
13*3d8817e4Smiod This program is distributed in the hope that it will be useful,
14*3d8817e4Smiod but WITHOUT ANY WARRANTY; without even the implied warranty of
15*3d8817e4Smiod MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*3d8817e4Smiod GNU General Public License for more details.
17*3d8817e4Smiod
18*3d8817e4Smiod You should have received a copy of the GNU General Public License
19*3d8817e4Smiod along with this program; if not, write to the Free Software
20*3d8817e4Smiod Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21*3d8817e4Smiod 02110-1301, USA. */
22*3d8817e4Smiod
23*3d8817e4Smiod #include "libiberty.h"
24*3d8817e4Smiod #include "gprof.h"
25*3d8817e4Smiod #include "search_list.h"
26*3d8817e4Smiod #include "source.h"
27*3d8817e4Smiod #include "symtab.h"
28*3d8817e4Smiod #include "corefile.h"
29*3d8817e4Smiod #include "gmon_io.h"
30*3d8817e4Smiod #include "gmon_out.h"
31*3d8817e4Smiod #include "hist.h"
32*3d8817e4Smiod #include "sym_ids.h"
33*3d8817e4Smiod #include "utils.h"
34*3d8817e4Smiod
35*3d8817e4Smiod #define UNITS_TO_CODE (offset_to_code / sizeof(UNIT))
36*3d8817e4Smiod
37*3d8817e4Smiod static void scale_and_align_entries (void);
38*3d8817e4Smiod static void print_header (int);
39*3d8817e4Smiod static void print_line (Sym *, double);
40*3d8817e4Smiod static int cmp_time (const PTR, const PTR);
41*3d8817e4Smiod
42*3d8817e4Smiod /* Declarations of automatically generated functions to output blurbs. */
43*3d8817e4Smiod extern void flat_blurb (FILE * fp);
44*3d8817e4Smiod
45*3d8817e4Smiod bfd_vma s_lowpc; /* Lowest address in .text. */
46*3d8817e4Smiod bfd_vma s_highpc = 0; /* Highest address in .text. */
47*3d8817e4Smiod bfd_vma lowpc, highpc; /* Same, but expressed in UNITs. */
48*3d8817e4Smiod unsigned int hist_num_bins = 0; /* Number of histogram samples. */
49*3d8817e4Smiod int *hist_sample = 0; /* Histogram samples (shorts in the file!). */
50*3d8817e4Smiod double hist_scale;
51*3d8817e4Smiod static char hist_dimension[16] = "seconds";
52*3d8817e4Smiod static char hist_dimension_abbrev = 's';
53*3d8817e4Smiod
54*3d8817e4Smiod static double accum_time; /* Accumulated time so far for print_line(). */
55*3d8817e4Smiod static double total_time; /* Total time for all routines. */
56*3d8817e4Smiod
57*3d8817e4Smiod /* Table of SI prefixes for powers of 10 (used to automatically
58*3d8817e4Smiod scale some of the values in the flat profile). */
59*3d8817e4Smiod const struct
60*3d8817e4Smiod {
61*3d8817e4Smiod char prefix;
62*3d8817e4Smiod double scale;
63*3d8817e4Smiod }
64*3d8817e4Smiod SItab[] =
65*3d8817e4Smiod {
66*3d8817e4Smiod { 'T', 1e-12 }, /* tera */
67*3d8817e4Smiod { 'G', 1e-09 }, /* giga */
68*3d8817e4Smiod { 'M', 1e-06 }, /* mega */
69*3d8817e4Smiod { 'K', 1e-03 }, /* kilo */
70*3d8817e4Smiod { ' ', 1e-00 },
71*3d8817e4Smiod { 'm', 1e+03 }, /* milli */
72*3d8817e4Smiod { 'u', 1e+06 }, /* micro */
73*3d8817e4Smiod { 'n', 1e+09 }, /* nano */
74*3d8817e4Smiod { 'p', 1e+12 }, /* pico */
75*3d8817e4Smiod { 'f', 1e+15 }, /* femto */
76*3d8817e4Smiod { 'a', 1e+18 } /* ato */
77*3d8817e4Smiod };
78*3d8817e4Smiod
79*3d8817e4Smiod
80*3d8817e4Smiod /* Read the histogram from file IFP. FILENAME is the name of IFP and
81*3d8817e4Smiod is provided for formatting error messages only. */
82*3d8817e4Smiod
83*3d8817e4Smiod void
hist_read_rec(FILE * ifp,const char * filename)84*3d8817e4Smiod hist_read_rec (FILE * ifp, const char *filename)
85*3d8817e4Smiod {
86*3d8817e4Smiod bfd_vma n_lowpc, n_highpc;
87*3d8817e4Smiod unsigned int i, ncnt, profrate;
88*3d8817e4Smiod UNIT count;
89*3d8817e4Smiod
90*3d8817e4Smiod if (gmon_io_read_vma (ifp, &n_lowpc)
91*3d8817e4Smiod || gmon_io_read_vma (ifp, &n_highpc)
92*3d8817e4Smiod || gmon_io_read_32 (ifp, &ncnt)
93*3d8817e4Smiod || gmon_io_read_32 (ifp, &profrate)
94*3d8817e4Smiod || gmon_io_read (ifp, hist_dimension, 15)
95*3d8817e4Smiod || gmon_io_read (ifp, &hist_dimension_abbrev, 1))
96*3d8817e4Smiod {
97*3d8817e4Smiod fprintf (stderr, _("%s: %s: unexpected end of file\n"),
98*3d8817e4Smiod whoami, filename);
99*3d8817e4Smiod
100*3d8817e4Smiod done (1);
101*3d8817e4Smiod }
102*3d8817e4Smiod
103*3d8817e4Smiod if (!s_highpc)
104*3d8817e4Smiod {
105*3d8817e4Smiod /* This is the first histogram record. */
106*3d8817e4Smiod s_lowpc = n_lowpc;
107*3d8817e4Smiod s_highpc = n_highpc;
108*3d8817e4Smiod lowpc = (bfd_vma) n_lowpc / sizeof (UNIT);
109*3d8817e4Smiod highpc = (bfd_vma) n_highpc / sizeof (UNIT);
110*3d8817e4Smiod hist_num_bins = ncnt;
111*3d8817e4Smiod hz = profrate;
112*3d8817e4Smiod }
113*3d8817e4Smiod
114*3d8817e4Smiod DBG (SAMPLEDEBUG,
115*3d8817e4Smiod printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %u\n",
116*3d8817e4Smiod (unsigned long) n_lowpc, (unsigned long) n_highpc, ncnt);
117*3d8817e4Smiod printf ("[hist_read_rec] s_lowpc 0x%lx s_highpc 0x%lx nsamples %u\n",
118*3d8817e4Smiod (unsigned long) s_lowpc, (unsigned long) s_highpc,
119*3d8817e4Smiod hist_num_bins);
120*3d8817e4Smiod printf ("[hist_read_rec] lowpc 0x%lx highpc 0x%lx\n",
121*3d8817e4Smiod (unsigned long) lowpc, (unsigned long) highpc));
122*3d8817e4Smiod
123*3d8817e4Smiod if (n_lowpc != s_lowpc || n_highpc != s_highpc
124*3d8817e4Smiod || ncnt != hist_num_bins || hz != (int) profrate)
125*3d8817e4Smiod {
126*3d8817e4Smiod fprintf (stderr, _("%s: `%s' is incompatible with first gmon file\n"),
127*3d8817e4Smiod whoami, filename);
128*3d8817e4Smiod done (1);
129*3d8817e4Smiod }
130*3d8817e4Smiod
131*3d8817e4Smiod if (!hist_sample)
132*3d8817e4Smiod {
133*3d8817e4Smiod hist_sample = (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0]));
134*3d8817e4Smiod memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0]));
135*3d8817e4Smiod }
136*3d8817e4Smiod
137*3d8817e4Smiod for (i = 0; i < hist_num_bins; ++i)
138*3d8817e4Smiod {
139*3d8817e4Smiod if (fread (&count[0], sizeof (count), 1, ifp) != 1)
140*3d8817e4Smiod {
141*3d8817e4Smiod fprintf (stderr,
142*3d8817e4Smiod _("%s: %s: unexpected EOF after reading %u of %u samples\n"),
143*3d8817e4Smiod whoami, filename, i, hist_num_bins);
144*3d8817e4Smiod done (1);
145*3d8817e4Smiod }
146*3d8817e4Smiod hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]);
147*3d8817e4Smiod DBG (SAMPLEDEBUG,
148*3d8817e4Smiod printf ("[hist_read_rec] 0x%lx: %u\n",
149*3d8817e4Smiod (unsigned long) (n_lowpc + i * (n_highpc - n_lowpc) / ncnt),
150*3d8817e4Smiod hist_sample[i]));
151*3d8817e4Smiod }
152*3d8817e4Smiod }
153*3d8817e4Smiod
154*3d8817e4Smiod
155*3d8817e4Smiod /* Write execution histogram to file OFP. FILENAME is the name
156*3d8817e4Smiod of OFP and is provided for formatting error-messages only. */
157*3d8817e4Smiod
158*3d8817e4Smiod void
hist_write_hist(FILE * ofp,const char * filename)159*3d8817e4Smiod hist_write_hist (FILE * ofp, const char *filename)
160*3d8817e4Smiod {
161*3d8817e4Smiod UNIT count;
162*3d8817e4Smiod unsigned int i;
163*3d8817e4Smiod
164*3d8817e4Smiod /* Write header. */
165*3d8817e4Smiod
166*3d8817e4Smiod if (gmon_io_write_8 (ofp, GMON_TAG_TIME_HIST)
167*3d8817e4Smiod || gmon_io_write_vma (ofp, s_lowpc)
168*3d8817e4Smiod || gmon_io_write_vma (ofp, s_highpc)
169*3d8817e4Smiod || gmon_io_write_32 (ofp, hist_num_bins)
170*3d8817e4Smiod || gmon_io_write_32 (ofp, hz)
171*3d8817e4Smiod || gmon_io_write (ofp, hist_dimension, 15)
172*3d8817e4Smiod || gmon_io_write (ofp, &hist_dimension_abbrev, 1))
173*3d8817e4Smiod {
174*3d8817e4Smiod perror (filename);
175*3d8817e4Smiod done (1);
176*3d8817e4Smiod }
177*3d8817e4Smiod
178*3d8817e4Smiod for (i = 0; i < hist_num_bins; ++i)
179*3d8817e4Smiod {
180*3d8817e4Smiod bfd_put_16 (core_bfd, (bfd_vma) hist_sample[i], (bfd_byte *) &count[0]);
181*3d8817e4Smiod
182*3d8817e4Smiod if (fwrite (&count[0], sizeof (count), 1, ofp) != 1)
183*3d8817e4Smiod {
184*3d8817e4Smiod perror (filename);
185*3d8817e4Smiod done (1);
186*3d8817e4Smiod }
187*3d8817e4Smiod }
188*3d8817e4Smiod }
189*3d8817e4Smiod
190*3d8817e4Smiod
191*3d8817e4Smiod /* Calculate scaled entry point addresses (to save time in
192*3d8817e4Smiod hist_assign_samples), and, on architectures that have procedure
193*3d8817e4Smiod entry masks at the start of a function, possibly push the scaled
194*3d8817e4Smiod entry points over the procedure entry mask, if it turns out that
195*3d8817e4Smiod the entry point is in one bin and the code for a routine is in the
196*3d8817e4Smiod next bin. */
197*3d8817e4Smiod
198*3d8817e4Smiod static void
scale_and_align_entries()199*3d8817e4Smiod scale_and_align_entries ()
200*3d8817e4Smiod {
201*3d8817e4Smiod Sym *sym;
202*3d8817e4Smiod bfd_vma bin_of_entry;
203*3d8817e4Smiod bfd_vma bin_of_code;
204*3d8817e4Smiod
205*3d8817e4Smiod for (sym = symtab.base; sym < symtab.limit; sym++)
206*3d8817e4Smiod {
207*3d8817e4Smiod sym->hist.scaled_addr = sym->addr / sizeof (UNIT);
208*3d8817e4Smiod bin_of_entry = (sym->hist.scaled_addr - lowpc) / hist_scale;
209*3d8817e4Smiod bin_of_code = ((sym->hist.scaled_addr + UNITS_TO_CODE - lowpc)
210*3d8817e4Smiod / hist_scale);
211*3d8817e4Smiod if (bin_of_entry < bin_of_code)
212*3d8817e4Smiod {
213*3d8817e4Smiod DBG (SAMPLEDEBUG,
214*3d8817e4Smiod printf ("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
215*3d8817e4Smiod (unsigned long) sym->hist.scaled_addr,
216*3d8817e4Smiod (unsigned long) (sym->hist.scaled_addr
217*3d8817e4Smiod + UNITS_TO_CODE)));
218*3d8817e4Smiod sym->hist.scaled_addr += UNITS_TO_CODE;
219*3d8817e4Smiod }
220*3d8817e4Smiod }
221*3d8817e4Smiod }
222*3d8817e4Smiod
223*3d8817e4Smiod
224*3d8817e4Smiod /* Assign samples to the symbol to which they belong.
225*3d8817e4Smiod
226*3d8817e4Smiod Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
227*3d8817e4Smiod which may overlap one more symbol address ranges. If a symbol
228*3d8817e4Smiod overlaps with the bin's address range by O percent, then O percent
229*3d8817e4Smiod of the bin's count is credited to that symbol.
230*3d8817e4Smiod
231*3d8817e4Smiod There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
232*3d8817e4Smiod with respect to the symbol's address range [SYM_LOW_PC,
233*3d8817e4Smiod SYM_HIGH_PC) as shown in the following diagram. OVERLAP computes
234*3d8817e4Smiod the distance (in UNITs) between the arrows, the fraction of the
235*3d8817e4Smiod sample that is to be credited to the symbol which starts at
236*3d8817e4Smiod SYM_LOW_PC.
237*3d8817e4Smiod
238*3d8817e4Smiod sym_low_pc sym_high_pc
239*3d8817e4Smiod | |
240*3d8817e4Smiod v v
241*3d8817e4Smiod
242*3d8817e4Smiod +-----------------------------------------------+
243*3d8817e4Smiod | |
244*3d8817e4Smiod | ->| |<- ->| |<- ->| |<- |
245*3d8817e4Smiod | | | | | |
246*3d8817e4Smiod +---------+ +---------+ +---------+
247*3d8817e4Smiod
248*3d8817e4Smiod ^ ^ ^ ^ ^ ^
249*3d8817e4Smiod | | | | | |
250*3d8817e4Smiod bin_low_pc bin_high_pc bin_low_pc bin_high_pc bin_low_pc bin_high_pc
251*3d8817e4Smiod
252*3d8817e4Smiod For the VAX we assert that samples will never fall in the first two
253*3d8817e4Smiod bytes of any routine, since that is the entry mask, thus we call
254*3d8817e4Smiod scale_and_align_entries() to adjust the entry points if the entry
255*3d8817e4Smiod mask falls in one bin but the code for the routine doesn't start
256*3d8817e4Smiod until the next bin. In conjunction with the alignment of routine
257*3d8817e4Smiod addresses, this should allow us to have only one sample for every
258*3d8817e4Smiod four bytes of text space and never have any overlap (the two end
259*3d8817e4Smiod cases, above). */
260*3d8817e4Smiod
261*3d8817e4Smiod void
hist_assign_samples()262*3d8817e4Smiod hist_assign_samples ()
263*3d8817e4Smiod {
264*3d8817e4Smiod bfd_vma bin_low_pc, bin_high_pc;
265*3d8817e4Smiod bfd_vma sym_low_pc, sym_high_pc;
266*3d8817e4Smiod bfd_vma overlap, addr;
267*3d8817e4Smiod unsigned int bin_count;
268*3d8817e4Smiod unsigned int i, j;
269*3d8817e4Smiod double time, credit;
270*3d8817e4Smiod
271*3d8817e4Smiod /* Read samples and assign to symbols. */
272*3d8817e4Smiod hist_scale = highpc - lowpc;
273*3d8817e4Smiod hist_scale /= hist_num_bins;
274*3d8817e4Smiod scale_and_align_entries ();
275*3d8817e4Smiod
276*3d8817e4Smiod /* Iterate over all sample bins. */
277*3d8817e4Smiod for (i = 0, j = 1; i < hist_num_bins; ++i)
278*3d8817e4Smiod {
279*3d8817e4Smiod bin_count = hist_sample[i];
280*3d8817e4Smiod if (! bin_count)
281*3d8817e4Smiod continue;
282*3d8817e4Smiod
283*3d8817e4Smiod bin_low_pc = lowpc + (bfd_vma) (hist_scale * i);
284*3d8817e4Smiod bin_high_pc = lowpc + (bfd_vma) (hist_scale * (i + 1));
285*3d8817e4Smiod time = bin_count;
286*3d8817e4Smiod
287*3d8817e4Smiod DBG (SAMPLEDEBUG,
288*3d8817e4Smiod printf (
289*3d8817e4Smiod "[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%u\n",
290*3d8817e4Smiod (unsigned long) (sizeof (UNIT) * bin_low_pc),
291*3d8817e4Smiod (unsigned long) (sizeof (UNIT) * bin_high_pc),
292*3d8817e4Smiod bin_count));
293*3d8817e4Smiod total_time += time;
294*3d8817e4Smiod
295*3d8817e4Smiod /* Credit all symbols that are covered by bin I. */
296*3d8817e4Smiod for (j = j - 1; j < symtab.len; ++j)
297*3d8817e4Smiod {
298*3d8817e4Smiod sym_low_pc = symtab.base[j].hist.scaled_addr;
299*3d8817e4Smiod sym_high_pc = symtab.base[j + 1].hist.scaled_addr;
300*3d8817e4Smiod
301*3d8817e4Smiod /* If high end of bin is below entry address,
302*3d8817e4Smiod go for next bin. */
303*3d8817e4Smiod if (bin_high_pc < sym_low_pc)
304*3d8817e4Smiod break;
305*3d8817e4Smiod
306*3d8817e4Smiod /* If low end of bin is above high end of symbol,
307*3d8817e4Smiod go for next symbol. */
308*3d8817e4Smiod if (bin_low_pc >= sym_high_pc)
309*3d8817e4Smiod continue;
310*3d8817e4Smiod
311*3d8817e4Smiod overlap =
312*3d8817e4Smiod MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc);
313*3d8817e4Smiod if (overlap > 0)
314*3d8817e4Smiod {
315*3d8817e4Smiod DBG (SAMPLEDEBUG,
316*3d8817e4Smiod printf (
317*3d8817e4Smiod "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
318*3d8817e4Smiod (unsigned long) symtab.base[j].addr,
319*3d8817e4Smiod (unsigned long) (sizeof (UNIT) * sym_high_pc),
320*3d8817e4Smiod symtab.base[j].name, overlap * time / hist_scale,
321*3d8817e4Smiod (long) overlap));
322*3d8817e4Smiod
323*3d8817e4Smiod addr = symtab.base[j].addr;
324*3d8817e4Smiod credit = overlap * time / hist_scale;
325*3d8817e4Smiod
326*3d8817e4Smiod /* Credit symbol if it appears in INCL_FLAT or that
327*3d8817e4Smiod table is empty and it does not appear it in
328*3d8817e4Smiod EXCL_FLAT. */
329*3d8817e4Smiod if (sym_lookup (&syms[INCL_FLAT], addr)
330*3d8817e4Smiod || (syms[INCL_FLAT].len == 0
331*3d8817e4Smiod && !sym_lookup (&syms[EXCL_FLAT], addr)))
332*3d8817e4Smiod {
333*3d8817e4Smiod symtab.base[j].hist.time += credit;
334*3d8817e4Smiod }
335*3d8817e4Smiod else
336*3d8817e4Smiod {
337*3d8817e4Smiod total_time -= credit;
338*3d8817e4Smiod }
339*3d8817e4Smiod }
340*3d8817e4Smiod }
341*3d8817e4Smiod }
342*3d8817e4Smiod
343*3d8817e4Smiod DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n",
344*3d8817e4Smiod total_time));
345*3d8817e4Smiod }
346*3d8817e4Smiod
347*3d8817e4Smiod
348*3d8817e4Smiod /* Print header for flag histogram profile. */
349*3d8817e4Smiod
350*3d8817e4Smiod static void
print_header(int prefix)351*3d8817e4Smiod print_header (int prefix)
352*3d8817e4Smiod {
353*3d8817e4Smiod char unit[64];
354*3d8817e4Smiod
355*3d8817e4Smiod sprintf (unit, _("%c%c/call"), prefix, hist_dimension_abbrev);
356*3d8817e4Smiod
357*3d8817e4Smiod if (bsd_style_output)
358*3d8817e4Smiod {
359*3d8817e4Smiod printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
360*3d8817e4Smiod (long) hist_scale * sizeof (UNIT));
361*3d8817e4Smiod if (total_time > 0.0)
362*3d8817e4Smiod {
363*3d8817e4Smiod printf (_(" for %.2f%% of %.2f %s\n\n"),
364*3d8817e4Smiod 100.0 / total_time, total_time / hz, hist_dimension);
365*3d8817e4Smiod }
366*3d8817e4Smiod }
367*3d8817e4Smiod else
368*3d8817e4Smiod {
369*3d8817e4Smiod printf (_("\nEach sample counts as %g %s.\n"), 1.0 / hz, hist_dimension);
370*3d8817e4Smiod }
371*3d8817e4Smiod
372*3d8817e4Smiod if (total_time <= 0.0)
373*3d8817e4Smiod {
374*3d8817e4Smiod printf (_(" no time accumulated\n\n"));
375*3d8817e4Smiod
376*3d8817e4Smiod /* This doesn't hurt since all the numerators will be zero. */
377*3d8817e4Smiod total_time = 1.0;
378*3d8817e4Smiod }
379*3d8817e4Smiod
380*3d8817e4Smiod printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
381*3d8817e4Smiod "% ", _("cumulative"), _("self "), "", _("self "), _("total "),
382*3d8817e4Smiod "");
383*3d8817e4Smiod printf ("%5.5s %9.9s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
384*3d8817e4Smiod _("time"), hist_dimension, hist_dimension, _("calls"), unit, unit,
385*3d8817e4Smiod _("name"));
386*3d8817e4Smiod }
387*3d8817e4Smiod
388*3d8817e4Smiod
389*3d8817e4Smiod static void
print_line(Sym * sym,double scale)390*3d8817e4Smiod print_line (Sym *sym, double scale)
391*3d8817e4Smiod {
392*3d8817e4Smiod if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0)
393*3d8817e4Smiod return;
394*3d8817e4Smiod
395*3d8817e4Smiod accum_time += sym->hist.time;
396*3d8817e4Smiod
397*3d8817e4Smiod if (bsd_style_output)
398*3d8817e4Smiod printf ("%5.1f %10.2f %8.2f",
399*3d8817e4Smiod total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
400*3d8817e4Smiod accum_time / hz, sym->hist.time / hz);
401*3d8817e4Smiod else
402*3d8817e4Smiod printf ("%6.2f %9.2f %8.2f",
403*3d8817e4Smiod total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
404*3d8817e4Smiod accum_time / hz, sym->hist.time / hz);
405*3d8817e4Smiod
406*3d8817e4Smiod if (sym->ncalls != 0)
407*3d8817e4Smiod printf (" %8lu %8.2f %8.2f ",
408*3d8817e4Smiod sym->ncalls, scale * sym->hist.time / hz / sym->ncalls,
409*3d8817e4Smiod scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls);
410*3d8817e4Smiod else
411*3d8817e4Smiod printf (" %8.8s %8.8s %8.8s ", "", "", "");
412*3d8817e4Smiod
413*3d8817e4Smiod if (bsd_style_output)
414*3d8817e4Smiod print_name (sym);
415*3d8817e4Smiod else
416*3d8817e4Smiod print_name_only (sym);
417*3d8817e4Smiod
418*3d8817e4Smiod printf ("\n");
419*3d8817e4Smiod }
420*3d8817e4Smiod
421*3d8817e4Smiod
422*3d8817e4Smiod /* Compare LP and RP. The primary comparison key is execution time,
423*3d8817e4Smiod the secondary is number of invocation, and the tertiary is the
424*3d8817e4Smiod lexicographic order of the function names. */
425*3d8817e4Smiod
426*3d8817e4Smiod static int
cmp_time(const PTR lp,const PTR rp)427*3d8817e4Smiod cmp_time (const PTR lp, const PTR rp)
428*3d8817e4Smiod {
429*3d8817e4Smiod const Sym *left = *(const Sym **) lp;
430*3d8817e4Smiod const Sym *right = *(const Sym **) rp;
431*3d8817e4Smiod double time_diff;
432*3d8817e4Smiod
433*3d8817e4Smiod time_diff = right->hist.time - left->hist.time;
434*3d8817e4Smiod
435*3d8817e4Smiod if (time_diff > 0.0)
436*3d8817e4Smiod return 1;
437*3d8817e4Smiod
438*3d8817e4Smiod if (time_diff < 0.0)
439*3d8817e4Smiod return -1;
440*3d8817e4Smiod
441*3d8817e4Smiod if (right->ncalls > left->ncalls)
442*3d8817e4Smiod return 1;
443*3d8817e4Smiod
444*3d8817e4Smiod if (right->ncalls < left->ncalls)
445*3d8817e4Smiod return -1;
446*3d8817e4Smiod
447*3d8817e4Smiod return strcmp (left->name, right->name);
448*3d8817e4Smiod }
449*3d8817e4Smiod
450*3d8817e4Smiod
451*3d8817e4Smiod /* Print the flat histogram profile. */
452*3d8817e4Smiod
453*3d8817e4Smiod void
hist_print()454*3d8817e4Smiod hist_print ()
455*3d8817e4Smiod {
456*3d8817e4Smiod Sym **time_sorted_syms, *top_dog, *sym;
457*3d8817e4Smiod unsigned int index;
458*3d8817e4Smiod unsigned log_scale;
459*3d8817e4Smiod double top_time, time;
460*3d8817e4Smiod bfd_vma addr;
461*3d8817e4Smiod
462*3d8817e4Smiod if (first_output)
463*3d8817e4Smiod first_output = FALSE;
464*3d8817e4Smiod else
465*3d8817e4Smiod printf ("\f\n");
466*3d8817e4Smiod
467*3d8817e4Smiod accum_time = 0.0;
468*3d8817e4Smiod
469*3d8817e4Smiod if (bsd_style_output)
470*3d8817e4Smiod {
471*3d8817e4Smiod if (print_descriptions)
472*3d8817e4Smiod {
473*3d8817e4Smiod printf (_("\n\n\nflat profile:\n"));
474*3d8817e4Smiod flat_blurb (stdout);
475*3d8817e4Smiod }
476*3d8817e4Smiod }
477*3d8817e4Smiod else
478*3d8817e4Smiod {
479*3d8817e4Smiod printf (_("Flat profile:\n"));
480*3d8817e4Smiod }
481*3d8817e4Smiod
482*3d8817e4Smiod /* Sort the symbol table by time (call-count and name as secondary
483*3d8817e4Smiod and tertiary keys). */
484*3d8817e4Smiod time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
485*3d8817e4Smiod
486*3d8817e4Smiod for (index = 0; index < symtab.len; ++index)
487*3d8817e4Smiod time_sorted_syms[index] = &symtab.base[index];
488*3d8817e4Smiod
489*3d8817e4Smiod qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
490*3d8817e4Smiod
491*3d8817e4Smiod if (bsd_style_output)
492*3d8817e4Smiod {
493*3d8817e4Smiod log_scale = 5; /* Milli-seconds is BSD-default. */
494*3d8817e4Smiod }
495*3d8817e4Smiod else
496*3d8817e4Smiod {
497*3d8817e4Smiod /* Search for symbol with highest per-call
498*3d8817e4Smiod execution time and scale accordingly. */
499*3d8817e4Smiod log_scale = 0;
500*3d8817e4Smiod top_dog = 0;
501*3d8817e4Smiod top_time = 0.0;
502*3d8817e4Smiod
503*3d8817e4Smiod for (index = 0; index < symtab.len; ++index)
504*3d8817e4Smiod {
505*3d8817e4Smiod sym = time_sorted_syms[index];
506*3d8817e4Smiod
507*3d8817e4Smiod if (sym->ncalls != 0)
508*3d8817e4Smiod {
509*3d8817e4Smiod time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
510*3d8817e4Smiod
511*3d8817e4Smiod if (time > top_time)
512*3d8817e4Smiod {
513*3d8817e4Smiod top_dog = sym;
514*3d8817e4Smiod top_time = time;
515*3d8817e4Smiod }
516*3d8817e4Smiod }
517*3d8817e4Smiod }
518*3d8817e4Smiod
519*3d8817e4Smiod if (top_dog && top_dog->ncalls != 0 && top_time > 0.0)
520*3d8817e4Smiod {
521*3d8817e4Smiod top_time /= hz;
522*3d8817e4Smiod
523*3d8817e4Smiod for (log_scale = 0; log_scale < ARRAY_SIZE (SItab); log_scale ++)
524*3d8817e4Smiod {
525*3d8817e4Smiod double scaled_value = SItab[log_scale].scale * top_time;
526*3d8817e4Smiod
527*3d8817e4Smiod if (scaled_value >= 1.0 && scaled_value < 1000.0)
528*3d8817e4Smiod break;
529*3d8817e4Smiod }
530*3d8817e4Smiod }
531*3d8817e4Smiod }
532*3d8817e4Smiod
533*3d8817e4Smiod /* For now, the dimension is always seconds. In the future, we
534*3d8817e4Smiod may also want to support other (pseudo-)dimensions (such as
535*3d8817e4Smiod I-cache misses etc.). */
536*3d8817e4Smiod print_header (SItab[log_scale].prefix);
537*3d8817e4Smiod
538*3d8817e4Smiod for (index = 0; index < symtab.len; ++index)
539*3d8817e4Smiod {
540*3d8817e4Smiod addr = time_sorted_syms[index]->addr;
541*3d8817e4Smiod
542*3d8817e4Smiod /* Print symbol if its in INCL_FLAT table or that table
543*3d8817e4Smiod is empty and the symbol is not in EXCL_FLAT. */
544*3d8817e4Smiod if (sym_lookup (&syms[INCL_FLAT], addr)
545*3d8817e4Smiod || (syms[INCL_FLAT].len == 0
546*3d8817e4Smiod && !sym_lookup (&syms[EXCL_FLAT], addr)))
547*3d8817e4Smiod print_line (time_sorted_syms[index], SItab[log_scale].scale);
548*3d8817e4Smiod }
549*3d8817e4Smiod
550*3d8817e4Smiod free (time_sorted_syms);
551*3d8817e4Smiod
552*3d8817e4Smiod if (print_descriptions && !bsd_style_output)
553*3d8817e4Smiod flat_blurb (stdout);
554*3d8817e4Smiod }
555