diff options
Diffstat (limited to 'gprof/basic_blocks.c')
-rw-r--r-- | gprof/basic_blocks.c | 292 |
1 files changed, 123 insertions, 169 deletions
diff --git a/gprof/basic_blocks.c b/gprof/basic_blocks.c index 43dd762b..926743f 100644 --- a/gprof/basic_blocks.c +++ b/gprof/basic_blocks.c @@ -1,8 +1,26 @@ -/* - * Basic-block level related code: reading/writing of basic-block info - * to/from gmon.out; computing and formatting of basic-block related - * statistics. - */ +/* basic_blocks.c - Basic-block level related code: reading/writing + of basic-block info to/from gmon.out; computing and formatting of + basic-block related statistics. + + Copyright (C) 2000 Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + #include <stdio.h> #include <unistd.h> #include "basic_blocks.h" @@ -14,26 +32,19 @@ #include "source.h" #include "sym_ids.h" - -/* - * Default option values: - */ +/* Default option values: */ bool bb_annotate_all_lines = FALSE; unsigned long bb_min_calls = 1; int bb_table_length = 10; -/* - * Variables used to compute annotated source listing stats: - */ +/* Variables used to compute annotated source listing stats: */ static long num_executable_lines; static long num_lines_executed; -/* - * Helper for sorting. Compares two symbols and returns result - * such that sorting will be increasing according to filename, line - * number, and address (in that order). - */ +/* Helper for sorting. Compares two symbols and returns result + such that sorting will be increasing according to filename, line + number, and address (in that order). */ static int DEFUN (cmp_bb, (lp, rp), const void *lp AND const void *rp) @@ -45,36 +56,25 @@ DEFUN (cmp_bb, (lp, rp), const void *lp AND const void *rp) if (left->file && right->file) { r = strcmp (left->file->name, right->file->name); + if (r) - { - return r; - } + return r; if (left->line_num != right->line_num) - { - return left->line_num - right->line_num; - } + return left->line_num - right->line_num; } if (left->addr < right->addr) - { - return -1; - } + return -1; else if (left->addr > right->addr) - { - return 1; - } + return 1; else - { - return 0; - } + return 0; } -/* - * Helper for sorting. Order basic blocks in decreasing number of - * calls, ties are broken in increasing order of line numbers. - */ +/* Helper for sorting. Order basic blocks in decreasing number of + calls, ties are broken in increasing order of line numbers. */ static int DEFUN (cmp_ncalls, (lp, rp), const void *lp AND const void *rp) { @@ -82,13 +82,9 @@ DEFUN (cmp_ncalls, (lp, rp), const void *lp AND const void *rp) const Sym *right = *(const Sym **) rp; if (!left) - { - return 1; - } + return 1; else if (!right) - { - return -1; - } + return -1; if (left->ncalls < right->ncalls) return 1; @@ -98,10 +94,7 @@ DEFUN (cmp_ncalls, (lp, rp), const void *lp AND const void *rp) return left->line_num - right->line_num; } - -/* - * Skip over variable length string. - */ +/* Skip over variable length string. */ static void DEFUN (fskip_string, (fp), FILE * fp) { @@ -110,17 +103,13 @@ DEFUN (fskip_string, (fp), FILE * fp) while ((ch = fgetc (fp)) != EOF) { if (ch == '\0') - { - break; - } + break; } } +/* Read a basic-block record from file IFP. FILENAME is the name + of file IFP and is provided for formatting error-messages only. */ -/* - * Read a basic-block record from file IFP. FILENAME is the name - * of file IFP and is provided for formatting error-messages only. - */ void DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename) { @@ -136,20 +125,18 @@ DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename) } nblocks = bfd_get_32 (core_bfd, (bfd_byte *) & nblocks); + if (gmon_file_version == 0) - { - fskip_string (ifp); - } + fskip_string (ifp); for (b = 0; b < nblocks; ++b) { if (gmon_file_version == 0) { int line_num; - /* - * Version 0 had lots of extra stuff that we don't - * care about anymore. - */ + + /* Version 0 had lots of extra stuff that we don't + care about anymore. */ if ((fread (&ncalls, sizeof (ncalls), 1, ifp) != 1) || (fread (&addr, sizeof (addr), 1, ifp) != 1) || (fskip_string (ifp), FALSE) @@ -170,15 +157,11 @@ DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename) } } - /* - * Basic-block execution counts are meaningful only if we're - * profiling at the line-by-line level: - */ + /* Basic-block execution counts are meaningful only if we're + profiling at the line-by-line level: */ if (line_granularity) { - - /* convert from target to host endianness: */ - + /* Convert from target to host endianness: */ addr = get_vma (core_bfd, (bfd_byte *) & addr); ncalls = bfd_get_32 (core_bfd, (bfd_byte *) &ncalls); @@ -212,7 +195,7 @@ DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename) { user_warned = TRUE; fprintf (stderr, - _("%s: warning: ignoring basic-block exec counts (use -l or --line)\n"), + _("%s: warning: ignoring basic-block exec counts (use -l or --line)\n"), whoami); } } @@ -220,12 +203,9 @@ DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename) return; } - -/* - * Write all basic-blocks with non-zero counts to file OFP. FILENAME - * is the name of OFP and is provided for producing error-messages - * only. - */ +/* Write all basic-blocks with non-zero counts to file OFP. FILENAME + is the name of OFP and is provided for producing error-messages + only. */ void DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename) { @@ -236,8 +216,7 @@ DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename) Sym *sym; int i; - /* count how many non-zero blocks with have: */ - + /* Count how many non-zero blocks with have: */ for (sym = symtab.base; sym < symtab.limit; ++sym) { for (i = 0; i < NBBS && sym->bb_addr[i]; i++) @@ -245,7 +224,7 @@ DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename) nblocks += i; } - /* write header: */ + /* Write header: */ bfd_put_32 (core_bfd, nblocks, (bfd_byte *) & nblocks); if (fwrite (&tag, sizeof (tag), 1, ofp) != 1 || fwrite (&nblocks, sizeof (nblocks), 1, ofp) != 1) @@ -254,7 +233,7 @@ DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename) done (1); } - /* write counts: */ + /* Write counts: */ for (sym = symtab.base; sym < symtab.limit; ++sym) { for (i = 0; i < NBBS && sym->bb_addr[i]; i++) @@ -272,13 +251,11 @@ DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename) } } +/* Output basic-block statistics in a format that is easily parseable. + Current the format is: + + <filename>:<line-number>: (<function-name>:<bb-addr): <ncalls> */ -/* - * Output basic-block statistics in a format that is easily parseable. - * Current the format is: - * - * <filename>:<line-number>: (<function-name>:<bb-addr): <ncalls> - */ void DEFUN_VOID (print_exec_counts) { @@ -286,25 +263,19 @@ DEFUN_VOID (print_exec_counts) int i, j, len; if (first_output) - { - first_output = FALSE; - } + first_output = FALSE; else - { - printf ("\f\n"); - } - - /* sort basic-blocks according to function name and line number: */ + printf ("\f\n"); + /* Sort basic-blocks according to function name and line number: */ sorted_bbs = (Sym **) xmalloc (symtab.len * sizeof (sorted_bbs[0])); len = 0; + for (sym = symtab.base; sym < symtab.limit; ++sym) { - /* - * Accept symbol if it's in the INCL_EXEC table - * or there is no INCL_EXEC table - * and it does not appear in the EXCL_EXEC table. - */ + /* Accept symbol if it's in the INCL_EXEC table + or there is no INCL_EXEC table + and it does not appear in the EXCL_EXEC table. */ if (sym_lookup (&syms[INCL_EXEC], sym->addr) || (syms[INCL_EXEC].len == 0 && !sym_lookup (&syms[EXCL_EXEC], sym->addr))) @@ -312,9 +283,10 @@ DEFUN_VOID (print_exec_counts) sorted_bbs[len++] = sym; } } + qsort (sorted_bbs, len, sizeof (sorted_bbs[0]), cmp_bb); - /* output basic-blocks: */ + /* Output basic-blocks: */ for (i = 0; i < len; ++i) { @@ -325,6 +297,7 @@ DEFUN_VOID (print_exec_counts) sym->file ? sym->file->name : _("<unknown>"), sym->line_num, sym->name, (unsigned long) sym->addr, sym->ncalls); } + for (j = 0; j < NBBS && sym->bb_addr[j]; j ++) { if (sym->bb_calls[j] > 0 || ! ignore_zeros) @@ -340,17 +313,15 @@ DEFUN_VOID (print_exec_counts) free (sorted_bbs); } -/* - * Helper for bb_annotated_source: format annotation containing - * number of line executions. Depends on being called on each - * line of a file in sequential order. - * - * Global variable bb_annotate_all_lines enables execution count - * compression (counts are supressed if identical to the last one) - * and prints counts on all executed lines. Otherwise, print - * all basic-block execution counts exactly once on the line - * that starts the basic-block. - */ +/* Helper for bb_annotated_source: format annotation containing + number of line executions. Depends on being called on each + line of a file in sequential order. + + Global variable bb_annotate_all_lines enables execution count + compression (counts are supressed if identical to the last one) + and prints counts on all executed lines. Otherwise, print + all basic-block execution counts exactly once on the line + that starts the basic-block. */ static void DEFUN (annotate_with_count, (buf, width, line_num, arg), @@ -363,10 +334,10 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg), unsigned long last_print = (unsigned long) -1; b = NULL; + if (line_num <= sf->num_lines) - { - b = sf->line[line_num - 1]; - } + b = sf->line[line_num - 1]; + if (!b) { for (i = 0; i < width; i++) @@ -390,13 +361,11 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg), ncalls_set = 0; /* If this is a function entry point, label the line no matter what. - * Otherwise, we're in the middle of a function, so check to see - * if the first basic-block address is larger than the starting - * address of the line. If so, then this line begins with a - * a portion of the previous basic-block, so print that prior - * execution count (if bb_annotate_all_lines is set). - */ - + Otherwise, we're in the middle of a function, so check to see + if the first basic-block address is larger than the starting + address of the line. If so, then this line begins with a + a portion of the previous basic-block, so print that prior + execution count (if bb_annotate_all_lines is set). */ if (b->is_func) { sprintf (p, "%lu", b->ncalls); @@ -417,9 +386,8 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg), } /* Loop through all of this line's basic-blocks. For each one, - * update last_count, then compress sequential identical counts - * (if bb_annotate_all_lines) and print the execution count. - */ + update last_count, then compress sequential identical counts + (if bb_annotate_all_lines) and print the execution count. */ for (i = 0; i < NBBS && b->bb_addr[i]; i++) { @@ -432,9 +400,7 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg), ncalls += last_count; if (bb_annotate_all_lines && last_count == last_print) - { - continue; - } + continue; if (p > tmpbuf) *p++ = ','; @@ -445,11 +411,10 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg), } /* We're done. If nothing has been printed on this line, - * print the last execution count (bb_annotate_all_lines), - * which could be from either a previous line (if there were - * no BBs on this line), or from this line (if all our BB - * counts were compressed out because they were identical). - */ + print the last execution count (bb_annotate_all_lines), + which could be from either a previous line (if there were + no BBs on this line), or from this line (if all our BB + counts were compressed out because they were identical). */ if (bb_annotate_all_lines && p == tmpbuf) { @@ -497,11 +462,10 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg), } } -/* - * Annotate the files named in SOURCE_FILES with basic-block statistics - * (execution counts). After each source files, a few statistics - * regarding that source file are printed. - */ +/* Annotate the files named in SOURCE_FILES with basic-block statistics + (execution counts). After each source files, a few statistics + regarding that source file are printed. */ + void DEFUN_VOID (print_annotated_source) { @@ -510,18 +474,14 @@ DEFUN_VOID (print_annotated_source) int i, table_len; FILE *ofp; - /* - * Find maximum line number for each source file that user is - * interested in: - */ + /* Find maximum line number for each source file that user is + interested in: */ for (sym = symtab.base; sym < symtab.limit; ++sym) { - /* - * Accept symbol if it's file is known, its line number is - * bigger than anything we have seen for that file so far and - * if it's in the INCL_ANNO table or there is no INCL_ANNO - * table and it does not appear in the EXCL_ANNO table. - */ + /* Accept symbol if it's file is known, its line number is + bigger than anything we have seen for that file so far and + if it's in the INCL_ANNO table or there is no INCL_ANNO + table and it does not appear in the EXCL_ANNO table. */ if (sym->file && sym->line_num > sym->file->num_lines && (sym_lookup (&syms[INCL_ANNO], sym->addr) || (syms[INCL_ANNO].len == 0 @@ -531,8 +491,7 @@ DEFUN_VOID (print_annotated_source) } } - /* allocate line descriptors: */ - + /* Allocate line descriptors: */ for (sf = first_src_file; sf; sf = sf->next) { if (sf->num_lines > 0) @@ -542,8 +501,7 @@ DEFUN_VOID (print_annotated_source) } } - /* count executions per line: */ - + /* Count executions per line: */ for (sym = symtab.base; sym < symtab.limit; ++sym) { if (sym->file && sym->file->num_lines @@ -553,19 +511,20 @@ DEFUN_VOID (print_annotated_source) { sym->file->ncalls += sym->ncalls; line_stats = sym->file->line[sym->line_num - 1]; + if (!line_stats) { - /* common case has at most one basic-block per source line: */ + /* Common case has at most one basic-block per source line: */ sym->file->line[sym->line_num - 1] = sym; } else if (!line_stats->addr) { - /* sym is the 3rd .. nth basic block for this line: */ + /* sym is the 3rd .. nth basic block for this line: */ line_stats->ncalls += sym->ncalls; } else { - /* sym is the second basic block for this line */ + /* sym is the second basic block for this line. */ new_line = (Sym *) xmalloc (sizeof (*new_line)); *new_line = *line_stats; new_line->addr = 0; @@ -575,41 +534,37 @@ DEFUN_VOID (print_annotated_source) } } - /* plod over source files, annotating them: */ - + /* Plod over source files, annotating them: */ for (sf = first_src_file; sf; sf = sf->next) { if (!sf->num_lines || (ignore_zeros && sf->ncalls == 0)) - { - continue; - } + continue; num_executable_lines = num_lines_executed = 0; + ofp = annotate_source (sf, 16, annotate_with_count, sf); if (!ofp) - { - continue; - } + continue; if (bb_table_length > 0) { fprintf (ofp, _("\n\nTop %d Lines:\n\n Line Count\n\n"), bb_table_length); - /* abuse line arrays---it's not needed anymore: */ + /* Abuse line arrays---it's not needed anymore: */ qsort (sf->line, sf->num_lines, sizeof (sf->line[0]), cmp_ncalls); table_len = bb_table_length; + if (table_len > sf->num_lines) - { - table_len = sf->num_lines; - } + table_len = sf->num_lines; + for (i = 0; i < table_len; ++i) { sym = sf->line[i]; + if (!sym || sym->ncalls == 0) - { break; - } + fprintf (ofp, "%9d %10lu\n", sym->line_num, sym->ncalls); } } @@ -631,9 +586,8 @@ DEFUN_VOID (print_annotated_source) num_executable_lines ? (double) sf->ncalls / (double) num_executable_lines : 0.0); + if (ofp != stdout) - { - fclose (ofp); - } + fclose (ofp); } } |