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