1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#! /usr/bin/perl -w
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--------------------------------------------------------------------##
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--- The cache simulation framework: instrumentation, recording   ---##
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--- and results printing.                                        ---##
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##---                                           callgrind_annotate ---##
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--------------------------------------------------------------------##
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  This file is part of Callgrind, a cache-simulator and call graph
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  tracer built on Valgrind.
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  Copyright (C) 2003 Josef Weidendorfer
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     Josef.Weidendorfer@gmx.de
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  This file is based heavily on cg_annotate, part of Valgrind.
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  Copyright (C) 2002 Nicholas Nethercote
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     njn@valgrind.org
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  This program is free software; you can redistribute it and/or
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  modify it under the terms of the GNU General Public License as
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  published by the Free Software Foundation; either version 2 of the
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  License, or (at your option) any later version.
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  This program is distributed in the hope that it will be useful, but
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  WITHOUT ANY WARRANTY; without even the implied warranty of
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  General Public License for more details.
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  You should have received a copy of the GNU General Public License
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  along with this program; if not, write to the Free Software
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  02111-1307, USA.
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  The GNU General Public License is contained in the file COPYING.
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Annotator for cachegrind/callgrind. 
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# File format is described in /docs/techdocs.html.
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Performance improvements record, using cachegrind.out for cacheprof, doing no
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# source annotation (irrelevant ones removed):
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#                                                               user time
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# 1. turned off warnings in add_hash_a_to_b()                   3.81 --> 3.48s
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    [now add_array_a_to_b()]
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# 6. make line_to_CC() return a ref instead of a hash           3.01 --> 2.77s
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#10. changed file format to avoid file/fn name repetition       2.40s
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    (not sure why higher;  maybe due to new '.' entries?)
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#11. changed file format to drop unnecessary end-line "."s      2.36s
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    (shrunk file by about 37%)
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#12. switched from hash CCs to array CCs                        1.61s
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#13. only adding b[i] to a[i] if b[i] defined (was doing it if
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    either a[i] or b[i] was defined, but if b[i] was undefined
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    it just added 0)                                           1.48s
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#14. Stopped converting "." entries to undef and then back      1.16s
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#15. Using foreach $i (x..y) instead of for ($i = 0...) in
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    add_array_a_to_b()                                         1.11s
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Auto-annotating primes:
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#16. Finding count lengths by int((length-1)/3), not by
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    commifying (halves the number of commify calls)            1.68s --> 1.47s
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownuse strict;
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Overview: the running example in the comments is for:
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#   - events = A,B,C,D
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#   - --show=C,A,D
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#   - --sort=D,C
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Global variables, main data structures
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# CCs are arrays, the counts corresponding to @events, with 'undef'
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# representing '.'.  This makes things fast (faster than using hashes for CCs)
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# but we have to use @sort_order and @show_order below to handle the --sort and
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# --show options, which is a bit tricky.
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Total counts for summary (an array reference).
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $summary_CC;
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $totals_CC;
84436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovmy $summary_calculated = 0;
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Totals for each function, for overall summary.
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash(filename:fn_name => CC array)
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy %fn_totals;
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Individual CCs, organised by filename and line_num for easy annotation.
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash(filename => hash(line_num => CC array))
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy %all_ind_CCs;
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Files chosen for annotation on the command line.  
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# key = basename (trimmed of any directory), value = full filename
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy %user_ann_files;
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Generic description string.
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $desc = "";
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Command line of profiled program.
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $cmd = "";
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Info on the profiled process.
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $creator = "";
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $pid = "";
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $part = "";
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $thread = "";
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Positions used for cost lines; default: line numbers
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $has_line = 1;
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $has_addr = 0;
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Events in input file, eg. (A,B,C,D)
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @events;
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $events;
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Events to show, from command line, eg. (C,A,D)
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @show_events;
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Map from @show_events indices to @events indices, eg. (2,0,3).  Gives the
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# order in which we must traverse @events in order to show the @show_events, 
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# eg. (@events[$show_order[1]], @events[$show_order[2]]...) = @show_events.
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# (Might help to think of it like a hash (0 => 2, 1 => 0, 2 => 3).)
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @show_order;
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Print out the function totals sorted by these events, eg. (D,C).
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @sort_events;
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Map from @sort_events indices to @events indices, eg. (3,2).  Same idea as
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# for @show_order.
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @sort_order;
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Thresholds, one for each sort event (or default to 1 if no sort events
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# specified).  We print out functions and do auto-annotations until we've
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# handled this proportion of all the events thresholded.
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @thresholds;
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $default_threshold = 99;
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $single_threshold  = $default_threshold;
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# If on, automatically annotates all files that are involved in getting over
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# all the threshold counts.
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $auto_annotate = 0;
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Number of lines to show around each annotated line.
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $context = 8;
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Directories in which to look for annotation files.
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @include_dirs = ("");
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Verbose mode
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $verbose = "1";
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Inclusive statistics (with subroutine events)
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $inclusive = 0;
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Inclusive totals for each function, for overall summary.
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash(filename:fn_name => CC array)
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy %cfn_totals;
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash( file:func => [ called file:func ])
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $called_funcs;
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash( file:func => [ calling file:func ])
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $calling_funcs;
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash( file:func,line => [called file:func ])
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $called_from_line;
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash( file:func,line => file:func
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy %func_of_line;
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash (file:func => object name)
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy %obj_name;
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Print out the callers of a function
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $tree_caller = 0;
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Print out the called functions
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $tree_calling = 0;
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash( file:func,cfile:cfunc => call CC[])
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy %call_CCs;
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash( file:func,cfile:cfunc => call counter)
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy %call_counter;
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# hash(context, index) => realname for compressed traces
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy %compressed;
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Input file name, will be set in process_cmd_line
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $input_file = "";
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Version number
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $version = "@VERSION@";
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Usage message.
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $usage = <<END
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownusage: callgrind_annotate [options] [callgrind-out-file [source-files...]]
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  options for the user, with defaults in [ ], are:
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    -h --help             show this message
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --version             show version
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --show=A,B,C          only show figures for events A,B,C [all]
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --sort=A,B,C          sort columns by events A,B,C [event column order]
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --threshold=<0--100>  percentage of counts (of primary sort event) we
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          are interested in [$default_threshold%]
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --auto=yes|no         annotate all source files containing functions
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          that helped reach the event count threshold [no]
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --context=N           print N lines of context before and after
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          annotated lines [8]
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --inclusive=yes|no    add subroutine costs to functions calls [no]
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --tree=none|caller|   print for each function their callers,
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           calling|both   the called functions or both [none]
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    -I --include=<dir>    add <dir> to list of directories to search for 
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          source files
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownEND
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown;
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Used in various places of output.
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $fancy = '-' x 80 . "\n";
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Argument and option handling
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub process_cmd_line() 
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    for my $arg (@ARGV) { 
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Option handling
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if ($arg =~ /^-/) {
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # --version
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ($arg =~ /^--version$/) {
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                die("callgrind_annotate-$version\n");
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # --show=A,B,C
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^--show=(.*)$/) {
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                @show_events = split(/,/, $1);
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # --sort=A,B,C
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^--sort=(.*)$/) {
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                @sort_events = split(/,/, $1);
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                my $th_specified = 0;
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                foreach my $i (0 .. scalar @sort_events - 1) {
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    if ($sort_events[$i] =~ /.*:([\d\.]+)%?$/) {
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        my $th = $1;
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        ($th >= 0 && $th <= 100) or die($usage);
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        $sort_events[$i] =~ s/:.*//;
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        $thresholds[$i] = $th;
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        $th_specified = 1;
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    } else {
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        $thresholds[$i] = 0;
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    }
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                }
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                if (not $th_specified) {
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    @thresholds = ();
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                }
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # --threshold=X (tolerates a trailing '%')
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^--threshold=([\d\.]+)%?$/) {
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $single_threshold = $1;
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ($1 >= 0 && $1 <= 100) or die($usage);
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # --auto=yes|no
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^--auto=(yes|no)$/) {
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $auto_annotate = 1 if ($1 eq "yes");
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $auto_annotate = 0 if ($1 eq "no");
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # --context=N
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^--context=([\d\.]+)$/) {
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $context = $1;
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                if ($context < 0) {
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    die($usage);
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                }
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # --inclusive=yes|no
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^--inclusive=(yes|no)$/) {
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $inclusive = 1 if ($1 eq "yes");
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $inclusive = 0 if ($1 eq "no");
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # --tree=none|caller|calling|both
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^--tree=(none|caller|calling|both)$/) {
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $tree_caller  = 1 if ($1 eq "caller" || $1 eq "both");
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $tree_calling = 1 if ($1 eq "calling" || $1 eq "both");
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # --include=A,B,C
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^(-I|--include)=(.*)$/) {
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                my $inc = $2;
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $inc =~ s|/$||;         # trim trailing '/'
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                push(@include_dirs, "$inc/");
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {            # -h and --help fall under this case
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                die($usage);
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Argument handling -- annotation file checking and selection.
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Stick filenames into a hash for quick 'n easy lookup throughout
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } else {
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  if ($input_file eq "") {
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    $input_file = $arg;
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  }
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  else {
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $readable = 0;
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            foreach my $include_dir (@include_dirs) {
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                if (-r $include_dir . $arg) {
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    $readable = 1;
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                }
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $readable or die("File $arg not found in any of: @include_dirs\n");
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $user_ann_files{$arg} = 1;
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } 
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($input_file eq "") {
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      $input_file = (<callgrind.out*>)[0];
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!defined $input_file) {
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $input_file = (<cachegrind.out*>)[0];
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (defined $input_file) or die($usage);
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      print "Reading data from '$input_file'...\n";
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Reading of input file
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub max ($$) 
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($x, $y) = @_;
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return ($x > $y ? $x : $y);
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Add the two arrays;  any '.' entries are ignored.  Two tricky things:
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# 1. If $a2->[$i] is undefined, it defaults to 0 which is what we want; we turn
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    off warnings to allow this.  This makes things about 10% faster than
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    checking for definedness ourselves.
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# 2. We don't add an undefined count or a ".", even though it's value is 0,
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    because we don't want to make an $a2->[$i] that is undef become 0
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    unnecessarily.
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub add_array_a_to_b ($$) 
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($a1, $a2) = @_;
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $n = max(scalar @$a1, scalar @$a2);
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    $^W = 0;
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $i (0 .. $n-1) {
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $a2->[$i] += $a1->[$i] if (defined $a1->[$i] && "." ne $a1->[$i]);
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    $^W = 1;
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Is this a line with all events zero?
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub is_zero ($)
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($CC) = @_;
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $isZero = 1;
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $i (0 .. (scalar @$CC)-1) {
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	$isZero = 0 if ($CC->[$i] >0);
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return $isZero;
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Add each event count to the CC array.  '.' counts become undef, as do
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# missing entries (implicitly).
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub line_to_CC ($)
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my @CC = (split /\s+/, $_[0]);
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    (@CC <= @events) or die("Line $.: too many event counts\n");
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return \@CC;
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub uncompressed_name($$)
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   my ($context, $name) = @_;
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ($name =~ /^\((\d+)\)\s*(.*)$/) {
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     my $index = $1;
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     my $realname = $2;
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ($realname eq "") {
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       $realname = $compressed{$context,$index};
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else {
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       $compressed{$context,$index} = $realname;
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return $realname;
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return $name;
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub read_input_file() 
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    open(INPUTFILE, "< $input_file") || die "File $input_file not opened\n";
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $line;
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Read header
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    while(<INPUTFILE>) {
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      # remove comments
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s/#.*$//;
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (/^$/) { ; }
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elsif (/^version:\s*(\d+)/) {
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	# Can't read format with major version > 1
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	($1<2) or die("Can't read format with major version $1.\n");
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elsif (/^pid:\s+(.*)$/) { $pid = $1;  }
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elsif (/^thread:\s+(.*)$/) { $thread = $1;  }
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elsif (/^part:\s+(.*)$/) { $part = $1;  }
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elsif (/^desc:\s+(.*)$/) {
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	my $dline = $1;
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	# suppress profile options in description output
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ($dline =~ /^Option:/) {;}
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	else { $desc .= "$dline\n"; }
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elsif (/^cmd:\s+(.*)$/)  { $cmd = $1; }
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elsif (/^creator:\s+(.*)$/)  { $creator = $1; }
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elsif (/^positions:\s+(.*)$/) {
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	my $positions = $1;
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	$has_line = ($positions =~ /line/);
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	$has_addr = ($positions =~ /(addr|instr)/);
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elsif (/^events:\s+(.*)$/) {
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	$events = $1;
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	# events line is last in header
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	last;
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else {
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	warn("WARNING: header line $. malformed, ignoring\n");
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ($verbose) { chomp; warn("    line: '$_'\n"); }
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Read "events:" line.  We make a temporary hash in which the Nth event's
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # value is N, which is useful for handling --show/--sort options below.
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    ($events ne "") or die("Line $.: missing events line\n");
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    @events = split(/\s+/, $events);
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my %events;
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $n = 0;
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $event (@events) {
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $events{$event} = $n;
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $n++
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # If no --show arg give, default to showing all events in the file.
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # If --show option is used, check all specified events appeared in the
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # "events:" line.  Then initialise @show_order.
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (@show_events) {
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach my $show_event (@show_events) {
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (defined $events{$show_event}) or 
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                die("--show event `$show_event' did not appear in input\n");
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    } else {
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        @show_events = @events;
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $show_event (@show_events) {
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        push(@show_order, $events{$show_event});
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Do as for --show, but if no --sort arg given, default to sorting by
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # column order (ie. first column event is primary sort key, 2nd column is
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # 2ndary key, etc).
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (@sort_events) {
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach my $sort_event (@sort_events) {
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (defined $events{$sort_event}) or 
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                die("--sort event `$sort_event' did not appear in input\n");
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    } else {
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        @sort_events = @events;
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $sort_event (@sort_events) {
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        push(@sort_order, $events{$sort_event});
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # If multiple threshold args weren't given via --sort, stick in the single
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # threshold (either from --threshold if used, or the default otherwise) for
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # the primary sort event, and 0% for the rest.
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (not @thresholds) {
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach my $e (@sort_order) {
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            push(@thresholds, 0);
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $thresholds[0] = $single_threshold;
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Current directory, used to strip from file names if absolute
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $pwd = `pwd`;
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    chomp $pwd;
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    $pwd .= '/';
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_obj = "";
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_file;
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_fn;
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_name;
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_line_num = 0;
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $prev_line_num = 0;
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_cobj = "";
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_cfile = "";
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_cfunc = "";
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_cname;
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_call_counter = 0;
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_cfn_CC = [];
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_fn_CC = [];
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $curr_file_ind_CCs = {};     # hash(line_num => CC)
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Read body of input file.
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    while (<INPUTFILE>) {
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	$prev_line_num = $curr_line_num;
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        s/#.*$//;   # remove comments
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        s/^\+(\d+)/$prev_line_num+$1/e;
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        s/^\-(\d+)/$prev_line_num-$1/e;
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        s/^\*/$prev_line_num/e;
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (s/^(-?\d+|0x\w+)\s+//) {
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_line_num = $1;
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    if ($has_addr) {
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      if ($has_line) {
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                s/^\+(\d+)/$prev_line_num+$1/e;
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	        s/^\-(\d+)/$prev_line_num-$1/e;
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                s/^\*/$prev_line_num/e;
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	        if (s/^(\d+)\s+//) { $curr_line_num = $1; }
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      else { $curr_line_num = 0; }
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    }
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $CC = line_to_CC($_);
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    if ($curr_call_counter>0) {
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#	      print "Read ($curr_name => $curr_cname) $curr_call_counter\n";
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
542f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root	      if (!defined $call_CCs{$curr_name,$curr_cname}) {
543f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root		$call_CCs{$curr_name,$curr_cname} = [];
544f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root		$call_counter{$curr_name,$curr_cname} = 0;
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
546f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root	      add_array_a_to_b($CC, $call_CCs{$curr_name,$curr_cname});
547f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root	      $call_counter{$curr_name,$curr_cname} += $curr_call_counter;
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      my $tmp = $called_from_line->{$curr_file,$curr_line_num};
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      if (!defined $tmp) {
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		$func_of_line{$curr_file,$curr_line_num} = $curr_name;
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      $tmp = {} unless defined $tmp;
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      $$tmp{$curr_cname} = 1;
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      $called_from_line->{$curr_file,$curr_line_num} = $tmp;
556f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root	      if (!defined $call_CCs{$curr_name,$curr_cname,$curr_line_num}) {
557f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root		$call_CCs{$curr_name,$curr_cname,$curr_line_num} = [];
558f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root		$call_counter{$curr_name,$curr_cname,$curr_line_num} = 0;
559f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root	      }
560f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root	      add_array_a_to_b($CC, $call_CCs{$curr_name,$curr_cname,$curr_line_num});
561f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root	      $call_counter{$curr_name,$curr_cname,$curr_line_num} += $curr_call_counter;
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      $curr_call_counter = 0;
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      # inclusive costs
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      $curr_cfn_CC = $cfn_totals{$curr_cname};
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      $curr_cfn_CC = [] unless (defined $curr_cfn_CC);
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      add_array_a_to_b($CC, $curr_cfn_CC);
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      $cfn_totals{$curr_cname} = $curr_cfn_CC;
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      if ($inclusive) {
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		add_array_a_to_b($CC, $curr_fn_CC);
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      next;
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    }
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add_array_a_to_b($CC, $curr_fn_CC);
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # If curr_file is selected, add CC to curr_file list.  We look for
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # full filename matches;  or, if auto-annotating, we have to
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # remember everything -- we won't know until the end what's needed.
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ($auto_annotate || defined $user_ann_files{$curr_file}) {
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                my $tmp = $curr_file_ind_CCs->{$curr_line_num};
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $tmp = [] unless defined $tmp;
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                add_array_a_to_b($CC, $tmp);
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $curr_file_ind_CCs->{$curr_line_num} = $tmp;
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^fn=(.*)$//) {
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Commit result from previous function
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $fn_totals{$curr_name} = $curr_fn_CC if (defined $curr_name);
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Setup new one
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_fn = uncompressed_name("fn",$1);
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_name = "$curr_file:$curr_fn";
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    $obj_name{$curr_name} = $curr_obj;
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_fn_CC = $fn_totals{$curr_name};
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_fn_CC = [] unless (defined $curr_fn_CC);
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^ob=(.*)$//) {
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_obj = uncompressed_name("ob",$1);
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^fl=(.*)$//) {
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $all_ind_CCs{$curr_file} = $curr_file_ind_CCs 
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                if (defined $curr_file);
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_file = uncompressed_name("fl",$1);
608b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            $curr_file =~ s/^\Q$pwd\E//;
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_file_ind_CCs = $all_ind_CCs{$curr_file};
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_file_ind_CCs = {} unless (defined $curr_file_ind_CCs);
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^(fi|fe)=(.*)$//) {
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (defined $curr_name) or die("Line $.: Unexpected fi/fe line\n");
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $fn_totals{$curr_name} = $curr_fn_CC;
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $all_ind_CCs{$curr_file} = $curr_file_ind_CCs;
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_file = uncompressed_name("fl",$2);
618b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            $curr_file =~ s/^\Q$pwd\E//;
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_name = "$curr_file:$curr_fn";
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_file_ind_CCs = $all_ind_CCs{$curr_file};
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_file_ind_CCs = {} unless (defined $curr_file_ind_CCs);
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_fn_CC = $fn_totals{$curr_name};
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_fn_CC = [] unless (defined $curr_fn_CC);
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^\s*$//) {
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # blank, do nothing
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^cob=(.*)$//) {
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $curr_cobj = uncompressed_name("ob",$1);
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
631436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	} elsif (s/^cf[il]=(.*)$//) {
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $curr_cfile = uncompressed_name("fl",$1);
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	} elsif (s/^cfn=(.*)$//) {
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $curr_cfunc = uncompressed_name("fn",$1);
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  if ($curr_cfile eq "") {
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    $curr_cname = "$curr_file:$curr_cfunc";
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  }
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  else {
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    $curr_cname = "$curr_cfile:$curr_cfunc";
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    $curr_cfile = "";
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  }
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  my $tmp = $calling_funcs->{$curr_cname};
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $tmp = {} unless defined $tmp;
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $$tmp{$curr_name} = 1;
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $calling_funcs->{$curr_cname} = $tmp;
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  my $tmp2 = $called_funcs->{$curr_name};
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $tmp2 = {} unless defined $tmp2;
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $$tmp2{$curr_cname} = 1;
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $called_funcs->{$curr_name} = $tmp2;
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	} elsif (s/^calls=(\d+)//) {
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  $curr_call_counter = $1;
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^(jump|jcnd)=//) {
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  #ignore jump information
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^jfi=(.*)$//) {
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          # side effect needed: possibly add compression mapping 
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          uncompressed_name("fl",$1);
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          # ignore jump information	
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^jfn=(.*)$//) {
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          # side effect needed: possibly add compression mapping
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          uncompressed_name("fn",$1);
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          # ignore jump information
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^totals:\s+//) {
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    $totals_CC = line_to_CC($_);
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (s/^summary:\s+//) {
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $summary_CC = line_to_CC($_);
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } else {
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            warn("WARNING: line $. malformed, ignoring\n");
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    if ($verbose) { chomp; warn("    line: '$_'\n"); }
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Finish up handling final filename/fn_name counts
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    $fn_totals{"$curr_file:$curr_fn"} = $curr_fn_CC
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (defined $curr_file && defined $curr_fn);
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    $all_ind_CCs{$curr_file} =
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	$curr_file_ind_CCs if (defined $curr_file);
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Correct inclusive totals
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($inclusive) {
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      foreach my $name (keys %cfn_totals) {
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	$fn_totals{$name} = $cfn_totals{$name};
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    close(INPUTFILE);
696436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
697436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    if ((not defined $summary_CC) || is_zero($summary_CC)) {
698436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	$summary_CC = $totals_CC;
699436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
700436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	# if neither 'summary:' nor 'totals:' line is given,
701436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	# calculate summary from fn_totals hash
702436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	if ((not defined $summary_CC) || is_zero($summary_CC)) {
703436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	    $summary_calculated = 1;
704436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	    $summary_CC = [];
705436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	    foreach my $name (keys %fn_totals) {
706436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		add_array_a_to_b($fn_totals{$name}, $summary_CC);
707436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	    }
708436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	}
709436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    }
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Print options used
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub print_options ()
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print($fancy);
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print "Profile data file '$input_file'";
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($creator ne "") { print " (creator: $creator)"; }
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print "\n";
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print($fancy);
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print($desc);
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $target = $cmd;
725436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    if ($target eq "") { $target = "(unknown)"; }
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($pid ne "") {
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      $target .= " (PID $pid";
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ($part ne "") { $target .= ", part $part"; }
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ($thread ne "") { $target .= ", thread $thread"; }
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      $target .= ")";
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("Profiled target:  $target\n");
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("Events recorded:  @events\n");
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("Events shown:     @show_events\n");
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("Event sort order: @sort_events\n");
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("Thresholds:       @thresholds\n");
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my @include_dirs2 = @include_dirs;  # copy @include_dirs
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    shift(@include_dirs2);       # remove "" entry, which is always the first
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    unshift(@include_dirs2, "") if (0 == @include_dirs2); 
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $include_dir = shift(@include_dirs2);
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("Include dirs:     $include_dir\n");
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $include_dir (@include_dirs2) {
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print("                  $include_dir\n");
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my @user_ann_files = keys %user_ann_files;
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    unshift(@user_ann_files, "") if (0 == @user_ann_files); 
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $user_ann_file = shift(@user_ann_files);
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("User annotated:   $user_ann_file\n");
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach $user_ann_file (@user_ann_files) {
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print("                  $user_ann_file\n");
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $is_on = ($auto_annotate ? "on" : "off");
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("Auto-annotation:  $is_on\n");
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("\n");
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Print summary and sorted function totals
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub mycmp ($$) 
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($c, $d) = @_;
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Iterate through sort events (eg. 3,2); return result if two are different
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $i (@sort_order) {
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my ($x, $y);
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $x = $c->[$i];
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $y = $d->[$i];
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $x = -1 unless defined $x;
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $y = -1 unless defined $y;
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $cmp = $y <=> $x;        # reverse sort
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (0 != $cmp) {
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return $cmp;
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Exhausted events, equal
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return 0;
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub commify ($) {
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($val) = @_;
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    1 while ($val =~ s/^(\d+)(\d{3})/$1,$2/);
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return $val;
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Because the counts can get very big, and we don't want to waste screen space
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# and make lines too long, we compute exactly how wide each column needs to be
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# by finding the widest entry for each one.
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub compute_CC_col_widths (@) 
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my @CCs = @_;
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $CC_col_widths = [];
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Initialise with minimum widths (from event names)
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $event (@events) {
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        push(@$CC_col_widths, length($event));
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Find maximum width count for each column.  @CC_col_width positions
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # correspond to @CC positions.
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $CC (@CCs) {
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach my $i (0 .. scalar(@$CC)-1) {
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (defined $CC->[$i]) {
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                # Find length, accounting for commas that will be added
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                my $length = length $CC->[$i];
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                my $clength = $length + int(($length - 1) / 3);
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $CC_col_widths->[$i] = max($CC_col_widths->[$i], $clength); 
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return $CC_col_widths;
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Print the CC with each column's size dictated by $CC_col_widths.
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub print_CC ($$) 
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($CC, $CC_col_widths) = @_;
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $i (@show_order) {
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $count = (defined $CC->[$i] ? commify($CC->[$i]) : ".");
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $space = ' ' x ($CC_col_widths->[$i] - length($count));
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print("$space$count ");
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub print_events ($)
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($CC_col_widths) = @_;
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $i (@show_order) { 
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $event       = $events[$i];
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $event_width = length($event);
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $col_width   = $CC_col_widths->[$i];
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $space       = ' ' x ($col_width - $event_width);
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print("$space$event ");
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Prints summary and function totals (with separate column widths, so that
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# function names aren't pushed over unnecessarily by huge summary figures).
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Also returns a hash containing all the files that are involved in getting the
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# events count above the thresholds (ie. all the interesting ones).
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub print_summary_and_fn_totals ()
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my @fn_fullnames = keys   %fn_totals;
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Work out the size of each column for printing (summary and functions
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # separately).
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $summary_CC_col_widths = compute_CC_col_widths($summary_CC);
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my      $fn_CC_col_widths = compute_CC_col_widths(values %fn_totals);
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Header and counts for summary
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print($fancy);
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print_events($summary_CC_col_widths);
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("\n");
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print($fancy);
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print_CC($summary_CC, $summary_CC_col_widths);
862436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    print(" PROGRAM TOTALS");
863436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    if ($summary_calculated) {
864436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	print(" (calculated)");
865436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    }
866436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    print("\n\n");
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Header for functions
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print($fancy);
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print_events($fn_CC_col_widths);
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print(" file:function\n");
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print($fancy);
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Sort function names into order dictated by --sort option.
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    @fn_fullnames = sort {
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        mycmp($fn_totals{$a}, $fn_totals{$b})
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    } @fn_fullnames;
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Assertion
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    (scalar @sort_order == scalar @thresholds) or 
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        die("sort_order length != thresholds length:\n",
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "  @sort_order\n  @thresholds\n");
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $threshold_files       = {};
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # @curr_totals has the same shape as @sort_order and @thresholds
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my @curr_totals = ();
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $e (@thresholds) {
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        push(@curr_totals, 0);
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Print functions, stopping when the threshold has been reached.
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $fn_name (@fn_fullnames) {
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Stop when we've reached all the thresholds
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $reached_all_thresholds = 1;
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach my $i (0 .. scalar @thresholds - 1) {
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $prop = $curr_totals[$i] * 100;
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    if ($summary_CC->[$sort_order[$i]] >0) {
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      $prop = $prop / $summary_CC->[$sort_order[$i]];
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    }
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $reached_all_thresholds &&= ($prop >= $thresholds[$i]);
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        last if $reached_all_thresholds;
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ($tree_caller || $tree_calling) { print "\n"; }
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ($tree_caller && ($fn_name ne "???:???")) {
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  # Print function callers
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  my $tmp1 = $calling_funcs->{$fn_name};
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  if (defined $tmp1) {
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    foreach my $calling (keys %$tmp1) {
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      if (defined $call_counter{$calling,$fn_name}) {
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		print_CC($call_CCs{$calling,$fn_name}, $fn_CC_col_widths);
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		print" < $calling (";
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		print $call_counter{$calling,$fn_name} . "x)";
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if (defined $obj_name{$calling}) {
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  print " [$obj_name{$calling}]";
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		}
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		print "\n";
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    }
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  }
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Print function results
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $fn_CC = $fn_totals{$fn_name};
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print_CC($fn_CC, $fn_CC_col_widths);
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ($tree_caller || $tree_calling) { print " * "; }
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print(" $fn_name");
931436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	if ((defined $obj_name{$fn_name}) &&
932436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	    ($obj_name{$fn_name} ne "")) {
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  print " [$obj_name{$fn_name}]";
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	print "\n";
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ($tree_calling && ($fn_name ne "???:???")) {
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  # Print called functions
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  my $tmp2 = $called_funcs->{$fn_name};
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  if (defined $tmp2) {
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    foreach my $called (keys %$tmp2) {
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      if (defined $call_counter{$fn_name,$called}) {
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		print_CC($call_CCs{$fn_name,$called}, $fn_CC_col_widths);
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		print" >   $called (";
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		print $call_counter{$fn_name,$called} . "x)";
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if (defined $obj_name{$called}) {
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  print " [$obj_name{$called}]";
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		}
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		print "\n";
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    }
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  }
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Update the threshold counts
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $filename = $fn_name;
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $filename =~ s/:.+$//;    # remove function name
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $threshold_files->{$filename} = 1;
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach my $i (0 .. scalar @sort_order - 1) {
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  if ($inclusive) {
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    $curr_totals[$i] = $summary_CC->[$sort_order[$i]] -
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               $fn_CC->[$sort_order[$i]]
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      if (defined $fn_CC->[$sort_order[$i]]);
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	  } else {
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $curr_totals[$i] += $fn_CC->[$sort_order[$i]] 
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                if (defined $fn_CC->[$sort_order[$i]]);
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print("\n");
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return $threshold_files;
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Annotate selected files
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------------------------------------------------------------------------
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Issue a warning that the source file is more recent than the input file. 
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub warning_on_src_more_recent_than_inputfile ($)
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $src_file = $_[0];
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $warning = <<END
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@ Source file '$src_file' is more recent than input file '$input_file'.
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@ Annotations may not be correct.
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownEND
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown;
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print($warning);
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# If there is information about lines not in the file, issue a warning
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# explaining possible causes.
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub warning_on_nonexistent_lines ($$$)
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($src_more_recent_than_inputfile, $src_file, $excess_line_nums) = @_;
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $cause_and_solution;
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($src_more_recent_than_inputfile) {
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $cause_and_solution = <<END
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@ cause:    '$src_file' has changed since information was gathered.
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@           If so, a warning will have already been issued about this.
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@ solution: Recompile program and rerun under "valgrind --cachesim=yes" to 
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@           gather new information.
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownEND
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # We suppress warnings about .h files
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    } elsif ($src_file =~ /\.h$/) {
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $cause_and_solution = <<END
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@ cause:    bug in the Valgrind's debug info reader that screws up with .h
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@           files sometimes
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@ solution: none, sorry
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownEND
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    } else {
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $cause_and_solution = <<END
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@ cause:    not sure, sorry
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownEND
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $warning = <<END
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@ Information recorded about lines past the end of '$src_file'.
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@ Probable cause and solution:
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown$cause_and_solution@@
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownEND
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown;
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    print($warning);
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub annotate_ann_files($)
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($threshold_files) = @_; 
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my %all_ann_files;
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my @unfound_auto_annotate_files;
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $printed_totals_CC = [];
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # If auto-annotating, add interesting files (but not "???")
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($auto_annotate) {
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        delete $threshold_files->{"???"};
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        %all_ann_files = (%user_ann_files, %$threshold_files) 
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    } else {
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        %all_ann_files = %user_ann_files;
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Track if we did any annotations.
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $did_annotations = 0;
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    LOOP:
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $src_file (keys %all_ann_files) {
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $opened_file = "";
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $full_file_name = "";
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach my $include_dir (@include_dirs) {
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $try_name = $include_dir . $src_file;
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (open(INPUTFILE, "< $try_name")) {
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $opened_file    = $try_name;
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $full_file_name = ($include_dir eq "" 
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  ? $src_file 
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  : "$include_dir + $src_file"); 
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                last;
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (not $opened_file) {
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Failed to open the file.  If chosen on the command line, die.
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # If arose from auto-annotation, print a little message.
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (defined $user_ann_files{$src_file}) {
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                die("File $src_file not opened in any of: @include_dirs\n");
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                push(@unfound_auto_annotate_files, $src_file);
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } else {
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # File header (distinguish between user- and auto-selected files).
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            print("$fancy");
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $ann_type = 
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (defined $user_ann_files{$src_file} ? "User" : "Auto");
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            print("-- $ann_type-annotated source: $full_file_name\n");
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            print("$fancy");
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Get file's CCs
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $src_file_CCs = $all_ind_CCs{$src_file};
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!defined $src_file_CCs) {
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                print("  No information has been collected for $src_file\n\n");
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                next LOOP;
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $did_annotations = 1;
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Numeric, not lexicographic sort!
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my @line_nums = sort {$a <=> $b} keys %$src_file_CCs;  
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # If $src_file more recent than cachegrind.out, issue warning
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $src_more_recent_than_inputfile = 0;
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((stat $opened_file)[9] > (stat $input_file)[9]) {
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $src_more_recent_than_inputfile = 1;
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                warning_on_src_more_recent_than_inputfile($src_file);
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Work out the size of each column for printing
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $CC_col_widths = compute_CC_col_widths(values %$src_file_CCs);
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Events header
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            print_events($CC_col_widths);
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            print("\n\n");
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Shift out 0 if it's in the line numbers (from unknown entries,
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # likely due to bugs in Valgrind's stabs debug info reader)
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            shift(@line_nums) if (0 == $line_nums[0]);
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Finds interesting line ranges -- all lines with a CC, and all
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # lines within $context lines of a line with a CC.
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $n = @line_nums;
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my @pairs;
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            for (my $i = 0; $i < $n; $i++) {
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                push(@pairs, $line_nums[$i] - $context);   # lower marker
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                while ($i < $n-1 && 
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       $line_nums[$i] + 2*$context >= $line_nums[$i+1]) {
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    $i++;
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                }
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                push(@pairs, $line_nums[$i] + $context);   # upper marker
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Annotate chosen lines, tracking total counts of lines printed
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $pairs[0] = 1 if ($pairs[0] < 1);
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            while (@pairs) {
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                my $low  = shift @pairs;
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                my $high = shift @pairs;
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                while ($. < $low-1) {
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    my $tmp = <INPUTFILE>;
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    last unless (defined $tmp);     # hack to detect EOF
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                }
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                my $src_line;
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                # Print line number, unless start of file
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                print("-- line $low " . '-' x 40 . "\n") if ($low != 1);
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                while (($. < $high) && ($src_line = <INPUTFILE>)) {
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    if (defined $line_nums[0] && $. == $line_nums[0]) {
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        print_CC($src_file_CCs->{$.}, $CC_col_widths);
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        add_array_a_to_b($src_file_CCs->{$.}, 
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         $printed_totals_CC);
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        shift(@line_nums);
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    } else {
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        print_CC( [], $CC_col_widths);
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    }
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    print(" $src_line");
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    my $tmp  = $called_from_line->{$src_file,$.};
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    my $func = $func_of_line{$src_file,$.};
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    if (defined $tmp) {
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		      foreach my $called (keys %$tmp) {
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			if (defined $call_CCs{$func,$called,$.}) {
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  print_CC($call_CCs{$func,$called,$.}, $CC_col_widths);
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  print " => $called (";
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  print $call_counter{$func,$called,$.} . "x)\n";
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			}
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		      }
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    }
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                }
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                # Print line number, unless EOF
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                if ($src_line) {
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    print("-- line $high " . '-' x 40 . "\n");
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                } else {
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    last;
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                }
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # If there was info on lines past the end of the file...
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (@line_nums) {
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                foreach my $line_num (@line_nums) {
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    print_CC($src_file_CCs->{$line_num}, $CC_col_widths);
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    print(" <bogus line $line_num>\n");
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                }
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                print("\n");
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                warning_on_nonexistent_lines($src_more_recent_than_inputfile,
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             $src_file, \@line_nums);
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            print("\n");
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Print summary of counts attributed to file but not to any
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # particular line (due to incomplete debug info).
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ($src_file_CCs->{0}) {
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                print_CC($src_file_CCs->{0}, $CC_col_widths);
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                print(" <counts for unidentified lines in $src_file>\n\n");
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            close(INPUTFILE);
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Print list of unfound auto-annotate selected files.
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (@unfound_auto_annotate_files) {
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print("$fancy");
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print("The following files chosen for auto-annotation could not be found:\n");
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print($fancy);
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach my $f (@unfound_auto_annotate_files) {
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            print("  $f\n");
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print("\n");
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # If we did any annotating, print what proportion of events were covered by
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # annotated lines above.
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($did_annotations) {
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $percent_printed_CC;
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach (my $i = 0; $i < @$summary_CC; $i++) {
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $percent_printed_CC->[$i] = 
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                sprintf("%.0f", 
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        $printed_totals_CC->[$i] / $summary_CC->[$i] * 100);
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $pp_CC_col_widths = compute_CC_col_widths($percent_printed_CC);
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print($fancy);
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print_events($pp_CC_col_widths);
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print("\n");
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print($fancy);
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print_CC($percent_printed_CC, $pp_CC_col_widths);
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print(" percentage of events annotated\n\n");
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# "main()"
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprocess_cmd_line();
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownread_input_file();
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprint_options();
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $threshold_files = print_summary_and_fn_totals();
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownannotate_ann_files($threshold_files);
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--------------------------------------------------------------------##
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--- end                                           vg_annotate.in ---##
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--------------------------------------------------------------------##
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1247