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