OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-binutils/] [binutils-2.19.1/] [gprof/] [basic_blocks.c] - Blame information for rev 13

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.