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 (C) 1999-2020 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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA 22 02110-1301, USA. */ 23 24 #include "gprof.h" 25 #include "libiberty.h" 26 #include "filenames.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 = filename_cmp (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 (void) 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 suppressed 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 = (Source_File *) 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 = (Sym *) 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 (void) 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 *) 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 = (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 } 586