]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gprof/basic_blocks.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gprof / basic_blocks.c
CommitLineData
ef368dac
NC
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
d87bef3a 5 Copyright (C) 1999-2023 Free Software Foundation, Inc.
ef368dac
NC
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
651dbc76 11 the Free Software Foundation; either version 3 of the License, or
ef368dac
NC
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
44eb1801
NC
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
ef368dac 23\f
6d9c411a 24#include "gprof.h"
ecba005f 25#include "libiberty.h"
aee9ba6f 26#include "filenames.h"
252b5132
RH
27#include "basic_blocks.h"
28#include "corefile.h"
29#include "gmon_io.h"
30#include "gmon_out.h"
6d9c411a 31#include "search_list.h"
252b5132 32#include "source.h"
6d9c411a 33#include "symtab.h"
252b5132
RH
34#include "sym_ids.h"
35
e3154ef6
AM
36static int cmp_bb (const void *, const void *);
37static int cmp_ncalls (const void *, const void *);
3e8f6abf 38static void fskip_string (FILE *);
e3154ef6 39static void annotate_with_count (char *, unsigned int, int, void *);
1355568a 40
ef368dac 41/* Default option values: */
faa7a260 42bool bb_annotate_all_lines = false;
252b5132
RH
43unsigned long bb_min_calls = 1;
44int bb_table_length = 10;
45
ef368dac 46/* Variables used to compute annotated source listing stats: */
252b5132
RH
47static long num_executable_lines;
48static long num_lines_executed;
49
50
ef368dac
NC
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). */
252b5132
RH
54
55static int
e3154ef6 56cmp_bb (const void *lp, const void *rp)
252b5132
RH
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 {
aee9ba6f 64 r = filename_cmp (left->file->name, right->file->name);
0eee5820 65
252b5132 66 if (r)
ef368dac 67 return r;
252b5132
RH
68
69 if (left->line_num != right->line_num)
ef368dac 70 return left->line_num - right->line_num;
252b5132
RH
71 }
72
73 if (left->addr < right->addr)
ef368dac 74 return -1;
252b5132 75 else if (left->addr > right->addr)
ef368dac 76 return 1;
252b5132 77 else
ef368dac 78 return 0;
252b5132
RH
79}
80
81
ef368dac
NC
82/* Helper for sorting. Order basic blocks in decreasing number of
83 calls, ties are broken in increasing order of line numbers. */
252b5132 84static int
e3154ef6 85cmp_ncalls (const void *lp, const void *rp)
252b5132
RH
86{
87 const Sym *left = *(const Sym **) lp;
88 const Sym *right = *(const Sym **) rp;
89
90 if (!left)
ef368dac 91 return 1;
252b5132 92 else if (!right)
ef368dac 93 return -1;
252b5132
RH
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
ef368dac 103/* Skip over variable length string. */
252b5132 104static void
3e8f6abf 105fskip_string (FILE *fp)
252b5132
RH
106{
107 int ch;
108
109 while ((ch = fgetc (fp)) != EOF)
110 {
111 if (ch == '\0')
ef368dac 112 break;
252b5132
RH
113 }
114}
115
ef368dac
NC
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. */
252b5132 118
252b5132 119void
3e8f6abf 120bb_read_rec (FILE *ifp, const char *filename)
252b5132 121{
8c62e9e1 122 unsigned int nblocks, b;
0eee5820 123 bfd_vma addr, ncalls;
252b5132
RH
124 Sym *sym;
125
0eee5820 126 if (gmon_io_read_32 (ifp, &nblocks))
252b5132 127 {
0eee5820
AM
128 fprintf (stderr, _("%s: %s: unexpected end of file\n"),
129 whoami, filename);
252b5132
RH
130 done (1);
131 }
132
133 nblocks = bfd_get_32 (core_bfd, (bfd_byte *) & nblocks);
134 if (gmon_file_version == 0)
ef368dac 135 fskip_string (ifp);
252b5132
RH
136
137 for (b = 0; b < nblocks; ++b)
138 {
139 if (gmon_file_version == 0)
140 {
141 int line_num;
0eee5820 142
ef368dac
NC
143 /* Version 0 had lots of extra stuff that we don't
144 care about anymore. */
252b5132
RH
145 if ((fread (&ncalls, sizeof (ncalls), 1, ifp) != 1)
146 || (fread (&addr, sizeof (addr), 1, ifp) != 1)
faa7a260
AM
147 || (fskip_string (ifp), false)
148 || (fskip_string (ifp), false)
252b5132
RH
149 || (fread (&line_num, sizeof (line_num), 1, ifp) != 1))
150 {
151 perror (filename);
152 done (1);
153 }
154 }
0eee5820
AM
155 else if (gmon_io_read_vma (ifp, &addr)
156 || gmon_io_read_vma (ifp, &ncalls))
252b5132 157 {
0eee5820
AM
158 perror (filename);
159 done (1);
252b5132
RH
160 }
161
ef368dac 162 /* Basic-block execution counts are meaningful only if we're
0eee5820 163 profiling at the line-by-line level: */
252b5132
RH
164 if (line_granularity)
165 {
252b5132
RH
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",
fdcf7d43 174 (unsigned long) addr, (unsigned long) sym->addr,
0eee5820 175 sym->name, sym->line_num, (unsigned long) ncalls));
252b5132
RH
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 {
faa7a260 190 static bool user_warned = false;
252b5132
RH
191
192 if (!user_warned)
193 {
faa7a260 194 user_warned = true;
252b5132 195 fprintf (stderr,
ef368dac 196 _("%s: warning: ignoring basic-block exec counts (use -l or --line)\n"),
252b5132
RH
197 whoami);
198 }
199 }
200 }
201 return;
202}
203
ef368dac
NC
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. */
252b5132 207void
3e8f6abf 208bb_write_blocks (FILE *ofp, const char *filename)
252b5132 209{
1355568a 210 unsigned int nblocks = 0;
252b5132
RH
211 Sym *sym;
212 int i;
213
ef368dac 214 /* Count how many non-zero blocks with have: */
252b5132
RH
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
ef368dac 222 /* Write header: */
0eee5820
AM
223 if (gmon_io_write_8 (ofp, GMON_TAG_BB_COUNT)
224 || gmon_io_write_32 (ofp, nblocks))
252b5132
RH
225 {
226 perror (filename);
227 done (1);
228 }
229
ef368dac 230 /* Write counts: */
252b5132
RH
231 for (sym = symtab.base; sym < symtab.limit; ++sym)
232 {
233 for (i = 0; i < NBBS && sym->bb_addr[i]; i++)
234 {
0eee5820 235 if (gmon_io_write_vma (ofp, sym->bb_addr[i])
1355568a 236 || gmon_io_write_vma (ofp, (bfd_vma) sym->bb_calls[i]))
252b5132
RH
237 {
238 perror (filename);
239 done (1);
240 }
241 }
242 }
243}
244
ef368dac
NC
245/* Output basic-block statistics in a format that is easily parseable.
246 Current the format is:
0eee5820
AM
247
248 <filename>:<line-number>: (<function-name>:<bb-addr): <ncalls> */
252b5132 249
252b5132 250void
e6c7cdec 251print_exec_counts (void)
252b5132
RH
252{
253 Sym **sorted_bbs, *sym;
1355568a 254 unsigned int i, j, len;
252b5132
RH
255
256 if (first_output)
faa7a260 257 first_output = false;
252b5132 258 else
ef368dac 259 printf ("\f\n");
252b5132 260
ef368dac 261 /* Sort basic-blocks according to function name and line number: */
252b5132
RH
262 sorted_bbs = (Sym **) xmalloc (symtab.len * sizeof (sorted_bbs[0]));
263 len = 0;
0eee5820 264
252b5132
RH
265 for (sym = symtab.base; sym < symtab.limit; ++sym)
266 {
ef368dac 267 /* Accept symbol if it's in the INCL_EXEC table
0eee5820
AM
268 or there is no INCL_EXEC table
269 and it does not appear in the EXCL_EXEC table. */
252b5132
RH
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 }
0eee5820 277
252b5132
RH
278 qsort (sorted_bbs, len, sizeof (sorted_bbs[0]), cmp_bb);
279
ef368dac 280 /* Output basic-blocks: */
252b5132
RH
281
282 for (i = 0; i < len; ++i)
283 {
f7945f45 284 sym = sorted_bbs [i];
f3445b37 285
252b5132
RH
286 if (sym->ncalls > 0 || ! ignore_zeros)
287 {
fdcf7d43 288 /* FIXME: This only works if bfd_vma is unsigned long. */
252b5132
RH
289 printf (_("%s:%d: (%s:0x%lx) %lu executions\n"),
290 sym->file ? sym->file->name : _("<unknown>"), sym->line_num,
fdcf7d43 291 sym->name, (unsigned long) sym->addr, sym->ncalls);
252b5132 292 }
0eee5820 293
252b5132
RH
294 for (j = 0; j < NBBS && sym->bb_addr[j]; j ++)
295 {
296 if (sym->bb_calls[j] > 0 || ! ignore_zeros)
297 {
fdcf7d43 298 /* FIXME: This only works if bfd_vma is unsigned long. */
252b5132
RH
299 printf (_("%s:%d: (%s:0x%lx) %lu executions\n"),
300 sym->file ? sym->file->name : _("<unknown>"), sym->line_num,
fdcf7d43
ILT
301 sym->name, (unsigned long) sym->bb_addr[j],
302 sym->bb_calls[j]);
252b5132
RH
303 }
304 }
305 }
306 free (sorted_bbs);
307}
308
ef368dac
NC
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.
0eee5820 312
ef368dac 313 Global variable bb_annotate_all_lines enables execution count
576a6e4d 314 compression (counts are suppressed if identical to the last one)
ef368dac
NC
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. */
252b5132
RH
318
319static void
e3154ef6 320annotate_with_count (char *buf, unsigned int width, int line_num, void *arg)
252b5132 321{
1e9cc1c2 322 Source_File *sf = (Source_File *) arg;
252b5132 323 Sym *b;
1355568a 324 unsigned int i;
252b5132
RH
325 static unsigned long last_count;
326 unsigned long last_print = (unsigned long) -1;
327
328 b = NULL;
0eee5820 329
252b5132 330 if (line_num <= sf->num_lines)
1e9cc1c2 331 b = (Sym *) sf->line[line_num - 1];
ef368dac 332
252b5132
RH
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;
1355568a 345 unsigned int len;
252b5132
RH
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.
0eee5820
AM
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). */
252b5132
RH
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,
0eee5820
AM
381 update last_count, then compress sequential identical counts
382 (if bb_annotate_all_lines) and print the execution count. */
252b5132
RH
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)
ef368dac 395 continue;
252b5132
RH
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,
0eee5820
AM
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). */
252b5132
RH
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 {
1355568a 421 unsigned int c;
252b5132
RH
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 {
1355568a 448 unsigned int c;
252b5132
RH
449
450 strcpy (buf + width - len, tmpbuf);
451 for (c = 0; c < width - len; ++c)
452 buf[c] = ' ';
453 }
454 }
455}
456
ef368dac
NC
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
252b5132 461void
e6c7cdec 462print_annotated_source (void)
252b5132
RH
463{
464 Sym *sym, *line_stats, *new_line;
465 Source_File *sf;
466 int i, table_len;
467 FILE *ofp;
468
ef368dac
NC
469 /* Find maximum line number for each source file that user is
470 interested in: */
252b5132
RH
471 for (sym = symtab.base; sym < symtab.limit; ++sym)
472 {
ef368dac 473 /* Accept symbol if it's file is known, its line number is
0eee5820
AM
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. */
252b5132
RH
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
ef368dac 486 /* Allocate line descriptors: */
252b5132
RH
487 for (sf = first_src_file; sf; sf = sf->next)
488 {
489 if (sf->num_lines > 0)
490 {
1e9cc1c2 491 sf->line = (void **) xmalloc (sf->num_lines * sizeof (sf->line[0]));
252b5132
RH
492 memset (sf->line, 0, sf->num_lines * sizeof (sf->line[0]));
493 }
494 }
495
ef368dac 496 /* Count executions per line: */
252b5132
RH
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;
1e9cc1c2 505 line_stats = (Sym *) sym->file->line[sym->line_num - 1];
0eee5820 506
252b5132
RH
507 if (!line_stats)
508 {
ef368dac 509 /* Common case has at most one basic-block per source line: */
252b5132
RH
510 sym->file->line[sym->line_num - 1] = sym;
511 }
512 else if (!line_stats->addr)
513 {
ef368dac 514 /* sym is the 3rd .. nth basic block for this line: */
252b5132
RH
515 line_stats->ncalls += sym->ncalls;
516 }
517 else
518 {
ef368dac 519 /* sym is the second basic block for this line. */
252b5132
RH
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
ef368dac 529 /* Plod over source files, annotating them: */
252b5132
RH
530 for (sf = first_src_file; sf; sf = sf->next)
531 {
532 if (!sf->num_lines || (ignore_zeros && sf->ncalls == 0))
ef368dac 533 continue;
252b5132
RH
534
535 num_executable_lines = num_lines_executed = 0;
0eee5820 536
252b5132
RH
537 ofp = annotate_source (sf, 16, annotate_with_count, sf);
538 if (!ofp)
ef368dac 539 continue;
252b5132
RH
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
ef368dac 546 /* Abuse line arrays---it's not needed anymore: */
252b5132
RH
547 qsort (sf->line, sf->num_lines, sizeof (sf->line[0]), cmp_ncalls);
548 table_len = bb_table_length;
0eee5820 549
252b5132 550 if (table_len > sf->num_lines)
ef368dac 551 table_len = sf->num_lines;
0eee5820 552
252b5132
RH
553 for (i = 0; i < table_len; ++i)
554 {
1e9cc1c2 555 sym = (Sym *) sf->line[i];
0eee5820 556
252b5132 557 if (!sym || sym->ncalls == 0)
252b5132 558 break;
ef368dac 559
252b5132
RH
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);
0eee5820 581
252b5132 582 if (ofp != stdout)
ef368dac 583 fclose (ofp);
252b5132
RH
584 }
585}