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