Back to index

cell-binutils  2.17cvs20070401
basic_blocks.c
Go to the documentation of this file.
00001 /* basic_blocks.c  -  Basic-block level related code: reading/writing
00002    of basic-block info to/from gmon.out; computing and formatting of
00003    basic-block related statistics.
00004 
00005    Copyright 1999, 2000, 2001, 2002, 2004, 2005
00006    Free Software Foundation, Inc.
00007 
00008    This file is part of GNU Binutils.
00009 
00010    This program is free software; you can redistribute it and/or modify
00011    it under the terms of the GNU General Public License as published by
00012    the Free Software Foundation; either version 2 of the License, or
00013    (at your option) any later version.
00014 
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019 
00020    You should have received a copy of the GNU General Public License
00021    along with this program; if not, write to the Free Software
00022    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
00023    02110-1301, USA.  */
00024 
00025 #include "libiberty.h"
00026 #include "gprof.h"
00027 #include "basic_blocks.h"
00028 #include "corefile.h"
00029 #include "gmon_io.h"
00030 #include "gmon_out.h"
00031 #include "search_list.h"
00032 #include "source.h"
00033 #include "symtab.h"
00034 #include "sym_ids.h"
00035 
00036 static int cmp_bb (const PTR, const PTR);
00037 static int cmp_ncalls (const PTR, const PTR);
00038 static void fskip_string (FILE *);
00039 static void annotate_with_count (char *, unsigned int, int, PTR);
00040 
00041 /* Default option values:  */
00042 bfd_boolean bb_annotate_all_lines = FALSE;
00043 unsigned long bb_min_calls = 1;
00044 int bb_table_length = 10;
00045 
00046 /* Variables used to compute annotated source listing stats:  */
00047 static long num_executable_lines;
00048 static long num_lines_executed;
00049 
00050 
00051 /* Helper for sorting.  Compares two symbols and returns result
00052    such that sorting will be increasing according to filename, line
00053    number, and address (in that order).  */
00054 
00055 static int
00056 cmp_bb (const PTR lp, const PTR rp)
00057 {
00058   int r;
00059   const Sym *left = *(const Sym **) lp;
00060   const Sym *right = *(const Sym **) rp;
00061 
00062   if (left->file && right->file)
00063     {
00064       r = strcmp (left->file->name, right->file->name);
00065 
00066       if (r)
00067        return r;
00068 
00069       if (left->line_num != right->line_num)
00070        return left->line_num - right->line_num;
00071     }
00072 
00073   if (left->addr < right->addr)
00074     return -1;
00075   else if (left->addr > right->addr)
00076     return 1;
00077   else
00078     return 0;
00079 }
00080 
00081 
00082 /* Helper for sorting.  Order basic blocks in decreasing number of
00083    calls, ties are broken in increasing order of line numbers.  */
00084 static int
00085 cmp_ncalls (const PTR lp, const PTR rp)
00086 {
00087   const Sym *left = *(const Sym **) lp;
00088   const Sym *right = *(const Sym **) rp;
00089 
00090   if (!left)
00091     return 1;
00092   else if (!right)
00093     return -1;
00094 
00095   if (left->ncalls < right->ncalls)
00096     return 1;
00097   else if (left->ncalls > right->ncalls)
00098     return -1;
00099 
00100   return left->line_num - right->line_num;
00101 }
00102 
00103 /* Skip over variable length string.  */
00104 static void
00105 fskip_string (FILE *fp)
00106 {
00107   int ch;
00108 
00109   while ((ch = fgetc (fp)) != EOF)
00110     {
00111       if (ch == '\0')
00112        break;
00113     }
00114 }
00115 
00116 /* Read a basic-block record from file IFP.  FILENAME is the name
00117    of file IFP and is provided for formatting error-messages only.  */
00118 
00119 void
00120 bb_read_rec (FILE *ifp, const char *filename)
00121 {
00122   unsigned int nblocks, b;
00123   bfd_vma addr, ncalls;
00124   Sym *sym;
00125 
00126   if (gmon_io_read_32 (ifp, &nblocks))
00127     {
00128       fprintf (stderr, _("%s: %s: unexpected end of file\n"),
00129               whoami, filename);
00130       done (1);
00131     }
00132 
00133   nblocks = bfd_get_32 (core_bfd, (bfd_byte *) & nblocks);
00134   if (gmon_file_version == 0)
00135     fskip_string (ifp);
00136 
00137   for (b = 0; b < nblocks; ++b)
00138     {
00139       if (gmon_file_version == 0)
00140        {
00141          int line_num;
00142 
00143          /* Version 0 had lots of extra stuff that we don't
00144             care about anymore.  */
00145          if ((fread (&ncalls, sizeof (ncalls), 1, ifp) != 1)
00146              || (fread (&addr, sizeof (addr), 1, ifp) != 1)
00147              || (fskip_string (ifp), FALSE)
00148              || (fskip_string (ifp), FALSE)
00149              || (fread (&line_num, sizeof (line_num), 1, ifp) != 1))
00150            {
00151              perror (filename);
00152              done (1);
00153            }
00154        }
00155       else if (gmon_io_read_vma (ifp, &addr)
00156               || gmon_io_read_vma (ifp, &ncalls))
00157        {
00158          perror (filename);
00159          done (1);
00160        }
00161 
00162       /* Basic-block execution counts are meaningful only if we're
00163         profiling at the line-by-line level:  */
00164       if (line_granularity)
00165        {
00166          sym = sym_lookup (&symtab, addr);
00167 
00168          if (sym)
00169            {
00170              int i;
00171 
00172              DBG (BBDEBUG,
00173                  printf ("[bb_read_rec] 0x%lx->0x%lx (%s:%d) cnt=%lu\n",
00174                         (unsigned long) addr, (unsigned long) sym->addr,
00175                         sym->name, sym->line_num, (unsigned long) ncalls));
00176 
00177              for (i = 0; i < NBBS; i++)
00178               {
00179                 if (! sym->bb_addr[i] || sym->bb_addr[i] == addr)
00180                   {
00181                     sym->bb_addr[i] = addr;
00182                     sym->bb_calls[i] += ncalls;
00183                     break;
00184                   }
00185               }
00186            }
00187        }
00188       else
00189        {
00190          static bfd_boolean user_warned = FALSE;
00191 
00192          if (!user_warned)
00193            {
00194              user_warned = TRUE;
00195              fprintf (stderr,
00196   _("%s: warning: ignoring basic-block exec counts (use -l or --line)\n"),
00197                      whoami);
00198            }
00199        }
00200     }
00201   return;
00202 }
00203 
00204 /* Write all basic-blocks with non-zero counts to file OFP.  FILENAME
00205    is the name of OFP and is provided for producing error-messages
00206    only.  */
00207 void
00208 bb_write_blocks (FILE *ofp, const char *filename)
00209 {
00210   unsigned int nblocks = 0;
00211   Sym *sym;
00212   int i;
00213 
00214   /* Count how many non-zero blocks with have:  */
00215   for (sym = symtab.base; sym < symtab.limit; ++sym)
00216     {
00217       for (i = 0; i < NBBS && sym->bb_addr[i]; i++)
00218        ;
00219       nblocks += i;
00220     }
00221 
00222   /* Write header:  */
00223   if (gmon_io_write_8 (ofp, GMON_TAG_BB_COUNT)
00224       || gmon_io_write_32 (ofp, nblocks))
00225     {
00226       perror (filename);
00227       done (1);
00228     }
00229 
00230   /* Write counts:  */
00231   for (sym = symtab.base; sym < symtab.limit; ++sym)
00232     {
00233       for (i = 0; i < NBBS && sym->bb_addr[i]; i++)
00234        {
00235          if (gmon_io_write_vma (ofp, sym->bb_addr[i])
00236              || gmon_io_write_vma (ofp, (bfd_vma) sym->bb_calls[i]))
00237            {
00238              perror (filename);
00239              done (1);
00240            }
00241        }
00242     }
00243 }
00244 
00245 /* Output basic-block statistics in a format that is easily parseable.
00246    Current the format is:
00247 
00248        <filename>:<line-number>: (<function-name>:<bb-addr): <ncalls>  */
00249 
00250 void
00251 print_exec_counts ()
00252 {
00253   Sym **sorted_bbs, *sym;
00254   unsigned int i, j, len;
00255 
00256   if (first_output)
00257     first_output = FALSE;
00258   else
00259     printf ("\f\n");
00260 
00261   /* Sort basic-blocks according to function name and line number:  */
00262   sorted_bbs = (Sym **) xmalloc (symtab.len * sizeof (sorted_bbs[0]));
00263   len = 0;
00264 
00265   for (sym = symtab.base; sym < symtab.limit; ++sym)
00266     {
00267       /* Accept symbol if it's in the INCL_EXEC table
00268         or there is no INCL_EXEC table
00269         and it does not appear in the EXCL_EXEC table.  */
00270       if (sym_lookup (&syms[INCL_EXEC], sym->addr)
00271          || (syms[INCL_EXEC].len == 0
00272              && !sym_lookup (&syms[EXCL_EXEC], sym->addr)))
00273        {
00274          sorted_bbs[len++] = sym;
00275        }
00276     }
00277 
00278   qsort (sorted_bbs, len, sizeof (sorted_bbs[0]), cmp_bb);
00279 
00280   /* Output basic-blocks:  */
00281 
00282   for (i = 0; i < len; ++i)
00283     {
00284       sym = sorted_bbs [i];
00285       
00286       if (sym->ncalls > 0 || ! ignore_zeros)
00287        {
00288          /* FIXME: This only works if bfd_vma is unsigned long.  */
00289          printf (_("%s:%d: (%s:0x%lx) %lu executions\n"),
00290                 sym->file ? sym->file->name : _("<unknown>"), sym->line_num,
00291                 sym->name, (unsigned long) sym->addr, sym->ncalls);
00292        }
00293 
00294       for (j = 0; j < NBBS && sym->bb_addr[j]; j ++)
00295        {
00296          if (sym->bb_calls[j] > 0 || ! ignore_zeros)
00297            {
00298              /* FIXME: This only works if bfd_vma is unsigned long.  */
00299              printf (_("%s:%d: (%s:0x%lx) %lu executions\n"),
00300                     sym->file ? sym->file->name : _("<unknown>"), sym->line_num,
00301                     sym->name, (unsigned long) sym->bb_addr[j],
00302                     sym->bb_calls[j]);
00303            }
00304        }
00305     }
00306   free (sorted_bbs);
00307 }
00308 
00309 /* Helper for bb_annotated_source: format annotation containing
00310    number of line executions.  Depends on being called on each
00311    line of a file in sequential order.
00312 
00313    Global variable bb_annotate_all_lines enables execution count
00314    compression (counts are supressed if identical to the last one)
00315    and prints counts on all executed lines.  Otherwise, print
00316    all basic-block execution counts exactly once on the line
00317    that starts the basic-block.  */
00318 
00319 static void
00320 annotate_with_count (char *buf, unsigned int width, int line_num, PTR arg)
00321 {
00322   Source_File *sf = arg;
00323   Sym *b;
00324   unsigned int i;
00325   static unsigned long last_count;
00326   unsigned long last_print = (unsigned long) -1;
00327 
00328   b = NULL;
00329 
00330   if (line_num <= sf->num_lines)
00331     b = sf->line[line_num - 1];
00332 
00333   if (!b)
00334     {
00335       for (i = 0; i < width; i++)
00336        buf[i] = ' ';
00337       buf[width] = '\0';
00338     }
00339   else
00340     {
00341       char tmpbuf[NBBS * 30];
00342       char *p;
00343       unsigned long ncalls;
00344       int ncalls_set;
00345       unsigned int len;
00346 
00347       ++num_executable_lines;
00348 
00349       p = tmpbuf;
00350       *p = '\0';
00351 
00352       ncalls = 0;
00353       ncalls_set = 0;
00354 
00355       /* If this is a function entry point, label the line no matter what.
00356         Otherwise, we're in the middle of a function, so check to see
00357         if the first basic-block address is larger than the starting
00358         address of the line.  If so, then this line begins with a
00359         a portion of the previous basic-block, so print that prior
00360         execution count (if bb_annotate_all_lines is set).  */
00361       if (b->is_func)
00362        {
00363          sprintf (p, "%lu", b->ncalls);
00364          p += strlen (p);
00365          last_count = b->ncalls;
00366          last_print = last_count;
00367          ncalls = b->ncalls;
00368          ncalls_set = 1;
00369        }
00370       else if (bb_annotate_all_lines
00371               && b->bb_addr[0] && b->bb_addr[0] > b->addr)
00372        {
00373          sprintf (p, "%lu", last_count);
00374          p += strlen (p);
00375          last_print = last_count;
00376          ncalls = last_count;
00377          ncalls_set = 1;
00378        }
00379 
00380       /* Loop through all of this line's basic-blocks.  For each one,
00381         update last_count, then compress sequential identical counts
00382         (if bb_annotate_all_lines) and print the execution count.  */
00383 
00384       for (i = 0; i < NBBS && b->bb_addr[i]; i++)
00385        {
00386          last_count = b->bb_calls[i];
00387          if (! ncalls_set)
00388            {
00389              ncalls = 0;
00390              ncalls_set = 1;
00391            }
00392          ncalls += last_count;
00393 
00394          if (bb_annotate_all_lines && last_count == last_print)
00395            continue;
00396 
00397          if (p > tmpbuf)
00398            *p++ = ',';
00399          sprintf (p, "%lu", last_count);
00400          p += strlen (p);
00401 
00402          last_print = last_count;
00403        }
00404 
00405       /* We're done.  If nothing has been printed on this line,
00406         print the last execution count (bb_annotate_all_lines),
00407         which could be from either a previous line (if there were
00408         no BBs on this line), or from this line (if all our BB
00409         counts were compressed out because they were identical).  */
00410 
00411       if (bb_annotate_all_lines && p == tmpbuf)
00412        {
00413          sprintf (p, "%lu", last_count);
00414          p += strlen (p);
00415          ncalls = last_count;
00416          ncalls_set = 1;
00417        }
00418 
00419       if (! ncalls_set)
00420        {
00421          unsigned int c;
00422 
00423          for (c = 0; c < width; c++)
00424            buf[c] = ' ';
00425          buf[width] = '\0';
00426          return;
00427        }
00428 
00429       ++num_lines_executed;
00430 
00431       if (ncalls < bb_min_calls)
00432        {
00433          strcpy (tmpbuf, "#####");
00434          p = tmpbuf + 5;
00435        }
00436 
00437       strcpy (p, " -> ");
00438       p += 4;
00439 
00440       len = p - tmpbuf;
00441       if (len >= width)
00442        {
00443          strncpy (buf, tmpbuf, width);
00444          buf[width] = '\0';
00445        }
00446       else
00447        {
00448          unsigned int c;
00449 
00450          strcpy (buf + width - len, tmpbuf);
00451          for (c = 0; c < width - len; ++c)
00452            buf[c] = ' ';
00453        }
00454     }
00455 }
00456 
00457 /* Annotate the files named in SOURCE_FILES with basic-block statistics
00458    (execution counts).  After each source files, a few statistics
00459    regarding that source file are printed.  */
00460 
00461 void
00462 print_annotated_source ()
00463 {
00464   Sym *sym, *line_stats, *new_line;
00465   Source_File *sf;
00466   int i, table_len;
00467   FILE *ofp;
00468 
00469   /* Find maximum line number for each source file that user is
00470      interested in:  */
00471   for (sym = symtab.base; sym < symtab.limit; ++sym)
00472     {
00473       /* Accept symbol if it's file is known, its line number is
00474         bigger than anything we have seen for that file so far and
00475         if it's in the INCL_ANNO table or there is no INCL_ANNO
00476         table and it does not appear in the EXCL_ANNO table.  */
00477       if (sym->file && sym->line_num > sym->file->num_lines
00478          && (sym_lookup (&syms[INCL_ANNO], sym->addr)
00479              || (syms[INCL_ANNO].len == 0
00480                 && !sym_lookup (&syms[EXCL_ANNO], sym->addr))))
00481        {
00482          sym->file->num_lines = sym->line_num;
00483        }
00484     }
00485 
00486   /* Allocate line descriptors:  */
00487   for (sf = first_src_file; sf; sf = sf->next)
00488     {
00489       if (sf->num_lines > 0)
00490        {
00491          sf->line = (void *) xmalloc (sf->num_lines * sizeof (sf->line[0]));
00492          memset (sf->line, 0, sf->num_lines * sizeof (sf->line[0]));
00493        }
00494     }
00495 
00496   /* Count executions per line:  */
00497   for (sym = symtab.base; sym < symtab.limit; ++sym)
00498     {
00499       if (sym->file && sym->file->num_lines
00500          && (sym_lookup (&syms[INCL_ANNO], sym->addr)
00501              || (syms[INCL_ANNO].len == 0
00502                 && !sym_lookup (&syms[EXCL_ANNO], sym->addr))))
00503        {
00504          sym->file->ncalls += sym->ncalls;
00505          line_stats = sym->file->line[sym->line_num - 1];
00506 
00507          if (!line_stats)
00508            {
00509              /* Common case has at most one basic-block per source line:  */
00510              sym->file->line[sym->line_num - 1] = sym;
00511            }
00512          else if (!line_stats->addr)
00513            {
00514              /* sym is the 3rd .. nth basic block for this line:  */
00515              line_stats->ncalls += sym->ncalls;
00516            }
00517          else
00518            {
00519              /* sym is the second basic block for this line.  */
00520              new_line = (Sym *) xmalloc (sizeof (*new_line));
00521              *new_line = *line_stats;
00522              new_line->addr = 0;
00523              new_line->ncalls += sym->ncalls;
00524              sym->file->line[sym->line_num - 1] = new_line;
00525            }
00526        }
00527     }
00528 
00529   /* Plod over source files, annotating them:  */
00530   for (sf = first_src_file; sf; sf = sf->next)
00531     {
00532       if (!sf->num_lines || (ignore_zeros && sf->ncalls == 0))
00533        continue;
00534 
00535       num_executable_lines = num_lines_executed = 0;
00536 
00537       ofp = annotate_source (sf, 16, annotate_with_count, sf);
00538       if (!ofp)
00539        continue;
00540 
00541       if (bb_table_length > 0)
00542        {
00543          fprintf (ofp, _("\n\nTop %d Lines:\n\n     Line      Count\n\n"),
00544                  bb_table_length);
00545 
00546          /* Abuse line arrays---it's not needed anymore:  */
00547          qsort (sf->line, sf->num_lines, sizeof (sf->line[0]), cmp_ncalls);
00548          table_len = bb_table_length;
00549 
00550          if (table_len > sf->num_lines)
00551            table_len = sf->num_lines;
00552 
00553          for (i = 0; i < table_len; ++i)
00554            {
00555              sym = sf->line[i];
00556 
00557              if (!sym || sym->ncalls == 0)
00558                 break;
00559 
00560              fprintf (ofp, "%9d %10lu\n", sym->line_num, sym->ncalls);
00561            }
00562        }
00563 
00564       free (sf->line);
00565       sf->line = 0;
00566 
00567       fprintf (ofp, _("\nExecution Summary:\n\n"));
00568       fprintf (ofp, _("%9ld   Executable lines in this file\n"),
00569               num_executable_lines);
00570       fprintf (ofp, _("%9ld   Lines executed\n"), num_lines_executed);
00571       fprintf (ofp, _("%9.2f   Percent of the file executed\n"),
00572               num_executable_lines
00573               ? 100.0 * num_lines_executed / (double) num_executable_lines
00574               : 100.0);
00575       fprintf (ofp, _("\n%9lu   Total number of line executions\n"),
00576               sf->ncalls);
00577       fprintf (ofp, _("%9.2f   Average executions per line\n"),
00578               num_executable_lines
00579               ? (double) sf->ncalls / (double) num_executable_lines
00580               : 0.0);
00581 
00582       if (ofp != stdout)
00583        fclose (ofp);
00584     }
00585 }