cg_annotate.in revision dac0cdac0f7155750b93e8c95aab98d97e17a7b2
1#! @PERL@ 2 3##--------------------------------------------------------------------## 4##--- Cachegrind's annotator. cg_annotate.in ---## 5##--------------------------------------------------------------------## 6 7# This file is part of Cachegrind, a Valgrind tool for cache 8# profiling programs. 9# 10# Copyright (C) 2002-2005 Nicholas Nethercote 11# njn@valgrind.org 12# 13# This program is free software; you can redistribute it and/or 14# modify it under the terms of the GNU General Public License as 15# published by the Free Software Foundation; either version 2 of the 16# License, or (at your option) any later version. 17# 18# This program is distributed in the hope that it will be useful, but 19# WITHOUT ANY WARRANTY; without even the implied warranty of 20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21# General Public License for more details. 22# 23# You should have received a copy of the GNU General Public License 24# along with this program; if not, write to the Free Software 25# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26# 02111-1307, USA. 27# 28# The GNU General Public License is contained in the file COPYING. 29 30#---------------------------------------------------------------------------- 31# The file format is simple, basically printing the cost centre for every 32# source line, grouped by files and functions: 33# 34# file ::= desc_line* cmd_line events_line data_line+ summary_line 35# desc_line ::= "desc:" ws? non_nl_string 36# cmd_line ::= "cmd:" ws? cmd 37# events_line ::= "events:" ws? (event ws)+ 38# data_line ::= file_line | fn_line | count_line 39# file_line ::= "fl=" filename 40# fn_line ::= "fn=" fn_name 41# count_line ::= line_num ws? (count ws)+ 42# summary_line ::= "summary:" ws? (count ws)+ 43# count ::= num | "." 44# 45# where 46# 'non_nl_string' is any string not containing a newline. 47# 'cmd' is a string holding the command line of the profiled program. 48# 'filename' and 'fn_name' are strings. 49# 'num' and 'line_num' are decimal integers. 50# 'ws' is whitespace. 51# 52# The contents of the "desc:" lines are printed out at the top 53# of the summary. This is a generic way of providing simulation 54# specific information, eg. for giving the cache configuration for 55# cache simulation. 56# 57# More than one line of info can be presented for each file/fn/line number. 58# In such cases, the counts for the named events will be accumulated. 59# 60# Counts can be "." to represent zero. This makes the files easier to read. 61# 62# The number of counts in each 'line' and the 'summary_line' should not exceed 63# the number of events in the 'event_line'. If the number in each 'line' is 64# less, cg_annotate treats those missing as though they were a "." entry. 65# 66# A 'file_line' changes the current file name. A 'fn_line' changes the 67# current function name. A 'count_line' contains counts that pertain to the 68# current filename/fn_name. A 'file_line' and a 'fn_line' must appear 69# before any 'count_line's to give the context of the first 'count_line'. 70# 71# Each 'file_line' will normally be immediately followed by a 'fn_line'. 72# But it doesn't have to be. 73 74#---------------------------------------------------------------------------- 75# Performance improvements record, using cachegrind.out for cacheprof, doing no 76# source annotation (irrelevant ones removed): 77# user time 78# 1. turned off warnings in add_hash_a_to_b() 3.81 --> 3.48s 79# [now add_array_a_to_b()] 80# 6. make line_to_CC() return a ref instead of a hash 3.01 --> 2.77s 81# 82#10. changed file format to avoid file/fn name repetition 2.40s 83# (not sure why higher; maybe due to new '.' entries?) 84#11. changed file format to drop unnecessary end-line "."s 2.36s 85# (shrunk file by about 37%) 86#12. switched from hash CCs to array CCs 1.61s 87#13. only adding b[i] to a[i] if b[i] defined (was doing it if 88# either a[i] or b[i] was defined, but if b[i] was undefined 89# it just added 0) 1.48s 90#14. Stopped converting "." entries to undef and then back 1.16s 91#15. Using foreach $i (x..y) instead of for ($i = 0...) in 92# add_array_a_to_b() 1.11s 93# 94# Auto-annotating primes: 95#16. Finding count lengths by int((length-1)/3), not by 96# commifying (halves the number of commify calls) 1.68s --> 1.47s 97 98use warnings; 99use strict; 100 101#---------------------------------------------------------------------------- 102# Overview: the running example in the comments is for: 103# - events = A,B,C,D 104# - --show=C,A,D 105# - --sort=D,C 106#---------------------------------------------------------------------------- 107 108#---------------------------------------------------------------------------- 109# Global variables, main data structures 110#---------------------------------------------------------------------------- 111# CCs are arrays, the counts corresponding to @events, with 'undef' 112# representing '.'. This makes things fast (faster than using hashes for CCs) 113# but we have to use @sort_order and @show_order below to handle the --sort and 114# --show options, which is a bit tricky. 115#---------------------------------------------------------------------------- 116 117# Total counts for summary (an array reference). 118my $summary_CC; 119 120# Totals for each function, for overall summary. 121# hash(filename:fn_name => CC array) 122my %fn_totals; 123 124# Individual CCs, organised by filename and line_num for easy annotation. 125# hash(filename => hash(line_num => CC array)) 126my %all_ind_CCs; 127 128# Files chosen for annotation on the command line. 129# key = basename (trimmed of any directory), value = full filename 130my %user_ann_files; 131 132# Generic description string. 133my $desc = ""; 134 135# Command line of profiled program. 136my $cmd; 137 138# Events in input file, eg. (A,B,C,D) 139my @events; 140 141# Events to show, from command line, eg. (C,A,D) 142my @show_events; 143 144# Map from @show_events indices to @events indices, eg. (2,0,3). Gives the 145# order in which we must traverse @events in order to show the @show_events, 146# eg. (@events[$show_order[1]], @events[$show_order[2]]...) = @show_events. 147# (Might help to think of it like a hash (0 => 2, 1 => 0, 2 => 3).) 148my @show_order; 149 150# Print out the function totals sorted by these events, eg. (D,C). 151my @sort_events; 152 153# Map from @sort_events indices to @events indices, eg. (3,2). Same idea as 154# for @show_order. 155my @sort_order; 156 157# Thresholds, one for each sort event (or default to 1 if no sort events 158# specified). We print out functions and do auto-annotations until we've 159# handled this proportion of all the events thresholded. 160my @thresholds; 161 162my $default_threshold = 99; 163 164my $single_threshold = $default_threshold; 165 166# If on, automatically annotates all files that are involved in getting over 167# all the threshold counts. 168my $auto_annotate = 0; 169 170# Number of lines to show around each annotated line. 171my $context = 8; 172 173# Directories in which to look for annotation files. 174my @include_dirs = (""); 175 176# Input file name 177my $input_file = undef; 178 179# Version number 180my $version = "@VERSION@"; 181 182# Usage message. 183my $usage = <<END 184usage: cg_annotate [options] --<pid> [source-files] 185 186 options for the user, with defaults in [ ], are: 187 -h --help show this message 188 -v --version show version 189 --show=A,B,C only show figures for events A,B,C [all] 190 --sort=A,B,C sort columns by events A,B,C [event column order] 191 --threshold=<0--100> percentage of counts (of primary sort event) we 192 are interested in [$default_threshold%] 193 --auto=yes|no annotate all source files containing functions 194 that helped reach the event count threshold [no] 195 --context=N print N lines of context before and after 196 annotated lines [8] 197 -I<d> --include=<d> add <d> to list of directories to search for 198 source files 199 200 Cachegrind is Copyright (C) 2002-2005 Nicholas Nethercote. 201 Both are licensed under the GNU General Public License, version 2. 202 Bug reports, feedback, admiration, abuse, etc, to: njn\@valgrind.org. 203 204END 205; 206 207# Used in various places of output. 208my $fancy = '-' x 80 . "\n"; 209 210#----------------------------------------------------------------------------- 211# Argument and option handling 212#----------------------------------------------------------------------------- 213sub process_cmd_line() 214{ 215 for my $arg (@ARGV) { 216 217 # Option handling 218 if ($arg =~ /^-/) { 219 220 # --version 221 if ($arg =~ /^-v$|^--version$/) { 222 die("cg_annotate-$version\n"); 223 224 # --show=A,B,C 225 } elsif ($arg =~ /^--show=(.*)$/) { 226 @show_events = split(/,/, $1); 227 228 # --sort=A,B,C 229 # Nb: You can specify thresholds individually, eg. 230 # --sort=A:99,B:95,C:90. These will override any --threshold 231 # argument. 232 } elsif ($arg =~ /^--sort=(.*)$/) { 233 @sort_events = split(/,/, $1); 234 my $th_specified = 0; 235 foreach my $i (0 .. scalar @sort_events - 1) { 236 if ($sort_events[$i] =~ /.*:([\d\.]+)%?$/) { 237 my $th = $1; 238 ($th >= 0 && $th <= 100) or die($usage); 239 $sort_events[$i] =~ s/:.*//; 240 $thresholds[$i] = $th; 241 $th_specified = 1; 242 } else { 243 $thresholds[$i] = 0; 244 } 245 } 246 if (not $th_specified) { 247 @thresholds = (); 248 } 249 250 # --threshold=X (tolerates a trailing '%') 251 } elsif ($arg =~ /^--threshold=([\d\.]+)%?$/) { 252 $single_threshold = $1; 253 ($1 >= 0 && $1 <= 100) or die($usage); 254 255 # --auto=yes|no 256 } elsif ($arg =~ /^--auto=yes$/) { 257 $auto_annotate = 1; 258 } elsif ($arg =~ /^--auto=no$/) { 259 $auto_annotate = 0; 260 261 # --context=N 262 } elsif ($arg =~ /^--context=([\d\.]+)$/) { 263 $context = $1; 264 if ($context < 0) { 265 die($usage); 266 } 267 268 # We don't handle "-I name" -- there can be no space. 269 } elsif ($arg =~ /^-I$/) { 270 die("Sorry, no space is allowed after a -I flag\n"); 271 272 # --include=A,B,C. Allow -I=name for backwards compatibility. 273 } elsif ($arg =~ /^(-I=|-I|--include=)(.*)$/) { 274 my $inc = $2; 275 $inc =~ s|/$||; # trim trailing '/' 276 push(@include_dirs, "$inc/"); 277 278 } elsif ($arg =~ /^--(\d+)$/) { 279 my $pid = $1; 280 if (not defined $input_file) { 281 $input_file = "cachegrind.out.$pid"; 282 } else { 283 die("One cachegrind.out.<pid> file at a time, please\n"); 284 } 285 286 } else { # -h and --help fall under this case 287 die($usage); 288 } 289 290 # Argument handling -- annotation file checking and selection. 291 # Stick filenames into a hash for quick 'n easy lookup throughout. 292 } else { 293 my $readable = 0; 294 foreach my $include_dir (@include_dirs) { 295 if (-r $include_dir . $arg) { 296 $readable = 1; 297 } 298 } 299 $readable or die("File $arg not found in any of: @include_dirs\n"); 300 $user_ann_files{$arg} = 1; 301 } 302 } 303 304 # Must have chosen an input file 305 if (not defined $input_file) { 306 die($usage); 307 } 308} 309 310#----------------------------------------------------------------------------- 311# Reading of input file 312#----------------------------------------------------------------------------- 313sub max ($$) 314{ 315 my ($x, $y) = @_; 316 return ($x > $y ? $x : $y); 317} 318 319# Add the two arrays; any '.' entries are ignored. Two tricky things: 320# 1. If $a2->[$i] is undefined, it defaults to 0 which is what we want; we turn 321# off warnings to allow this. This makes things about 10% faster than 322# checking for definedness ourselves. 323# 2. We don't add an undefined count or a ".", even though it's value is 0, 324# because we don't want to make an $a2->[$i] that is undef become 0 325# unnecessarily. 326sub add_array_a_to_b ($$) 327{ 328 my ($a1, $a2) = @_; 329 330 my $n = max(scalar @$a1, scalar @$a2); 331 $^W = 0; 332 foreach my $i (0 .. $n-1) { 333 $a2->[$i] += $a1->[$i] if (defined $a1->[$i] && "." ne $a1->[$i]); 334 } 335 $^W = 1; 336} 337 338# Add each event count to the CC array. '.' counts become undef, as do 339# missing entries (implicitly). 340sub line_to_CC ($) 341{ 342 my @CC = (split /\s+/, $_[0]); 343 (@CC <= @events) or die("Line $.: too many event counts\n"); 344 return \@CC; 345} 346 347sub read_input_file() 348{ 349 open(INPUTFILE, "< $input_file") || die "File $input_file not opened\n"; 350 351 # Read "desc:" lines. 352 my $line; 353 while ($line = <INPUTFILE>) { 354 if ($line =~ s/desc:\s+//) { 355 $desc .= $line; 356 } else { 357 last; 358 } 359 } 360 361 # Read "cmd:" line (Nb: will already be in $line from "desc:" loop above). 362 ($line =~ s/^cmd:\s+//) or die("Line $.: missing command line\n"); 363 $cmd = $line; 364 chomp($cmd); # Remove newline 365 366 # Read "events:" line. We make a temporary hash in which the Nth event's 367 # value is N, which is useful for handling --show/--sort options below. 368 $line = <INPUTFILE>; 369 (defined $line && $line =~ s/^events:\s+//) 370 or die("Line $.: missing events line\n"); 371 @events = split(/\s+/, $line); 372 my %events; 373 my $n = 0; 374 foreach my $event (@events) { 375 $events{$event} = $n; 376 $n++ 377 } 378 379 # If no --show arg give, default to showing all events in the file. 380 # If --show option is used, check all specified events appeared in the 381 # "events:" line. Then initialise @show_order. 382 if (@show_events) { 383 foreach my $show_event (@show_events) { 384 (defined $events{$show_event}) or 385 die("--show event `$show_event' did not appear in input\n"); 386 } 387 } else { 388 @show_events = @events; 389 } 390 foreach my $show_event (@show_events) { 391 push(@show_order, $events{$show_event}); 392 } 393 394 # Do as for --show, but if no --sort arg given, default to sorting by 395 # column order (ie. first column event is primary sort key, 2nd column is 396 # 2ndary key, etc). 397 if (@sort_events) { 398 foreach my $sort_event (@sort_events) { 399 (defined $events{$sort_event}) or 400 die("--sort event `$sort_event' did not appear in input\n"); 401 } 402 } else { 403 @sort_events = @events; 404 } 405 foreach my $sort_event (@sort_events) { 406 push(@sort_order, $events{$sort_event}); 407 } 408 409 # If multiple threshold args weren't given via --sort, stick in the single 410 # threshold (either from --threshold if used, or the default otherwise) for 411 # the primary sort event, and 0% for the rest. 412 if (not @thresholds) { 413 foreach my $e (@sort_order) { 414 push(@thresholds, 0); 415 } 416 $thresholds[0] = $single_threshold; 417 } 418 419 my $curr_file; 420 my $curr_fn; 421 my $curr_name; 422 423 my $curr_fn_CC = []; 424 my $curr_file_ind_CCs = {}; # hash(line_num => CC) 425 426 # Read body of input file. 427 while (<INPUTFILE>) { 428 s/#.*$//; # remove comments 429 if (s/^(\d+)\s+//) { 430 my $line_num = $1; 431 my $CC = line_to_CC($_); 432 add_array_a_to_b($CC, $curr_fn_CC); 433 434 # If curr_file is selected, add CC to curr_file list. We look for 435 # full filename matches; or, if auto-annotating, we have to 436 # remember everything -- we won't know until the end what's needed. 437 if ($auto_annotate || defined $user_ann_files{$curr_file}) { 438 my $tmp = $curr_file_ind_CCs->{$line_num}; 439 $tmp = [] unless defined $tmp; 440 add_array_a_to_b($CC, $tmp); 441 $curr_file_ind_CCs->{$line_num} = $tmp; 442 } 443 444 } elsif (s/^fn=(.*)$//) { 445 # Commit result from previous function 446 $fn_totals{$curr_name} = $curr_fn_CC if (defined $curr_name); 447 448 # Setup new one 449 $curr_fn = $1; 450 $curr_name = "$curr_file:$curr_fn"; 451 $curr_fn_CC = $fn_totals{$curr_name}; 452 $curr_fn_CC = [] unless (defined $curr_fn_CC); 453 454 } elsif (s/^fl=(.*)$//) { 455 $all_ind_CCs{$curr_file} = $curr_file_ind_CCs 456 if (defined $curr_file); 457 458 $curr_file = $1; 459 $curr_file_ind_CCs = $all_ind_CCs{$curr_file}; 460 $curr_file_ind_CCs = {} unless (defined $curr_file_ind_CCs); 461 462 } elsif (s/^\s*$//) { 463 # blank, do nothing 464 465 } elsif (s/^summary:\s+//) { 466 # Finish up handling final filename/fn_name counts 467 $fn_totals{"$curr_file:$curr_fn"} = $curr_fn_CC 468 if (defined $curr_file && defined $curr_fn); 469 $all_ind_CCs{$curr_file} = 470 $curr_file_ind_CCs if (defined $curr_file); 471 472 $summary_CC = line_to_CC($_); 473 (scalar(@$summary_CC) == @events) 474 or die("Line $.: summary event and total event mismatch\n"); 475 476 } else { 477 warn("WARNING: line $. malformed, ignoring\n"); 478 } 479 } 480 481 # Check if summary line was present 482 if (not defined $summary_CC) { 483 die("missing final summary line, aborting\n"); 484 } 485 486 close(INPUTFILE); 487} 488 489#----------------------------------------------------------------------------- 490# Print options used 491#----------------------------------------------------------------------------- 492sub print_options () 493{ 494 print($fancy); 495 print($desc); 496 print("Command: $cmd\n"); 497 print("Data file: $input_file\n"); 498 print("Events recorded: @events\n"); 499 print("Events shown: @show_events\n"); 500 print("Event sort order: @sort_events\n"); 501 print("Thresholds: @thresholds\n"); 502 503 my @include_dirs2 = @include_dirs; # copy @include_dirs 504 shift(@include_dirs2); # remove "" entry, which is always the first 505 unshift(@include_dirs2, "") if (0 == @include_dirs2); 506 my $include_dir = shift(@include_dirs2); 507 print("Include dirs: $include_dir\n"); 508 foreach my $include_dir (@include_dirs2) { 509 print(" $include_dir\n"); 510 } 511 512 my @user_ann_files = keys %user_ann_files; 513 unshift(@user_ann_files, "") if (0 == @user_ann_files); 514 my $user_ann_file = shift(@user_ann_files); 515 print("User annotated: $user_ann_file\n"); 516 foreach $user_ann_file (@user_ann_files) { 517 print(" $user_ann_file\n"); 518 } 519 520 my $is_on = ($auto_annotate ? "on" : "off"); 521 print("Auto-annotation: $is_on\n"); 522 print("\n"); 523} 524 525#----------------------------------------------------------------------------- 526# Print summary and sorted function totals 527#----------------------------------------------------------------------------- 528sub mycmp ($$) 529{ 530 my ($c, $d) = @_; 531 532 # Iterate through sort events (eg. 3,2); return result if two are different 533 foreach my $i (@sort_order) { 534 my ($x, $y); 535 $x = $c->[$i]; 536 $y = $d->[$i]; 537 $x = -1 unless defined $x; 538 $y = -1 unless defined $y; 539 540 my $cmp = $y <=> $x; # reverse sort 541 if (0 != $cmp) { 542 return $cmp; 543 } 544 } 545 # Exhausted events, equal 546 return 0; 547} 548 549sub commify ($) { 550 my ($val) = @_; 551 1 while ($val =~ s/^(\d+)(\d{3})/$1,$2/); 552 return $val; 553} 554 555# Because the counts can get very big, and we don't want to waste screen space 556# and make lines too long, we compute exactly how wide each column needs to be 557# by finding the widest entry for each one. 558sub compute_CC_col_widths (@) 559{ 560 my @CCs = @_; 561 my $CC_col_widths = []; 562 563 # Initialise with minimum widths (from event names) 564 foreach my $event (@events) { 565 push(@$CC_col_widths, length($event)); 566 } 567 568 # Find maximum width count for each column. @CC_col_width positions 569 # correspond to @CC positions. 570 foreach my $CC (@CCs) { 571 foreach my $i (0 .. scalar(@$CC)-1) { 572 if (defined $CC->[$i]) { 573 # Find length, accounting for commas that will be added 574 my $length = length $CC->[$i]; 575 my $clength = $length + int(($length - 1) / 3); 576 $CC_col_widths->[$i] = max($CC_col_widths->[$i], $clength); 577 } 578 } 579 } 580 return $CC_col_widths; 581} 582 583# Print the CC with each column's size dictated by $CC_col_widths. 584sub print_CC ($$) 585{ 586 my ($CC, $CC_col_widths) = @_; 587 588 foreach my $i (@show_order) { 589 my $count = (defined $CC->[$i] ? commify($CC->[$i]) : "."); 590 my $space = ' ' x ($CC_col_widths->[$i] - length($count)); 591 print("$space$count "); 592 } 593} 594 595sub print_events ($) 596{ 597 my ($CC_col_widths) = @_; 598 599 foreach my $i (@show_order) { 600 my $event = $events[$i]; 601 my $event_width = length($event); 602 my $col_width = $CC_col_widths->[$i]; 603 my $space = ' ' x ($col_width - $event_width); 604 print("$space$event "); 605 } 606} 607 608# Prints summary and function totals (with separate column widths, so that 609# function names aren't pushed over unnecessarily by huge summary figures). 610# Also returns a hash containing all the files that are involved in getting the 611# events count above the thresholds (ie. all the interesting ones). 612sub print_summary_and_fn_totals () 613{ 614 my @fn_fullnames = keys %fn_totals; 615 616 # Work out the size of each column for printing (summary and functions 617 # separately). 618 my $summary_CC_col_widths = compute_CC_col_widths($summary_CC); 619 my $fn_CC_col_widths = compute_CC_col_widths(values %fn_totals); 620 621 # Header and counts for summary 622 print($fancy); 623 print_events($summary_CC_col_widths); 624 print("\n"); 625 print($fancy); 626 print_CC($summary_CC, $summary_CC_col_widths); 627 print(" PROGRAM TOTALS\n"); 628 print("\n"); 629 630 # Header for functions 631 print($fancy); 632 print_events($fn_CC_col_widths); 633 print(" file:function\n"); 634 print($fancy); 635 636 # Sort function names into order dictated by --sort option. 637 @fn_fullnames = sort { 638 mycmp($fn_totals{$a}, $fn_totals{$b}) 639 } @fn_fullnames; 640 641 642 # Assertion 643 (scalar @sort_order == scalar @thresholds) or 644 die("sort_order length != thresholds length:\n", 645 " @sort_order\n @thresholds\n"); 646 647 my $threshold_files = {}; 648 # @curr_totals has the same shape as @sort_order and @thresholds 649 my @curr_totals = (); 650 foreach my $e (@thresholds) { 651 push(@curr_totals, 0); 652 } 653 654 # Print functions, stopping when the threshold has been reached. 655 foreach my $fn_name (@fn_fullnames) { 656 657 # Stop when we've reached all the thresholds 658 my $reached_all_thresholds = 1; 659 foreach my $i (0 .. scalar @thresholds - 1) { 660 my $prop = $curr_totals[$i] * 100 / $summary_CC->[$sort_order[$i]]; 661 $reached_all_thresholds &&= ($prop >= $thresholds[$i]); 662 } 663 last if $reached_all_thresholds; 664 665 # Print function results 666 my $fn_CC = $fn_totals{$fn_name}; 667 print_CC($fn_CC, $fn_CC_col_widths); 668 print(" $fn_name\n"); 669 670 # Update the threshold counts 671 my $filename = $fn_name; 672 $filename =~ s/:.+$//; # remove function name 673 $threshold_files->{$filename} = 1; 674 foreach my $i (0 .. scalar @sort_order - 1) { 675 $curr_totals[$i] += $fn_CC->[$sort_order[$i]] 676 if (defined $fn_CC->[$sort_order[$i]]); 677 } 678 } 679 print("\n"); 680 681 return $threshold_files; 682} 683 684#----------------------------------------------------------------------------- 685# Annotate selected files 686#----------------------------------------------------------------------------- 687 688# Issue a warning that the source file is more recent than the input file. 689sub warning_on_src_more_recent_than_inputfile ($) 690{ 691 my $src_file = $_[0]; 692 693 my $warning = <<END 694@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 695@@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ 696@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 697@ Source file '$src_file' is more recent than input file '$input_file'. 698@ Annotations may not be correct. 699@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 700 701END 702; 703 print($warning); 704} 705 706# If there is information about lines not in the file, issue a warning 707# explaining possible causes. 708sub warning_on_nonexistent_lines ($$$) 709{ 710 my ($src_more_recent_than_inputfile, $src_file, $excess_line_nums) = @_; 711 my $cause_and_solution; 712 713 if ($src_more_recent_than_inputfile) { 714 $cause_and_solution = <<END 715@@ cause: '$src_file' has changed since information was gathered. 716@@ If so, a warning will have already been issued about this. 717@@ solution: Recompile program and rerun under "valgrind --cachesim=yes" to 718@@ gather new information. 719END 720 # We suppress warnings about .h files 721 } elsif ($src_file =~ /\.h$/) { 722 $cause_and_solution = <<END 723@@ cause: bug in the Valgrind's debug info reader that screws up with .h 724@@ files sometimes 725@@ solution: none, sorry 726END 727 } else { 728 $cause_and_solution = <<END 729@@ cause: not sure, sorry 730END 731 } 732 733 my $warning = <<END 734@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 735@@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ 736@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 737@@ 738@@ Information recorded about lines past the end of '$src_file'. 739@@ 740@@ Probable cause and solution: 741$cause_and_solution@@ 742@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 743END 744; 745 print($warning); 746} 747 748sub annotate_ann_files($) 749{ 750 my ($threshold_files) = @_; 751 752 my %all_ann_files; 753 my @unfound_auto_annotate_files; 754 my $printed_totals_CC = []; 755 756 # If auto-annotating, add interesting files (but not "???") 757 if ($auto_annotate) { 758 delete $threshold_files->{"???"}; 759 %all_ann_files = (%user_ann_files, %$threshold_files) 760 } else { 761 %all_ann_files = %user_ann_files; 762 } 763 764 # Track if we did any annotations. 765 my $did_annotations = 0; 766 767 LOOP: 768 foreach my $src_file (keys %all_ann_files) { 769 770 my $opened_file = ""; 771 my $full_file_name = ""; 772 foreach my $include_dir (@include_dirs) { 773 my $try_name = $include_dir . $src_file; 774 if (open(INPUTFILE, "< $try_name")) { 775 $opened_file = $try_name; 776 $full_file_name = ($include_dir eq "" 777 ? $src_file 778 : "$include_dir + $src_file"); 779 last; 780 } 781 } 782 783 if (not $opened_file) { 784 # Failed to open the file. If chosen on the command line, die. 785 # If arose from auto-annotation, print a little message. 786 if (defined $user_ann_files{$src_file}) { 787 die("File $src_file not opened in any of: @include_dirs\n"); 788 789 } else { 790 push(@unfound_auto_annotate_files, $src_file); 791 } 792 793 } else { 794 # File header (distinguish between user- and auto-selected files). 795 print("$fancy"); 796 my $ann_type = 797 (defined $user_ann_files{$src_file} ? "User" : "Auto"); 798 print("-- $ann_type-annotated source: $full_file_name\n"); 799 print("$fancy"); 800 801 # Get file's CCs 802 my $src_file_CCs = $all_ind_CCs{$src_file}; 803 if (!defined $src_file_CCs) { 804 print(" No information has been collected for $src_file\n\n"); 805 next LOOP; 806 } 807 808 $did_annotations = 1; 809 810 # Numeric, not lexicographic sort! 811 my @line_nums = sort {$a <=> $b} keys %$src_file_CCs; 812 813 # If $src_file more recent than cachegrind.out, issue warning 814 my $src_more_recent_than_inputfile = 0; 815 if ((stat $opened_file)[9] > (stat $input_file)[9]) { 816 $src_more_recent_than_inputfile = 1; 817 warning_on_src_more_recent_than_inputfile($src_file); 818 } 819 820 # Work out the size of each column for printing 821 my $CC_col_widths = compute_CC_col_widths(values %$src_file_CCs); 822 823 # Events header 824 print_events($CC_col_widths); 825 print("\n\n"); 826 827 # Shift out 0 if it's in the line numbers (from unknown entries, 828 # likely due to bugs in Valgrind's stabs debug info reader) 829 shift(@line_nums) if (0 == $line_nums[0]); 830 831 # Finds interesting line ranges -- all lines with a CC, and all 832 # lines within $context lines of a line with a CC. 833 my $n = @line_nums; 834 my @pairs; 835 for (my $i = 0; $i < $n; $i++) { 836 push(@pairs, $line_nums[$i] - $context); # lower marker 837 while ($i < $n-1 && 838 $line_nums[$i] + 2*$context >= $line_nums[$i+1]) { 839 $i++; 840 } 841 push(@pairs, $line_nums[$i] + $context); # upper marker 842 } 843 844 # Annotate chosen lines, tracking total counts of lines printed 845 $pairs[0] = 1 if ($pairs[0] < 1); 846 while (@pairs) { 847 my $low = shift @pairs; 848 my $high = shift @pairs; 849 while ($. < $low-1) { 850 my $tmp = <INPUTFILE>; 851 last unless (defined $tmp); # hack to detect EOF 852 } 853 my $src_line; 854 # Print line number, unless start of file 855 print("-- line $low " . '-' x 40 . "\n") if ($low != 1); 856 while (($. < $high) && ($src_line = <INPUTFILE>)) { 857 if (defined $line_nums[0] && $. == $line_nums[0]) { 858 print_CC($src_file_CCs->{$.}, $CC_col_widths); 859 add_array_a_to_b($src_file_CCs->{$.}, 860 $printed_totals_CC); 861 shift(@line_nums); 862 863 } else { 864 print_CC( [], $CC_col_widths); 865 } 866 867 print(" $src_line"); 868 } 869 # Print line number, unless EOF 870 if ($src_line) { 871 print("-- line $high " . '-' x 40 . "\n"); 872 } else { 873 last; 874 } 875 } 876 877 # If there was info on lines past the end of the file... 878 if (@line_nums) { 879 foreach my $line_num (@line_nums) { 880 print_CC($src_file_CCs->{$line_num}, $CC_col_widths); 881 print(" <bogus line $line_num>\n"); 882 } 883 print("\n"); 884 warning_on_nonexistent_lines($src_more_recent_than_inputfile, 885 $src_file, \@line_nums); 886 } 887 print("\n"); 888 889 # Print summary of counts attributed to file but not to any 890 # particular line (due to incomplete debug info). 891 if ($src_file_CCs->{0}) { 892 print_CC($src_file_CCs->{0}, $CC_col_widths); 893 print(" <counts for unidentified lines in $src_file>\n\n"); 894 } 895 896 close(INPUTFILE); 897 } 898 } 899 900 # Print list of unfound auto-annotate selected files. 901 if (@unfound_auto_annotate_files) { 902 print("$fancy"); 903 print("The following files chosen for auto-annotation could not be found:\n"); 904 print($fancy); 905 foreach my $f (@unfound_auto_annotate_files) { 906 print(" $f\n"); 907 } 908 print("\n"); 909 } 910 911 # If we did any annotating, print what proportion of events were covered by 912 # annotated lines above. 913 if ($did_annotations) { 914 my $percent_printed_CC; 915 foreach (my $i = 0; $i < @$summary_CC; $i++) { 916 $percent_printed_CC->[$i] = 917 sprintf("%.0f", 918 $printed_totals_CC->[$i] / $summary_CC->[$i] * 100); 919 } 920 my $pp_CC_col_widths = compute_CC_col_widths($percent_printed_CC); 921 print($fancy); 922 print_events($pp_CC_col_widths); 923 print("\n"); 924 print($fancy); 925 print_CC($percent_printed_CC, $pp_CC_col_widths); 926 print(" percentage of events annotated\n\n"); 927 } 928} 929 930#---------------------------------------------------------------------------- 931# "main()" 932#---------------------------------------------------------------------------- 933process_cmd_line(); 934read_input_file(); 935print_options(); 936my $threshold_files = print_summary_and_fn_totals(); 937annotate_ann_files($threshold_files); 938 939##--------------------------------------------------------------------## 940##--- end cg_annotate.in ---## 941##--------------------------------------------------------------------## 942 943 944