source: vendor/binutils/current/gprof/basic_blocks.c

Last change on this file was 609, checked in by bird, 22 years ago

binutils v2.14 - offical sources.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 14.7 KB
Line 
1/* basic_blocks.c - Basic-block level related code: reading/writing
2 of basic-block info to/from gmon.out; computing and formatting of
3 basic-block related statistics.
4
5 Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
6
7 This file is part of GNU Binutils.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 02111-1307, USA. */
23
24
25#include "libiberty.h"
26#include "gprof.h"
27#include "basic_blocks.h"
28#include "corefile.h"
29#include "gmon_io.h"
30#include "gmon_out.h"
31#include "search_list.h"
32#include "source.h"
33#include "symtab.h"
34#include "sym_ids.h"
35
36static int cmp_bb PARAMS ((const PTR, const PTR));
37static int cmp_ncalls PARAMS ((const PTR, const PTR));
38static void fskip_string PARAMS ((FILE *));
39static void annotate_with_count PARAMS ((char *, unsigned int, int, PTR));
40
41/* Default option values: */
42bfd_boolean bb_annotate_all_lines = FALSE;
43unsigned long bb_min_calls = 1;
44int bb_table_length = 10;
45
46/* Variables used to compute annotated source listing stats: */
47static long num_executable_lines;
48static long num_lines_executed;
49
50
51/* Helper for sorting. Compares two symbols and returns result
52 such that sorting will be increasing according to filename, line
53 number, and address (in that order). */
54
55static int
56cmp_bb (lp, rp)
57 const PTR lp;
58 const PTR rp;
59{
60 int r;
61 const Sym *left = *(const Sym **) lp;
62 const Sym *right = *(const Sym **) rp;
63
64 if (left->file && right->file)
65 {
66 r = strcmp (left->file->name, right->file->name);
67
68 if (r)
69 return r;
70
71 if (left->line_num != right->line_num)
72 return left->line_num - right->line_num;
73 }
74
75 if (left->addr < right->addr)
76 return -1;
77 else if (left->addr > right->addr)
78 return 1;
79 else
80 return 0;
81}
82
83
84/* Helper for sorting. Order basic blocks in decreasing number of
85 calls, ties are broken in increasing order of line numbers. */
86static int
87cmp_ncalls (lp, rp)
88 const PTR lp;
89 const PTR rp;
90{
91 const Sym *left = *(const Sym **) lp;
92 const Sym *right = *(const Sym **) rp;
93
94 if (!left)
95 return 1;
96 else if (!right)
97 return -1;
98
99 if (left->ncalls < right->ncalls)
100 return 1;
101 else if (left->ncalls > right->ncalls)
102 return -1;
103
104 return left->line_num - right->line_num;
105}
106
107/* Skip over variable length string. */
108static void
109fskip_string (fp)
110 FILE *fp;
111{
112 int ch;
113
114 while ((ch = fgetc (fp)) != EOF)
115 {
116 if (ch == '\0')
117 break;
118 }
119}
120
121/* Read a basic-block record from file IFP. FILENAME is the name
122 of file IFP and is provided for formatting error-messages only. */
123
124void
125bb_read_rec (ifp, filename)
126 FILE *ifp;
127 const char *filename;
128{
129 int nblocks, b;
130 bfd_vma addr, ncalls;
131 Sym *sym;
132
133 if (gmon_io_read_32 (ifp, &nblocks))
134 {
135 fprintf (stderr, _("%s: %s: unexpected end of file\n"),
136 whoami, filename);
137 done (1);
138 }
139
140 nblocks = bfd_get_32 (core_bfd, (bfd_byte *) & nblocks);
141 if (gmon_file_version == 0)
142 fskip_string (ifp);
143
144 for (b = 0; b < nblocks; ++b)
145 {
146 if (gmon_file_version == 0)
147 {
148 int line_num;
149
150 /* Version 0 had lots of extra stuff that we don't
151 care about anymore. */
152 if ((fread (&ncalls, sizeof (ncalls), 1, ifp) != 1)
153 || (fread (&addr, sizeof (addr), 1, ifp) != 1)
154 || (fskip_string (ifp), FALSE)
155 || (fskip_string (ifp), FALSE)
156 || (fread (&line_num, sizeof (line_num), 1, ifp) != 1))
157 {
158 perror (filename);
159 done (1);
160 }
161 }
162 else if (gmon_io_read_vma (ifp, &addr)
163 || gmon_io_read_vma (ifp, &ncalls))
164 {
165 perror (filename);
166 done (1);
167 }
168
169 /* Basic-block execution counts are meaningful only if we're
170 profiling at the line-by-line level: */
171 if (line_granularity)
172 {
173 sym = sym_lookup (&symtab, addr);
174
175 if (sym)
176 {
177 int i;
178
179 DBG (BBDEBUG,
180 printf ("[bb_read_rec] 0x%lx->0x%lx (%s:%d) cnt=%lu\n",
181 (unsigned long) addr, (unsigned long) sym->addr,
182 sym->name, sym->line_num, (unsigned long) ncalls));
183
184 for (i = 0; i < NBBS; i++)
185 {
186 if (! sym->bb_addr[i] || sym->bb_addr[i] == addr)
187 {
188 sym->bb_addr[i] = addr;
189 sym->bb_calls[i] += ncalls;
190 break;
191 }
192 }
193 }
194 }
195 else
196 {
197 static bfd_boolean user_warned = FALSE;
198
199 if (!user_warned)
200 {
201 user_warned = TRUE;
202 fprintf (stderr,
203 _("%s: warning: ignoring basic-block exec counts (use -l or --line)\n"),
204 whoami);
205 }
206 }
207 }
208 return;
209}
210
211/* Write all basic-blocks with non-zero counts to file OFP. FILENAME
212 is the name of OFP and is provided for producing error-messages
213 only. */
214void
215bb_write_blocks (ofp, filename)
216 FILE *ofp;
217 const char *filename;
218{
219 unsigned int nblocks = 0;
220 Sym *sym;
221 int i;
222
223 /* Count how many non-zero blocks with have: */
224 for (sym = symtab.base; sym < symtab.limit; ++sym)
225 {
226 for (i = 0; i < NBBS && sym->bb_addr[i]; i++)
227 ;
228 nblocks += i;
229 }
230
231 /* Write header: */
232 if (gmon_io_write_8 (ofp, GMON_TAG_BB_COUNT)
233 || gmon_io_write_32 (ofp, nblocks))
234 {
235 perror (filename);
236 done (1);
237 }
238
239 /* Write counts: */
240 for (sym = symtab.base; sym < symtab.limit; ++sym)
241 {
242 for (i = 0; i < NBBS && sym->bb_addr[i]; i++)
243 {
244 if (gmon_io_write_vma (ofp, sym->bb_addr[i])
245 || gmon_io_write_vma (ofp, (bfd_vma) sym->bb_calls[i]))
246 {
247 perror (filename);
248 done (1);
249 }
250 }
251 }
252}
253
254/* Output basic-block statistics in a format that is easily parseable.
255 Current the format is:
256
257 <filename>:<line-number>: (<function-name>:<bb-addr): <ncalls> */
258
259void
260print_exec_counts ()
261{
262 Sym **sorted_bbs, *sym;
263 unsigned int i, j, len;
264
265 if (first_output)
266 first_output = FALSE;
267 else
268 printf ("\f\n");
269
270 /* Sort basic-blocks according to function name and line number: */
271 sorted_bbs = (Sym **) xmalloc (symtab.len * sizeof (sorted_bbs[0]));
272 len = 0;
273
274 for (sym = symtab.base; sym < symtab.limit; ++sym)
275 {
276 /* Accept symbol if it's in the INCL_EXEC table
277 or there is no INCL_EXEC table
278 and it does not appear in the EXCL_EXEC table. */
279 if (sym_lookup (&syms[INCL_EXEC], sym->addr)
280 || (syms[INCL_EXEC].len == 0
281 && !sym_lookup (&syms[EXCL_EXEC], sym->addr)))
282 {
283 sorted_bbs[len++] = sym;
284 }
285 }
286
287 qsort (sorted_bbs, len, sizeof (sorted_bbs[0]), cmp_bb);
288
289 /* Output basic-blocks: */
290
291 for (i = 0; i < len; ++i)
292 {
293 if (sym->ncalls > 0 || ! ignore_zeros)
294 {
295 /* FIXME: This only works if bfd_vma is unsigned long. */
296 printf (_("%s:%d: (%s:0x%lx) %lu executions\n"),
297 sym->file ? sym->file->name : _("<unknown>"), sym->line_num,
298 sym->name, (unsigned long) sym->addr, sym->ncalls);
299 }
300
301 for (j = 0; j < NBBS && sym->bb_addr[j]; j ++)
302 {
303 if (sym->bb_calls[j] > 0 || ! ignore_zeros)
304 {
305 /* FIXME: This only works if bfd_vma is unsigned long. */
306 printf (_("%s:%d: (%s:0x%lx) %lu executions\n"),
307 sym->file ? sym->file->name : _("<unknown>"), sym->line_num,
308 sym->name, (unsigned long) sym->bb_addr[j],
309 sym->bb_calls[j]);
310 }
311 }
312 }
313 free (sorted_bbs);
314}
315
316/* Helper for bb_annotated_source: format annotation containing
317 number of line executions. Depends on being called on each
318 line of a file in sequential order.
319
320 Global variable bb_annotate_all_lines enables execution count
321 compression (counts are supressed if identical to the last one)
322 and prints counts on all executed lines. Otherwise, print
323 all basic-block execution counts exactly once on the line
324 that starts the basic-block. */
325
326static void
327annotate_with_count (buf, width, line_num, arg)
328 char *buf;
329 unsigned int width;
330 int line_num;
331 PTR arg;
332{
333 Source_File *sf = arg;
334 Sym *b;
335 unsigned int i;
336 static unsigned long last_count;
337 unsigned long last_print = (unsigned long) -1;
338
339 b = NULL;
340
341 if (line_num <= sf->num_lines)
342 b = sf->line[line_num - 1];
343
344 if (!b)
345 {
346 for (i = 0; i < width; i++)
347 buf[i] = ' ';
348 buf[width] = '\0';
349 }
350 else
351 {
352 char tmpbuf[NBBS * 30];
353 char *p;
354 unsigned long ncalls;
355 int ncalls_set;
356 unsigned int len;
357
358 ++num_executable_lines;
359
360 p = tmpbuf;
361 *p = '\0';
362
363 ncalls = 0;
364 ncalls_set = 0;
365
366 /* If this is a function entry point, label the line no matter what.
367 Otherwise, we're in the middle of a function, so check to see
368 if the first basic-block address is larger than the starting
369 address of the line. If so, then this line begins with a
370 a portion of the previous basic-block, so print that prior
371 execution count (if bb_annotate_all_lines is set). */
372 if (b->is_func)
373 {
374 sprintf (p, "%lu", b->ncalls);
375 p += strlen (p);
376 last_count = b->ncalls;
377 last_print = last_count;
378 ncalls = b->ncalls;
379 ncalls_set = 1;
380 }
381 else if (bb_annotate_all_lines
382 && b->bb_addr[0] && b->bb_addr[0] > b->addr)
383 {
384 sprintf (p, "%lu", last_count);
385 p += strlen (p);
386 last_print = last_count;
387 ncalls = last_count;
388 ncalls_set = 1;
389 }
390
391 /* Loop through all of this line's basic-blocks. For each one,
392 update last_count, then compress sequential identical counts
393 (if bb_annotate_all_lines) and print the execution count. */
394
395 for (i = 0; i < NBBS && b->bb_addr[i]; i++)
396 {
397 last_count = b->bb_calls[i];
398 if (! ncalls_set)
399 {
400 ncalls = 0;
401 ncalls_set = 1;
402 }
403 ncalls += last_count;
404
405 if (bb_annotate_all_lines && last_count == last_print)
406 continue;
407
408 if (p > tmpbuf)
409 *p++ = ',';
410 sprintf (p, "%lu", last_count);
411 p += strlen (p);
412
413 last_print = last_count;
414 }
415
416 /* We're done. If nothing has been printed on this line,
417 print the last execution count (bb_annotate_all_lines),
418 which could be from either a previous line (if there were
419 no BBs on this line), or from this line (if all our BB
420 counts were compressed out because they were identical). */
421
422 if (bb_annotate_all_lines && p == tmpbuf)
423 {
424 sprintf (p, "%lu", last_count);
425 p += strlen (p);
426 ncalls = last_count;
427 ncalls_set = 1;
428 }
429
430 if (! ncalls_set)
431 {
432 unsigned int c;
433
434 for (c = 0; c < width; c++)
435 buf[c] = ' ';
436 buf[width] = '\0';
437 return;
438 }
439
440 ++num_lines_executed;
441
442 if (ncalls < bb_min_calls)
443 {
444 strcpy (tmpbuf, "#####");
445 p = tmpbuf + 5;
446 }
447
448 strcpy (p, " -> ");
449 p += 4;
450
451 len = p - tmpbuf;
452 if (len >= width)
453 {
454 strncpy (buf, tmpbuf, width);
455 buf[width] = '\0';
456 }
457 else
458 {
459 unsigned int c;
460
461 strcpy (buf + width - len, tmpbuf);
462 for (c = 0; c < width - len; ++c)
463 buf[c] = ' ';
464 }
465 }
466}
467
468/* Annotate the files named in SOURCE_FILES with basic-block statistics
469 (execution counts). After each source files, a few statistics
470 regarding that source file are printed. */
471
472void
473print_annotated_source ()
474{
475 Sym *sym, *line_stats, *new_line;
476 Source_File *sf;
477 int i, table_len;
478 FILE *ofp;
479
480 /* Find maximum line number for each source file that user is
481 interested in: */
482 for (sym = symtab.base; sym < symtab.limit; ++sym)
483 {
484 /* Accept symbol if it's file is known, its line number is
485 bigger than anything we have seen for that file so far and
486 if it's in the INCL_ANNO table or there is no INCL_ANNO
487 table and it does not appear in the EXCL_ANNO table. */
488 if (sym->file && sym->line_num > sym->file->num_lines
489 && (sym_lookup (&syms[INCL_ANNO], sym->addr)
490 || (syms[INCL_ANNO].len == 0
491 && !sym_lookup (&syms[EXCL_ANNO], sym->addr))))
492 {
493 sym->file->num_lines = sym->line_num;
494 }
495 }
496
497 /* Allocate line descriptors: */
498 for (sf = first_src_file; sf; sf = sf->next)
499 {
500 if (sf->num_lines > 0)
501 {
502 sf->line = (void *) xmalloc (sf->num_lines * sizeof (sf->line[0]));
503 memset (sf->line, 0, sf->num_lines * sizeof (sf->line[0]));
504 }
505 }
506
507 /* Count executions per line: */
508 for (sym = symtab.base; sym < symtab.limit; ++sym)
509 {
510 if (sym->file && sym->file->num_lines
511 && (sym_lookup (&syms[INCL_ANNO], sym->addr)
512 || (syms[INCL_ANNO].len == 0
513 && !sym_lookup (&syms[EXCL_ANNO], sym->addr))))
514 {
515 sym->file->ncalls += sym->ncalls;
516 line_stats = sym->file->line[sym->line_num - 1];
517
518 if (!line_stats)
519 {
520 /* Common case has at most one basic-block per source line: */
521 sym->file->line[sym->line_num - 1] = sym;
522 }
523 else if (!line_stats->addr)
524 {
525 /* sym is the 3rd .. nth basic block for this line: */
526 line_stats->ncalls += sym->ncalls;
527 }
528 else
529 {
530 /* sym is the second basic block for this line. */
531 new_line = (Sym *) xmalloc (sizeof (*new_line));
532 *new_line = *line_stats;
533 new_line->addr = 0;
534 new_line->ncalls += sym->ncalls;
535 sym->file->line[sym->line_num - 1] = new_line;
536 }
537 }
538 }
539
540 /* Plod over source files, annotating them: */
541 for (sf = first_src_file; sf; sf = sf->next)
542 {
543 if (!sf->num_lines || (ignore_zeros && sf->ncalls == 0))
544 continue;
545
546 num_executable_lines = num_lines_executed = 0;
547
548 ofp = annotate_source (sf, 16, annotate_with_count, sf);
549 if (!ofp)
550 continue;
551
552 if (bb_table_length > 0)
553 {
554 fprintf (ofp, _("\n\nTop %d Lines:\n\n Line Count\n\n"),
555 bb_table_length);
556
557 /* Abuse line arrays---it's not needed anymore: */
558 qsort (sf->line, sf->num_lines, sizeof (sf->line[0]), cmp_ncalls);
559 table_len = bb_table_length;
560
561 if (table_len > sf->num_lines)
562 table_len = sf->num_lines;
563
564 for (i = 0; i < table_len; ++i)
565 {
566 sym = sf->line[i];
567
568 if (!sym || sym->ncalls == 0)
569 break;
570
571 fprintf (ofp, "%9d %10lu\n", sym->line_num, sym->ncalls);
572 }
573 }
574
575 free (sf->line);
576 sf->line = 0;
577
578 fprintf (ofp, _("\nExecution Summary:\n\n"));
579 fprintf (ofp, _("%9ld Executable lines in this file\n"),
580 num_executable_lines);
581 fprintf (ofp, _("%9ld Lines executed\n"), num_lines_executed);
582 fprintf (ofp, _("%9.2f Percent of the file executed\n"),
583 num_executable_lines
584 ? 100.0 * num_lines_executed / (double) num_executable_lines
585 : 100.0);
586 fprintf (ofp, _("\n%9lu Total number of line executions\n"),
587 sf->ncalls);
588 fprintf (ofp, _("%9.2f Average executions per line\n"),
589 num_executable_lines
590 ? (double) sf->ncalls / (double) num_executable_lines
591 : 0.0);
592
593 if (ofp != stdout)
594 fclose (ofp);
595 }
596}
Note: See TracBrowser for help on using the repository browser.