1a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#! /usr/bin/env perl
2a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
3a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Copyright (c) 1998-2007, Google Inc.
4a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# All rights reserved.
5a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# 
6a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Redistribution and use in source and binary forms, with or without
7a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# modification, are permitted provided that the following conditions are
8a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# met:
9a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# 
10a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#     * Redistributions of source code must retain the above copyright
11a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# notice, this list of conditions and the following disclaimer.
12a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#     * Redistributions in binary form must reproduce the above
13a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# copyright notice, this list of conditions and the following disclaimer
14a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# in the documentation and/or other materials provided with the
15a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# distribution.
16a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#     * Neither the name of Google Inc. nor the names of its
17a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# contributors may be used to endorse or promote products derived from
18a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# this software without specific prior written permission.
19a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# 
20a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
32a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# ---
33a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Program for printing the profile generated by common/profiler.cc,
34a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# or by the heap profiler (common/debugallocation.cc)
35a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
36a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# The profile contains a sequence of entries of the form:
37a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#       <count> <stack trace>
38a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# This program parses the profile, and generates user-readable
39a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# output.
40a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
41a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Examples:
42a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
43a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# % tools/pprof "program" "profile"
44a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   Enters "interactive" mode
45a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
46a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# % tools/pprof --text "program" "profile"
47a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   Generates one line per procedure
48a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
49a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# % tools/pprof --gv "program" "profile"
50a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   Generates annotated call-graph and displays via "gv"
51a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
52a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# % tools/pprof --gv --focus=Mutex "program" "profile"
53a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   Restrict to code paths that involve an entry that matches "Mutex"
54a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
55a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# % tools/pprof --gv --focus=Mutex --ignore=string "program" "profile"
56a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   Restrict to code paths that involve an entry that matches "Mutex"
57a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   and does not match "string"
58a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
59a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# % tools/pprof --list=IBF_CheckDocid "program" "profile"
60a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   Generates disassembly listing of all routines with at least one
61a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   sample that match the --list=<regexp> pattern.  The listing is
62a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   annotated with the flat and cumulative sample counts at each line.
63a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
64a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# % tools/pprof --disasm=IBF_CheckDocid "program" "profile"
65a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   Generates disassembly listing of all routines with at least one
66a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   sample that match the --disasm=<regexp> pattern.  The listing is
67a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#   annotated with the flat and cumulative sample counts at each PC value.
68a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#
69a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# TODO: Use color to indicate files?
70a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
71a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansuse strict;
72a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansuse warnings;
73a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansuse Getopt::Long;
74a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
7525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansmy $PPROF_VERSION = "2.0";
76a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
77a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# These are the object tools we use which can come from a
78a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# user-specified location using --tools, from the PPROF_TOOLS
79a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# environment variable, or from the environment.
80a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy %obj_tool_map = (
81a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  "objdump" => "objdump",
82a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  "nm" => "nm",
83a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  "addr2line" => "addr2line",
84a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  "c++filt" => "c++filt",
85a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  ## ConfigureObjTools may add architecture-specific entries:
86a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  #"nm_pdb" => "nm-pdb",       # for reading windows (PDB-format) executables
87a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  #"addr2line_pdb" => "addr2line-pdb",                                # ditto
88a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  #"otool" => "otool",         # equivalent of objdump on OS X
89a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans);
9025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# NOTE: these are lists, so you can put in commandline flags if you want.
9125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansmy @DOT = ("dot");          # leave non-absolute, since it may be in /usr/local
9225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansmy @GV = ("gv");
9325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansmy @EVINCE = ("evince");    # could also be xpdf or perhaps acroread
9425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansmy @KCACHEGRIND = ("kcachegrind");
9525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansmy @PS2PDF = ("ps2pdf");
96a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# These are used for dynamic profiles
9725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansmy @URL_FETCHER = ("curl", "-s");
98a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
99a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# These are the web pages that servers need to support for dynamic profiles
100a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $HEAP_PAGE = "/pprof/heap";
101a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $PROFILE_PAGE = "/pprof/profile";   # must support cgi-param "?seconds=#"
102a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param
103a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                                                # ?seconds=#&event=x&period=n
104a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $GROWTH_PAGE = "/pprof/growth";
105a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $CONTENTION_PAGE = "/pprof/contention";
106a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $WALL_PAGE = "/pprof/wall(?:\\?.*)?";  # accepts options like namefilter
107a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?";
10825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansmy $CENSUSPROFILE_PAGE = "/pprof/censusprofile(?:\\?.*)?"; # must support cgi-param
10925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                                                       # "?seconds=#",
11025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                                                       # "?tags_regexp=#" and
11125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                                                       # "?type=#".
112a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $SYMBOL_PAGE = "/pprof/symbol";     # must support symbol lookup via POST
113a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $PROGRAM_NAME_PAGE = "/pprof/cmdline";
114a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
115d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans# These are the web pages that can be named on the command line.
116d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans# All the alternatives must begin with /.
117d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evansmy $PROFILES = "($HEAP_PAGE|$PROFILE_PAGE|$PMUPROFILE_PAGE|" .
118d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans               "$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|" .
1199a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans               "$FILTEREDPROFILE_PAGE|$CENSUSPROFILE_PAGE)";
120d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans
121a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# default binary name
122a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $UNKNOWN_BINARY = "(unknown)";
123a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
124a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# There is a pervasive dependency on the length (in hex characters,
125a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# i.e., nibbles) of an address, distinguishing between 32-bit and
126a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# 64-bit profiles.  To err on the safe size, default to 64-bit here:
127a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $address_length = 16;
128a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
12925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansmy $dev_null = "/dev/null";
13025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansif (! -e $dev_null && $^O =~ /MSWin/) {    # $^O is the OS perl was built for
13125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  $dev_null = "nul";
13225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
13325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
134a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# A list of paths to search for shared object files
135a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy @prefix_list = ();
136a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
137a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Special routine name that should not have any symbols.
138a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Used as separator to parse "addr2line -i" output.
139a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $sep_symbol = '_fini';
140a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansmy $sep_address = undef;
141a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
142a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans##### Argument parsing #####
143a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
144a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub usage_string {
145a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  return <<EOF;
146a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansUsage:
147a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof [options] <program> <profiles>
148a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   <profiles> is a space separated list of profile names.
149a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof [options] <symbolized-profiles>
150a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   <symbolized-profiles> is a list of profile files where each file contains
151a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   the necessary symbol mappings  as well as profile data (likely generated
152a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   with --raw).
153a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof [options] <profile>
154a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   <profile> is a remote form.  Symbols are obtained from host:port$SYMBOL_PAGE
155a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
156a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   Each name can be:
157a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   /path/to/profile        - a path to a profile file
158a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   host:port[/<service>]   - a location of a service to get profile from
159a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
160a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
161a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                         $GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
1629a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans                         $CENSUSPROFILE_PAGE, or /pprof/filteredprofile.
16325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans   For instance:
16425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans     pprof http://myserver.com:80$HEAP_PAGE
165a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
166a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --symbols <program>
167a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   Maps addresses to symbol names.  In this mode, stdin should be a
168a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   list of library mappings, in the same format as is found in the heap-
169a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   and cpu-profile files (this loosely matches that of /proc/self/maps
170a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   on linux), followed by a list of hex addresses to map, one per line.
171a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
172a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   For more help with querying remote servers, including how to add the
173a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   necessary server-side support code, see this filename (or one like it):
174a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
17525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans   /usr/doc/gperftools-$PPROF_VERSION/pprof_remote_servers.html
176a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
177a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansOptions:
178a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --cum               Sort by cumulative data
179a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --base=<base>       Subtract <base> from <profile> before display
180a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --interactive       Run in interactive mode (interactive "help" gives help) [default]
181a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --seconds=<n>       Length of time for dynamic profiles [default=30 secs]
182a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --add_lib=<file>    Read additional symbols and line info from the given library
183a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --lib_prefix=<dir>  Comma separated list of library path prefixes
184a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
185a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansReporting Granularity:
186a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --addresses         Report at address level
187a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --lines             Report at source line level
188a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --functions         Report at function level [default]
189a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --files             Report at source file level
190a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
191a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansOutput type:
192a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --text              Generate text report
193a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --callgrind         Generate callgrind format to stdout
194a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --gv                Generate Postscript and display
1959a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans   --evince            Generate PDF and display
196d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans   --web               Generate SVG and display
197a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --list=<regexp>     Generate source listing of matching routines
198a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --disasm=<regexp>   Generate disassembly of matching routines
199a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --symbols           Print demangled symbol names found at given addresses
200a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --dot               Generate DOT file to stdout
201a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --ps                Generate Postcript to stdout
202a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --pdf               Generate PDF to stdout
203d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans   --svg               Generate SVG to stdout
204a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --gif               Generate GIF to stdout
205a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --raw               Generate symbolized pprof data (useful with remote fetch)
206a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
207a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansHeap-Profile Options:
208a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --inuse_space       Display in-use (mega)bytes [default]
209a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --inuse_objects     Display in-use objects
210a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --alloc_space       Display allocated (mega)bytes
211a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --alloc_objects     Display allocated objects
212a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --show_bytes        Display space in bytes
213a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --drop_negative     Ignore negative differences
214a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
215a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansContention-profile options:
216a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --total_delay       Display total delay at each region [default]
217a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --contentions       Display number of delays at each region
218a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --mean_delay        Display mean delay at each region
219a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
220a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansCall-graph Options:
221a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --nodecount=<n>     Show at most so many nodes [default=80]
222a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --nodefraction=<f>  Hide nodes below <f>*total [default=.005]
223a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --edgefraction=<f>  Hide edges below <f>*total [default=.001]
2249a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans   --maxdegree=<n>     Max incoming/outgoing edges per node [default=8]
225a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --focus=<regexp>    Focus on nodes matching <regexp>
226a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --ignore=<regexp>   Ignore nodes matching <regexp>
227a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --scale=<n>         Set GV scaling [default=0]
228a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --heapcheck         Make nodes with non-0 object counts
229a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       (i.e. direct leak generators) more visible
230a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
231a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansMiscellaneous:
232d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans   --tools=<prefix or binary:fullpath>[,...]   \$PATH for object tool pathnames
233a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --test              Run unit tests
234a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --help              This message
235a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   --version           Version information
236a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
237a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansEnvironment Variables:
238a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   PPROF_TMPDIR        Profiles directory. Defaults to \$HOME/pprof
239a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans   PPROF_TOOLS         Prefix for object tools pathnames
240a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
241a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansExamples:
242a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
243a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof /bin/ls ls.prof
244a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       Enters "interactive" mode
245a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --text /bin/ls ls.prof
246a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       Outputs one line per procedure
247d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evanspprof --web /bin/ls ls.prof
248d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans                       Displays annotated call-graph in web browser
249a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --gv /bin/ls ls.prof
250a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       Displays annotated call-graph via 'gv'
251a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --gv --focus=Mutex /bin/ls ls.prof
252a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       Restricts to code paths including a .*Mutex.* entry
253a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof
254a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       Code paths including Mutex but not string
255a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --list=getdir /bin/ls ls.prof
256a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       (Per-line) annotated source listing for getdir()
257a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --disasm=getdir /bin/ls ls.prof
258a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       (Per-PC) annotated disassembly for getdir()
259d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans
260d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evanspprof http://localhost:1234/
261d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans                       Enters "interactive" mode
262a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --text localhost:1234
263a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       Outputs one line per procedure for localhost:1234
264a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --raw localhost:1234 > ./local.raw
265a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanspprof --text ./local.raw
266a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       Fetches a remote profile for later analysis and then
267a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       analyzes it in text mode.
268a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansEOF
269a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
270a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
271a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub version_string {
272a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  return <<EOF
27325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evanspprof (part of gperftools $PPROF_VERSION)
274a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
275a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansCopyright 1998-2007 Google Inc.
276a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
277a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansThis is BSD licensed software; see the source for copying conditions
278a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansand license information.
279a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansThere is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
280a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansPARTICULAR PURPOSE.
281a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansEOF
282a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
283a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
284a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub usage {
285a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $msg = shift;
286a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print STDERR "$msg\n\n";
287a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print STDERR usage_string();
288a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print STDERR "\nFATAL ERROR: $msg\n";    # just as a reminder
289a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  exit(1);
290a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
291a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
292a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub Init() {
293a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Setup tmp-file name and handler to clean it up.
294a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # We do this in the very beginning so that we can use
295a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # error() and cleanup() function anytime here after.
296a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::tmpfile_sym = "/tmp/pprof$$.sym";
297a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::tmpfile_ps = "/tmp/pprof$$";
298a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::next_tmpfile = 0;
299a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $SIG{'INT'} = \&sighandler;
300a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
301a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Cache from filename/linenumber to source code
302a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::source_cache = ();
303a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
304a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_help = 0;
305a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_version = 0;
306a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
307a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_cum = 0;
308a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_base = '';
309a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_addresses = 0;
310a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_lines = 0;
311a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_functions = 0;
312a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_files = 0;
313a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_lib_prefix = "";
314a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
315a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_text = 0;
316a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_callgrind = 0;
317a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_list = "";
318a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_disasm = "";
319a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_symbols = 0;
320a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_gv = 0;
3219a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  $main::opt_evince = 0;
322d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  $main::opt_web = 0;
323a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_dot = 0;
324a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_ps = 0;
325a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_pdf = 0;
326a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_gif = 0;
327d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  $main::opt_svg = 0;
328a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_raw = 0;
329a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
330a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_nodecount = 80;
331a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_nodefraction = 0.005;
332a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_edgefraction = 0.001;
3339a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  $main::opt_maxdegree = 8;
334a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_focus = '';
335a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_ignore = '';
336a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_scale = 0;
337a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_heapcheck = 0;
338a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_seconds = 30;
339a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_lib = "";
340a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
341a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_inuse_space   = 0;
342a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_inuse_objects = 0;
343a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_alloc_space   = 0;
344a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_alloc_objects = 0;
345a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_show_bytes    = 0;
346a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_drop_negative = 0;
347a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_interactive   = 0;
348a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
349a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_total_delay = 0;
350a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_contentions = 0;
351a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_mean_delay = 0;
352a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
353a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_tools   = "";
354a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_debug   = 0;
355a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_test    = 0;
356a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
357a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # These are undocumented flags used only by unittests.
358a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_test_stride = 0;
359a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
360a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Are we using $SYMBOL_PAGE?
361a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::use_symbol_page = 0;
362a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
363d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  # Files returned by TempName.
364d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  %main::tempnames = ();
365d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans
366a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Type of profile we are dealing with
367a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Supported types:
368a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  #     cpu
369a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  #     heap
370a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  #     growth
371a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  #     contention
372a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::profile_type = '';     # Empty type means "unknown"
373a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
374a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  GetOptions("help!"          => \$main::opt_help,
375a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "version!"       => \$main::opt_version,
376a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "cum!"           => \$main::opt_cum,
377a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "base=s"         => \$main::opt_base,
378a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "seconds=i"      => \$main::opt_seconds,
379a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "add_lib=s"      => \$main::opt_lib,
380a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "lib_prefix=s"   => \$main::opt_lib_prefix,
381a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "functions!"     => \$main::opt_functions,
382a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "lines!"         => \$main::opt_lines,
383a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "addresses!"     => \$main::opt_addresses,
384a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "files!"         => \$main::opt_files,
385a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "text!"          => \$main::opt_text,
386a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "callgrind!"     => \$main::opt_callgrind,
387a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "list=s"         => \$main::opt_list,
388a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "disasm=s"       => \$main::opt_disasm,
389a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "symbols!"       => \$main::opt_symbols,
390a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "gv!"            => \$main::opt_gv,
3919a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans             "evince!"        => \$main::opt_evince,
392d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans             "web!"           => \$main::opt_web,
393a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "dot!"           => \$main::opt_dot,
394a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "ps!"            => \$main::opt_ps,
395a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "pdf!"           => \$main::opt_pdf,
396d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans             "svg!"           => \$main::opt_svg,
397a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "gif!"           => \$main::opt_gif,
398a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "raw!"           => \$main::opt_raw,
399a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "interactive!"   => \$main::opt_interactive,
400a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "nodecount=i"    => \$main::opt_nodecount,
401a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "nodefraction=f" => \$main::opt_nodefraction,
402a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "edgefraction=f" => \$main::opt_edgefraction,
4039a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans             "maxdegree=i"    => \$main::opt_maxdegree,
404a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "focus=s"        => \$main::opt_focus,
405a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "ignore=s"       => \$main::opt_ignore,
406a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "scale=i"        => \$main::opt_scale,
407a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "heapcheck"      => \$main::opt_heapcheck,
408a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "inuse_space!"   => \$main::opt_inuse_space,
409a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "inuse_objects!" => \$main::opt_inuse_objects,
410a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "alloc_space!"   => \$main::opt_alloc_space,
411a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "alloc_objects!" => \$main::opt_alloc_objects,
412a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "show_bytes!"    => \$main::opt_show_bytes,
413a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "drop_negative!" => \$main::opt_drop_negative,
414a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "total_delay!"   => \$main::opt_total_delay,
415a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "contentions!"   => \$main::opt_contentions,
416a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "mean_delay!"    => \$main::opt_mean_delay,
417a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "tools=s"        => \$main::opt_tools,
418a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "test!"          => \$main::opt_test,
419a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "debug!"         => \$main::opt_debug,
420a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             # Undocumented flags used only by unittests:
421a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             "test_stride=i"  => \$main::opt_test_stride,
422a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      ) || usage("Invalid option(s)");
423a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
424a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Deal with the standard --help and --version
425a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_help) {
426a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print usage_string();
427a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    exit(0);
428a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
429a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
430a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_version) {
431a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print version_string();
432a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    exit(0);
433a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
434a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
435a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Disassembly/listing/symbols mode requires address-level info
436a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) {
437a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::opt_functions = 0;
438a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::opt_lines = 0;
439a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::opt_addresses = 1;
440a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::opt_files = 0;
441a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
442a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
443a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Check heap-profiling flags
444a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_inuse_space +
445a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_inuse_objects +
446a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_alloc_space +
447a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_alloc_objects > 1) {
448a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    usage("Specify at most on of --inuse/--alloc options");
449a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
450a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
451a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Check output granularities
452a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $grains =
453a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_functions +
454a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_lines +
455a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_addresses +
456a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_files +
457a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      0;
458a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($grains > 1) {
459a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    usage("Only specify one output granularity option");
460a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
461a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($grains == 0) {
462a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::opt_functions = 1;
463a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
464a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
465a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Check output modes
466a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $modes =
467a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_text +
468a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_callgrind +
469a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      ($main::opt_list eq '' ? 0 : 1) +
470a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      ($main::opt_disasm eq '' ? 0 : 1) +
471a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      ($main::opt_symbols == 0 ? 0 : 1) +
472a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_gv +
4739a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      $main::opt_evince +
474d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      $main::opt_web +
475a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_dot +
476a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_ps +
477a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_pdf +
478d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      $main::opt_svg +
479a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_gif +
480a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_raw +
481a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_interactive +
482a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      0;
483a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($modes > 1) {
484a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    usage("Only specify one output mode");
485a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
486a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($modes == 0) {
487a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (-t STDOUT) {  # If STDOUT is a tty, activate interactive mode
488a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_interactive = 1;
489a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } else {
490a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_text = 1;
491a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
492a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
493a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
494a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_test) {
495a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    RunUnitTests();
496a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Should not return
497a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    exit(1);
498a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
499a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
500a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Binary name and profile arguments list
501a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::prog = "";
502a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  @main::pfile_args = ();
503a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
504a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Remote profiling without a binary (using $SYMBOL_PAGE instead)
50525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if (@ARGV > 0) {
50625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    if (IsProfileURL($ARGV[0])) {
50725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $main::use_symbol_page = 1;
50825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    } elsif (IsSymbolizedProfileFile($ARGV[0])) {
50925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $main::use_symbolized_profile = 1;
51025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $main::prog = $UNKNOWN_BINARY;  # will be set later from the profile file
51125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    }
512a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
513a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
514a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::use_symbol_page || $main::use_symbolized_profile) {
515a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # We don't need a binary!
516a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my %disabled = ('--lines' => $main::opt_lines,
517a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                    '--disasm' => $main::opt_disasm);
518a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    for my $option (keys %disabled) {
519a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      usage("$option cannot be used without a binary") if $disabled{$option};
520a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
521a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Set $main::prog later...
522a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    scalar(@ARGV) || usage("Did not specify profile file");
523a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } elsif ($main::opt_symbols) {
524a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # --symbols needs a binary-name (to run nm on, etc) but not profiles
525a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::prog = shift(@ARGV) || usage("Did not specify program");
526a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
527a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::prog = shift(@ARGV) || usage("Did not specify program");
528a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    scalar(@ARGV) || usage("Did not specify profile file");
529a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
530a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
531a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Parse profile file/location arguments
532a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $farg (@ARGV) {
533a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) {
534a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $machine = $1;
535a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $num_machines = $2;
536a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $path = $3;
537a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      for (my $i = 0; $i < $num_machines; $i++) {
538a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        unshift(@main::pfile_args, "$i.$machine$path");
539a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
540a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } else {
541a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      unshift(@main::pfile_args, $farg);
542a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
543a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
544a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
545a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::use_symbol_page) {
546a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    unless (IsProfileURL($main::pfile_args[0])) {
547a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      error("The first profile should be a remote form to use $SYMBOL_PAGE\n");
548a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
549a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    CheckSymbolPage();
550a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::prog = FetchProgramName();
551a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } elsif (!$main::use_symbolized_profile) {  # may not need objtools!
552a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    ConfigureObjTools($main::prog)
553a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
554a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
55525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  # Break the opt_lib_prefix into the prefix_list array
556a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  @prefix_list = split (',', $main::opt_lib_prefix);
557a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
558a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Remove trailing / from the prefixes, in the list to prevent
559a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # searching things like /my/path//lib/mylib.so
560a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach (@prefix_list) {
561a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    s|/+$||;
562a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
563a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
564a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
565a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub Main() {
566a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  Init();
567a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::collected_profile = undef;
568a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  @main::profile_files = ();
569a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::op_time = time();
570a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
571a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Printing symbols is special and requires a lot less info that most.
572a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_symbols) {
573a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    PrintSymbols(*STDIN);   # Get /proc/maps and symbols output from stdin
574a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return;
575a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
576a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
577a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Fetch all profile data
578a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  FetchDynamicProfiles();
579a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
580a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # this will hold symbols that we read from the profile files
581a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $symbol_map = {};
582a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
583a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Read one profile, pick the last item on the list
584a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $data = ReadProfile($main::prog, pop(@main::profile_files));
585a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $profile = $data->{profile};
586a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $pcs = $data->{pcs};
587a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $libs = $data->{libs};   # Info about main program and shared libraries
588a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $symbol_map = MergeSymbols($symbol_map, $data->{symbols});
589a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
590a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Add additional profiles, if available.
591a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (scalar(@main::profile_files) > 0) {
592a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    foreach my $pname (@main::profile_files) {
593a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $data2 = ReadProfile($main::prog, $pname);
594a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $profile = AddProfile($profile, $data2->{profile});
595a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $pcs = AddPcs($pcs, $data2->{pcs});
596a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $symbol_map = MergeSymbols($symbol_map, $data2->{symbols});
597a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
598a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
599a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
600a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Subtract base from profile, if specified
601a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_base ne '') {
602a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $base = ReadProfile($main::prog, $main::opt_base);
603a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $profile = SubtractProfile($profile, $base->{profile});
604a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $pcs = AddPcs($pcs, $base->{pcs});
605a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $symbol_map = MergeSymbols($symbol_map, $base->{symbols});
606a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
607a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
608a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Get total data in profile
609a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $total = TotalProfile($profile);
610a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
611a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Collect symbols
612a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $symbols;
613a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::use_symbolized_profile) {
614a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $symbols = FetchSymbols($pcs, $symbol_map);
615a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } elsif ($main::use_symbol_page) {
616a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $symbols = FetchSymbols($pcs);
617a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
618d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    # TODO(csilvers): $libs uses the /proc/self/maps data from profile1,
619d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    # which may differ from the data from subsequent profiles, especially
620d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    # if they were run on different machines.  Use appropriate libs for
621d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    # each pc somehow.
622a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $symbols = ExtractSymbols($libs, $pcs);
623a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
624a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
625a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Remove uniniteresting stack items
626a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $profile = RemoveUninterestingFrames($symbols, $profile);
627a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
628a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Focus?
629a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_focus ne '') {
630a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $profile = FocusProfile($symbols, $profile, $main::opt_focus);
631a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
632a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
633a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Ignore?
634a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_ignore ne '') {
635a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore);
636a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
637a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
638a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $calls = ExtractCalls($symbols, $profile);
639a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
640a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Reduce profiles to required output granularity, and also clean
641a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # each stack trace so a given entry exists at most once.
642a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $reduced = ReduceProfile($symbols, $profile);
643a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
644a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Get derived profiles
645a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $flat = FlatProfile($reduced);
646a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $cumulative = CumulativeProfile($reduced);
647a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
648a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Print
649a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (!$main::opt_interactive) {
650a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($main::opt_disasm) {
65125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm);
652a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } elsif ($main::opt_list) {
65325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
654a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } elsif ($main::opt_text) {
655a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Make sure the output is empty when have nothing to report
656a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # (only matters when --heapcheck is given but we must be
657a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # compatible with old branches that did not pass --heapcheck always):
658a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if ($total != 0) {
659a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        printf("Total: %s %s\n", Unparse($total), Units());
660a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
66125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      PrintText($symbols, $flat, $cumulative, -1);
662a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } elsif ($main::opt_raw) {
663a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      PrintSymbolizedProfile($symbols, $profile, $main::prog);
664a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } elsif ($main::opt_callgrind) {
665a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      PrintCallgrind($calls);
666a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } else {
667a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
668a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        if ($main::opt_gv) {
669d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          RunGV(TempName($main::next_tmpfile, "ps"), "");
6709a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans        } elsif ($main::opt_evince) {
67125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          RunEvince(TempName($main::next_tmpfile, "pdf"), "");
672d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans        } elsif ($main::opt_web) {
673d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          my $tmp = TempName($main::next_tmpfile, "svg");
674d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          RunWeb($tmp);
675d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          # The command we run might hand the file name off
676d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          # to an already running browser instance and then exit.
677d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          # Normally, we'd remove $tmp on exit (right now),
678d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          # but fork a child to remove $tmp a little later, so that the
679d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          # browser has time to load it first.
680d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          delete $main::tempnames{$tmp};
681d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          if (fork() == 0) {
682d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans            sleep 5;
683d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans            unlink($tmp);
684d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans            exit(0);
685d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans          }
686a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        }
687a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      } else {
688d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans        cleanup();
689a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        exit(1);
690a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
691a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
692a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
693a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    InteractiveMode($profile, $symbols, $libs, $total);
694a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
695a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
696a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  cleanup();
697a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  exit(0);
698a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
699a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
700a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans##### Entry Point #####
701a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
702a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansMain();
703a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
704a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Temporary code to detect if we're running on a Goobuntu system.
705a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# These systems don't have the right stuff installed for the special
706a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Readline libraries to work, so as a temporary workaround, we default
707a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# to using the normal stdio code, rather than the fancier readline-based
708a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# code
709a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub ReadlineMightFail {
710a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (-e '/lib/libtermcap.so.2') {
711a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 0;  # libtermcap exists, so readline should be okay
712a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
713a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 1;
714a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
715a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
716a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
717a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub RunGV {
718a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $fname = shift;
719a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $bg = shift;       # "" or " &" if we should run in background
72025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if (!system(ShellEscape(@GV, "--version") . " >$dev_null 2>&1")) {
721a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Options using double dash are supported by this gv version.
722a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Also, turn on noantialias to better handle bug in gv for
723a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # postscript files with large dimensions.
724a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # TODO: Maybe we should not pass the --noantialias flag
725a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # if the gv version is known to work properly without the flag.
72625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    system(ShellEscape(@GV, "--scale=$main::opt_scale", "--noantialias", $fname)
72725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans           . $bg);
728a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
729a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Old gv version - only supports options that use single dash.
73025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    print STDERR ShellEscape(@GV, "-scale", $main::opt_scale) . "\n";
73125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    system(ShellEscape(@GV, "-scale", "$main::opt_scale", $fname) . $bg);
732a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
733a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
734a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
7359a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evanssub RunEvince {
7369a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  my $fname = shift;
7379a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  my $bg = shift;       # "" or " &" if we should run in background
73825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  system(ShellEscape(@EVINCE, $fname) . $bg);
7399a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans}
7409a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans
741d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evanssub RunWeb {
742d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  my $fname = shift;
743d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  print STDERR "Loading web page file:///$fname\n";
744d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans
745d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  if (`uname` =~ /Darwin/) {
746d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    # OS X: open will use standard preference for SVG files.
747d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    system("/usr/bin/open", $fname);
748d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    return;
749d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  }
750d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans
751d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  # Some kind of Unix; try generic symlinks, then specific browsers.
752d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  # (Stop once we find one.)
753d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  # Works best if the browser is already running.
754d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  my @alt = (
755d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    "/etc/alternatives/gnome-www-browser",
756d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    "/etc/alternatives/x-www-browser",
757d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    "google-chrome",
758d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    "firefox",
759d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  );
760d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  foreach my $b (@alt) {
761d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    if (system($b, $fname) == 0) {
762d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      return;
763d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    }
764d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  }
765d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans
766d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  print STDERR "Could not load web browser.\n";
767d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans}
768d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans
769a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub RunKcachegrind {
770a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $fname = shift;
771a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $bg = shift;       # "" or " &" if we should run in background
77225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  print STDERR "Starting '@KCACHEGRIND " . $fname . $bg . "'\n";
77325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  system(ShellEscape(@KCACHEGRIND, $fname) . $bg);
774a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
775a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
776a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
777a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans##### Interactive helper routines #####
778a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
779a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub InteractiveMode {
780a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $| = 1;  # Make output unbuffered for interactive mode
781a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my ($orig_profile, $symbols, $libs, $total) = @_;
782a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
783a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print STDERR "Welcome to pprof!  For help, type 'help'.\n";
784a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
785a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Use ReadLine if it's installed and input comes from a console.
786a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ( -t STDIN &&
787a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans       !ReadlineMightFail() &&
788a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans       defined(eval {require Term::ReadLine}) ) {
789a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $term = new Term::ReadLine 'pprof';
790a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    while ( defined ($_ = $term->readline('(pprof) '))) {
791a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $term->addhistory($_) if /\S/;
792a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
793a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        last;    # exit when we get an interactive command to quit
794a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
795a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
796a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {       # don't have readline
797a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    while (1) {
798a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      print STDERR "(pprof) ";
799a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $_ = <STDIN>;
800a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      last if ! defined $_ ;
801a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      s/\r//g;         # turn windows-looking lines into unix-looking lines
802a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
803a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Save some flags that might be reset by InteractiveCommand()
804a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $save_opt_lines = $main::opt_lines;
805a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
806a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
807a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        last;    # exit when we get an interactive command to quit
808a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
809a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
810a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Restore flags
811a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_lines = $save_opt_lines;
812a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
813a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
814a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
815a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
816a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Takes two args: orig profile, and command to run.
817a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Returns 1 if we should keep going, or 0 if we were asked to quit
818a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub InteractiveCommand {
819a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my($orig_profile, $symbols, $libs, $total, $command) = @_;
820a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $_ = $command;                # just to make future m//'s easier
821a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (!defined($_)) {
822a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print STDERR "\n";
823a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 0;
824a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
825d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  if (m/^\s*quit/) {
826a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 0;
827a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
828d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  if (m/^\s*help/) {
829a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    InteractiveHelpMessage();
830a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 1;
831a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
832a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Clear all the mode options -- mode is controlled by "$command"
833a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_text = 0;
834a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_callgrind = 0;
835a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_disasm = 0;
836a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_list = 0;
837a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_gv = 0;
8389a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  $main::opt_evince = 0;
839a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $main::opt_cum = 0;
840a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
841d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  if (m/^\s*(text|top)(\d*)\s*(.*)/) {
842a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::opt_text = 1;
843a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
844a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $line_limit = ($2 ne "") ? int($2) : 10;
845a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
846a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $routine;
847a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $ignore;
848a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    ($routine, $ignore) = ParseInteractiveArgs($3);
849a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
85025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
851a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $reduced = ReduceProfile($symbols, $profile);
852a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
853a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Get derived profiles
854a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $flat = FlatProfile($reduced);
855a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $cumulative = CumulativeProfile($reduced);
856a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
85725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    PrintText($symbols, $flat, $cumulative, $line_limit);
858a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 1;
859a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
860d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  if (m/^\s*callgrind\s*([^ \n]*)/) {
861a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::opt_callgrind = 1;
862a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
863a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Get derived profiles
864a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $calls = ExtractCalls($symbols, $orig_profile);
865a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $filename = $1;
866a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ( $1 eq '' ) {
867d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      $filename = TempName($main::next_tmpfile, "callgrind");
868a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
869a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    PrintCallgrind($calls, $filename);
870a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ( $1 eq '' ) {
871a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      RunKcachegrind($filename, " & ");
872a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::next_tmpfile++;
873a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
874a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
875a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 1;
876a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
87725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if (m/^\s*(web)?list\s*(.+)/) {
87825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $html = (defined($1) && ($1 eq "web"));
879a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::opt_list = 1;
880a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
881a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $routine;
882a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $ignore;
88325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    ($routine, $ignore) = ParseInteractiveArgs($2);
884a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
88525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
886a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $reduced = ReduceProfile($symbols, $profile);
887a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
888a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Get derived profiles
889a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $flat = FlatProfile($reduced);
890a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $cumulative = CumulativeProfile($reduced);
891a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
89225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
893a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 1;
894a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
895d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  if (m/^\s*disasm\s*(.+)/) {
896a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::opt_disasm = 1;
897a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
898a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $routine;
899a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $ignore;
900a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    ($routine, $ignore) = ParseInteractiveArgs($1);
901a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
902a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Process current profile to account for various settings
90325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
904a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $reduced = ReduceProfile($symbols, $profile);
905a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
906a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Get derived profiles
907a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $flat = FlatProfile($reduced);
908a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $cumulative = CumulativeProfile($reduced);
909a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
91025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    PrintDisassembly($libs, $flat, $cumulative, $routine);
911a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 1;
912a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
9139a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  if (m/^\s*(gv|web|evince)\s*(.*)/) {
914d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    $main::opt_gv = 0;
9159a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    $main::opt_evince = 0;
916d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    $main::opt_web = 0;
917d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    if ($1 eq "gv") {
918d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      $main::opt_gv = 1;
9199a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    } elsif ($1 eq "evince") {
9209a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      $main::opt_evince = 1;
921d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    } elsif ($1 eq "web") {
922d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      $main::opt_web = 1;
923d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    }
924a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
925a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $focus;
926a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $ignore;
927d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    ($focus, $ignore) = ParseInteractiveArgs($2);
928a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
929a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Process current profile to account for various settings
93025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $profile = ProcessProfile($total, $orig_profile, $symbols,
93125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                                 $focus, $ignore);
932a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $reduced = ReduceProfile($symbols, $profile);
933a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
934a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Get derived profiles
935a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $flat = FlatProfile($reduced);
936a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $cumulative = CumulativeProfile($reduced);
937a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
938a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
939d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      if ($main::opt_gv) {
940d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans        RunGV(TempName($main::next_tmpfile, "ps"), " &");
9419a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      } elsif ($main::opt_evince) {
9429a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans        RunEvince(TempName($main::next_tmpfile, "pdf"), " &");
943d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      } elsif ($main::opt_web) {
944d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans        RunWeb(TempName($main::next_tmpfile, "svg"));
945d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      }
946a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::next_tmpfile++;
947a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
948a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 1;
949a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
950d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  if (m/^\s*$/) {
951d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    return 1;
952d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  }
953d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  print STDERR "Unknown command: try 'help'.\n";
954a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  return 1;
955a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
956a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
957a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
958a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub ProcessProfile {
95925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $total_count = shift;
960a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $orig_profile = shift;
961a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $symbols = shift;
962a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $focus = shift;
963a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $ignore = shift;
964a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
965a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Process current profile to account for various settings
966a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $profile = $orig_profile;
967a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  printf("Total: %s %s\n", Unparse($total_count), Units());
968a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($focus ne '') {
969a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $profile = FocusProfile($symbols, $profile, $focus);
970a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $focus_count = TotalProfile($profile);
971a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
972a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans           $focus,
973a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans           Unparse($focus_count), Units(),
974a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans           Unparse($total_count), ($focus_count*100.0) / $total_count);
975a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
976a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($ignore ne '') {
977a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $profile = IgnoreProfile($symbols, $profile, $ignore);
978a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $ignore_count = TotalProfile($profile);
979a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
980a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans           $ignore,
981a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans           Unparse($ignore_count), Units(),
982a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans           Unparse($total_count),
983a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans           ($ignore_count*100.0) / $total_count);
984a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
985a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
986a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  return $profile;
987a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
988a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
989a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub InteractiveHelpMessage {
990a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print STDERR <<ENDOFHELP;
991a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansInteractive pprof mode
992a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
993a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansCommands:
994a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  gv
995a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  gv [focus] [-ignore1] [-ignore2]
996a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      Show graphical hierarchical display of current profile.  Without
997a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      any arguments, shows all samples in the profile.  With the optional
998a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      "focus" argument, restricts the samples shown to just those where
999a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      the "focus" regular expression matches a routine name on the stack
1000a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      trace.
1001a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1002d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  web
1003d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  web [focus] [-ignore1] [-ignore2]
1004d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      Like GV, but displays profile in your web browser instead of using
1005d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      Ghostview. Works best if your web browser is already running.
1006d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      To change the browser that gets used:
1007d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      On Linux, set the /etc/alternatives/gnome-www-browser symlink.
1008d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      On OS X, change the Finder association for SVG files.
1009d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans
1010a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  list [routine_regexp] [-ignore1] [-ignore2]
1011a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      Show source listing of routines whose names match "routine_regexp"
1012a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
101325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  weblist [routine_regexp] [-ignore1] [-ignore2]
101425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans     Displays a source listing of routines whose names match "routine_regexp"
101525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans     in a web browser.  You can click on source lines to view the
101625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans     corresponding disassembly.
101725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
1018a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  top [--cum] [-ignore1] [-ignore2]
1019a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  top20 [--cum] [-ignore1] [-ignore2]
1020a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  top37 [--cum] [-ignore1] [-ignore2]
1021a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      Show top lines ordered by flat profile count, or cumulative count
1022a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if --cum is specified.  If a number is present after 'top', the
1023a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      top K routines will be shown (defaults to showing the top 10)
1024a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1025a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  disasm [routine_regexp] [-ignore1] [-ignore2]
1026a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      Show disassembly of routines whose names match "routine_regexp",
1027a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      annotated with sample counts.
1028a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1029a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  callgrind
1030a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  callgrind [filename]
1031a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      Generates callgrind file. If no filename is given, kcachegrind is called.
1032a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1033a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  help - This listing
1034a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  quit or ^D - End pprof
1035a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1036a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansFor commands that accept optional -ignore tags, samples where any routine in
1037a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansthe stack trace matches the regular expression in any of the -ignore
1038a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evansparameters will be ignored.
1039a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1040a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansFurther pprof details are available at this location (or one similar):
1041a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
104225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans /usr/doc/gperftools-$PPROF_VERSION/cpu_profiler.html
104325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans /usr/doc/gperftools-$PPROF_VERSION/heap_profiler.html
1044a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1045a91f2109292f4f4522f75d0636fdba30bda26e76Jason EvansENDOFHELP
1046a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1047a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub ParseInteractiveArgs {
1048a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $args = shift;
1049a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $focus = "";
1050a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $ignore = "";
1051a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my @x = split(/ +/, $args);
1052a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach $a (@x) {
1053a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($a =~ m/^(--|-)lines$/) {
1054a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_lines = 1;
1055a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } elsif ($a =~ m/^(--|-)cum$/) {
1056a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::opt_cum = 1;
1057a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } elsif ($a =~ m/^-(.*)/) {
1058a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $ignore .= (($ignore ne "") ? "|" : "" ) . $1;
1059a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } else {
1060a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $focus .= (($focus ne "") ? "|" : "" ) . $a;
1061a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1062a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1063a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($ignore ne "") {
1064a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print STDERR "Ignoring samples in call stacks that match '$ignore'\n";
1065a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1066a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  return ($focus, $ignore);
1067a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1068a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1069a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans##### Output code #####
1070a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1071d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evanssub TempName {
1072a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $fnum = shift;
1073d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  my $ext = shift;
1074d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  my $file = "$main::tmpfile_ps.$fnum.$ext";
1075d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  $main::tempnames{$file} = 1;
1076d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  return $file;
1077a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1078a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1079a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Print profile data in packed binary format (64-bit) to standard out
1080a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintProfileData {
1081a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $profile = shift;
1082a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1083a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # print header (64-bit style)
1084a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # (zero) (header-size) (version) (sample-period) (zero)
1085a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print pack('L*', 0, 0, 3, 0, 0, 0, 1, 0, 0, 0);
1086a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1087a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $k (keys(%{$profile})) {
1088a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $count = $profile->{$k};
1089a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my @addrs = split(/\n/, $k);
1090a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($#addrs >= 0) {
1091a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $depth = $#addrs + 1;
1092a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # int(foo / 2**32) is the only reliable way to get rid of bottom
1093a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # 32 bits on both 32- and 64-bit systems.
1094a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      print pack('L*', $count & 0xFFFFFFFF, int($count / 2**32));
1095a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      print pack('L*', $depth & 0xFFFFFFFF, int($depth / 2**32));
1096a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1097a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      foreach my $full_addr (@addrs) {
1098a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        my $addr = $full_addr;
1099a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $addr =~ s/0x0*//;  # strip off leading 0x, zeroes
1100a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        if (length($addr) > 16) {
1101a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          print STDERR "Invalid address in profile: $full_addr\n";
1102a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          next;
1103a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        }
1104a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        my $low_addr = substr($addr, -8);       # get last 8 hex chars
1105a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        my $high_addr = substr($addr, -16, 8);  # get up to 8 more hex chars
1106a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        print pack('L*', hex('0x' . $low_addr), hex('0x' . $high_addr));
1107a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
1108a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1109a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1110a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1111a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1112a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Print symbols and profile data
1113a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintSymbolizedProfile {
1114a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $symbols = shift;
1115a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $profile = shift;
1116a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $prog = shift;
1117a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1118a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $SYMBOL_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
1119a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $symbol_marker = $&;
1120a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1121a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print '--- ', $symbol_marker, "\n";
1122a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (defined($prog)) {
1123a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print 'binary=', $prog, "\n";
1124a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1125a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  while (my ($pc, $name) = each(%{$symbols})) {
1126a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $sep = ' ';
1127a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print '0x', $pc;
1128a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # We have a list of function names, which include the inlined
1129a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # calls.  They are separated (and terminated) by --, which is
1130a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # illegal in function names.
1131a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    for (my $j = 2; $j <= $#{$name}; $j += 3) {
1132a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      print $sep, $name->[$j];
1133a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $sep = '--';
1134a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1135a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print "\n";
1136a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1137a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print '---', "\n";
1138a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1139a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  $PROFILE_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
1140a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $profile_marker = $&;
1141a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print '--- ', $profile_marker, "\n";
1142a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (defined($main::collected_profile)) {
1143a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # if used with remote fetch, simply dump the collected profile to output.
1144a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    open(SRC, "<$main::collected_profile");
1145a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    while (<SRC>) {
1146a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      print $_;
1147a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1148a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    close(SRC);
1149a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
1150a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # dump a cpu-format profile to standard out
1151a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    PrintProfileData($profile);
1152a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1153a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1154a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1155a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Print text output
1156a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintText {
1157a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $symbols = shift;
1158a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $flat = shift;
1159a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $cumulative = shift;
1160a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $line_limit = shift;
1161a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
116225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $total = TotalProfile($flat);
116325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
1164a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Which profile to sort by?
1165a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $s = $main::opt_cum ? $cumulative : $flat;
1166a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1167a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $running_sum = 0;
1168a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $lines = 0;
1169a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $k (sort { GetEntry($s, $b) <=> GetEntry($s, $a) || $a cmp $b }
1170a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                 keys(%{$cumulative})) {
1171a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $f = GetEntry($flat, $k);
1172a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $c = GetEntry($cumulative, $k);
1173a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $running_sum += $f;
1174a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1175a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $sym = $k;
1176a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (exists($symbols->{$k})) {
1177a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1];
1178a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if ($main::opt_addresses) {
1179a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $sym = $k . " " . $sym;
1180a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
1181a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1182a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1183a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($f != 0 || $c != 0) {
1184a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      printf("%8s %6s %6s %8s %6s %s\n",
1185a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             Unparse($f),
1186a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             Percent($f, $total),
1187a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             Percent($running_sum, $total),
1188a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             Unparse($c),
1189a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             Percent($c, $total),
1190a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             $sym);
1191a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1192a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $lines++;
119325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    last if ($line_limit >= 0 && $lines >= $line_limit);
119425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
119525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
119625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
119725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# Callgrind format has a compression for repeated function and file
119825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# names.  You show the name the first time, and just use its number
119925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# subsequently.  This can cut down the file to about a third or a
120025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# quarter of its uncompressed size.  $key and $val are the key/value
120125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# pair that would normally be printed by callgrind; $map is a map from
120225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# value to number.
120325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evanssub CompressedCGName {
120425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my($key, $val, $map) = @_;
120525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $idx = $map->{$val};
120625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  # For very short keys, providing an index hurts rather than helps.
120725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if (length($val) <= 3) {
120825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    return "$key=$val\n";
120925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  } elsif (defined($idx)) {
121025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    return "$key=($idx)\n";
121125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  } else {
121225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    # scalar(keys $map) gives the number of items in the map.
121325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $idx = scalar(keys(%{$map})) + 1;
121425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $map->{$val} = $idx;
121525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    return "$key=($idx) $val\n";
1216a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1217a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1218a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1219a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Print the call graph in a way that's suiteable for callgrind.
1220a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintCallgrind {
1221a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $calls = shift;
1222a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $filename;
122325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my %filename_to_index_map;
122425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my %fnname_to_index_map;
122525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
1226a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_interactive) {
1227a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $filename = shift;
1228a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print STDERR "Writing callgrind file to '$filename'.\n"
1229a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
1230a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $filename = "&STDOUT";
1231a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
123225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  open(CG, ">$filename");
1233a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  printf CG ("events: Hits\n\n");
1234a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $call ( map { $_->[0] }
1235a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                     sort { $a->[1] cmp $b ->[1] ||
1236a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                            $a->[2] <=> $b->[2] }
1237a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                     map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
1238a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                           [$_, $1, $2] }
1239a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                     keys %$calls ) {
1240a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $count = int($calls->{$call});
1241a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
1242a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my ( $caller_file, $caller_line, $caller_function,
1243a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans         $callee_file, $callee_line, $callee_function ) =
1244a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans       ( $1, $2, $3, $5, $6, $7 );
1245a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
124625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    # TODO(csilvers): for better compression, collect all the
124725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    # caller/callee_files and functions first, before printing
124825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    # anything, and only compress those referenced more than once.
124925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    printf CG CompressedCGName("fl", $caller_file, \%filename_to_index_map);
125025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    printf CG CompressedCGName("fn", $caller_function, \%fnname_to_index_map);
1251a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (defined $6) {
125225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      printf CG CompressedCGName("cfl", $callee_file, \%filename_to_index_map);
125325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      printf CG CompressedCGName("cfn", $callee_function, \%fnname_to_index_map);
1254a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      printf CG ("calls=$count $callee_line\n");
1255a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1256a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    printf CG ("$caller_line $count\n\n");
1257a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1258a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1259a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1260a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Print disassembly for all all routines that match $main::opt_disasm
1261a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintDisassembly {
1262a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $libs = shift;
1263a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $flat = shift;
1264a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $cumulative = shift;
1265a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $disasm_opts = shift;
126625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
126725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $total = TotalProfile($flat);
1268a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1269a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $lib (@{$libs}) {
1270a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts);
1271a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $offset = AddressSub($lib->[1], $lib->[3]);
1272a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    foreach my $routine (sort ByName keys(%{$symbol_table})) {
1273a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $start_addr = $symbol_table->{$routine}->[0];
1274a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $end_addr = $symbol_table->{$routine}->[1];
1275a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # See if there are any samples in this routine
1276a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $length = hex(AddressSub($end_addr, $start_addr));
1277a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $addr = AddressAdd($start_addr, $offset);
1278a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      for (my $i = 0; $i < $length; $i++) {
1279a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        if (defined($cumulative->{$addr})) {
1280a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          PrintDisassembledFunction($lib->[0], $offset,
1281a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                                    $routine, $flat, $cumulative,
1282a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                                    $start_addr, $end_addr, $total);
1283a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          last;
1284a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        }
1285a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $addr = AddressInc($addr);
1286a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
1287a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1288a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1289a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1290a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1291a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Return reference to array of tuples of the form:
1292a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#       [start_address, filename, linenumber, instruction, limit_address]
1293a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# E.g.,
1294a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans#       ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"]
1295a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub Disassemble {
1296a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $prog = shift;
1297a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $offset = shift;
1298a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $start_addr = shift;
1299a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $end_addr = shift;
1300a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1301a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $objdump = $obj_tool_map{"objdump"};
130225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $cmd = ShellEscape($objdump, "-C", "-d", "-l", "--no-show-raw-insn",
130325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        "--start-address=0x$start_addr",
130425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        "--stop-address=0x$end_addr", $prog);
130525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  open(OBJDUMP, "$cmd |") || error("$cmd: $!\n");
1306a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my @result = ();
1307a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $filename = "";
1308a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $linenumber = -1;
1309a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $last = ["", "", "", ""];
1310a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  while (<OBJDUMP>) {
1311a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    s/\r//g;         # turn windows-looking lines into unix-looking lines
1312a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    chop;
1313a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (m|\s*([^:\s]+):(\d+)\s*$|) {
1314a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Location line of the form:
1315a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      #   <filename>:<linenumber>
1316a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $filename = $1;
1317a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $linenumber = $2;
1318a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } elsif (m/^ +([0-9a-f]+):\s*(.*)/) {
1319a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Disassembly line -- zero-extend address to full length
1320a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $addr = HexExtend($1);
1321a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $k = AddressAdd($addr, $offset);
1322a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $last->[4] = $k;   # Store ending address for previous instruction
1323a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $last = [$k, $filename, $linenumber, $2, $end_addr];
1324a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      push(@result, $last);
1325a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1326a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1327a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  close(OBJDUMP);
1328a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  return @result;
1329a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1330a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1331a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# The input file should contain lines of the form /proc/maps-like
1332a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# output (same format as expected from the profiles) or that looks
1333a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# like hex addresses (like "0xDEADBEEF").  We will parse all
1334a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# /proc/maps output, and for all the hex addresses, we will output
1335a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# "short" symbol names, one per line, in the same order as the input.
1336a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintSymbols {
1337a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $maps_and_symbols_file = shift;
1338a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1339a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # ParseLibraries expects pcs to be in a set.  Fine by us...
1340a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my @pclist = ();   # pcs in sorted order
1341a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $pcs = {};
1342a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $map = "";
1343a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $line (<$maps_and_symbols_file>) {
1344a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $line =~ s/\r//g;    # turn windows-looking lines into unix-looking lines
1345a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($line =~ /\b(0x[0-9a-f]+)\b/i) {
1346a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      push(@pclist, HexExtend($1));
1347a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $pcs->{$pclist[-1]} = 1;
1348a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    } else {
1349a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $map .= $line;
1350a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1351a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1352a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1353a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $libs = ParseLibraries($main::prog, $map, $pcs);
1354a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $symbols = ExtractSymbols($libs, $pcs);
1355a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1356a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $pc (@pclist) {
1357a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # ->[0] is the shortname, ->[2] is the full name
1358a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print(($symbols->{$pc}->[0] || "??") . "\n");
1359a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1360a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1361a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1362a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1363a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# For sorting functions by name
1364a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub ByName {
1365a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  return ShortFunctionName($a) cmp ShortFunctionName($b);
1366a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1367a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
136825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# Print source-listing for all all routines that match $list_opts
1369a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintListing {
137025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $total = shift;
1371a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $libs = shift;
1372a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $flat = shift;
1373a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $cumulative = shift;
1374a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $list_opts = shift;
137525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $html = shift;
137625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
137725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $output = \*STDOUT;
137825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $fname = "";
1379a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
138025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if ($html) {
138125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    # Arrange to write the output to a temporary file
138225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $fname = TempName($main::next_tmpfile, "html");
138325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $main::next_tmpfile++;
138425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    if (!open(TEMP, ">$fname")) {
138525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      print STDERR "$fname: $!\n";
138625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      return;
138725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    }
138825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $output = \*TEMP;
138925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    print $output HtmlListingHeader();
139025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
139125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                    $main::prog, Unparse($total), Units());
139225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
139325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
139425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $listed = 0;
1395a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $lib (@{$libs}) {
1396a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
1397a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $offset = AddressSub($lib->[1], $lib->[3]);
1398a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    foreach my $routine (sort ByName keys(%{$symbol_table})) {
1399a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Print if there are any samples in this routine
1400a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $start_addr = $symbol_table->{$routine}->[0];
1401a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $end_addr = $symbol_table->{$routine}->[1];
1402a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $length = hex(AddressSub($end_addr, $start_addr));
1403a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $addr = AddressAdd($start_addr, $offset);
1404a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      for (my $i = 0; $i < $length; $i++) {
1405a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        if (defined($cumulative->{$addr})) {
140625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          $listed += PrintSource(
140725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans            $lib->[0], $offset,
140825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans            $routine, $flat, $cumulative,
140925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans            $start_addr, $end_addr,
141025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans            $html,
141125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans            $output);
1412a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          last;
1413a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        }
1414a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $addr = AddressInc($addr);
1415a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
1416a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1417a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
141825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
141925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if ($html) {
142025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    if ($listed > 0) {
142125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      print $output HtmlListingFooter();
142225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      close($output);
142325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      RunWeb($fname);
142425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    } else {
142525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      close($output);
142625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      unlink($fname);
142725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    }
142825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
142925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
143025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
143125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evanssub HtmlListingHeader {
143225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  return <<'EOF';
143325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans<DOCTYPE html>
143425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans<html>
143525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans<head>
143625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans<title>Pprof listing</title>
143725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans<style type="text/css">
143825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansbody {
143925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  font-family: sans-serif;
144025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
144125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansh1 {
144225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  font-size: 1.5em;
144325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  margin-bottom: 4px;
144425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
144525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.legend {
144625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  font-size: 1.25em;
144725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
144825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.line {
144925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  color: #aaaaaa;
145025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
145125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.nop {
145225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  color: #aaaaaa;
145325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
145425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.unimportant {
145525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  color: #cccccc;
145625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
145725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.disasmloc {
145825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  color: #000000;
145925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
146025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.deadsrc {
146125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  cursor: pointer;
146225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
146325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.deadsrc:hover {
146425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  background-color: #eeeeee;
146525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
146625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.livesrc {
146725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  color: #0000ff;
146825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  cursor: pointer;
146925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
147025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.livesrc:hover {
147125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  background-color: #eeeeee;
147225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
147325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans.asm {
147425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  color: #008800;
147525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  display: none;
147625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
147725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans</style>
147825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans<script type="text/javascript">
147925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evansfunction pprof_toggle_asm(e) {
148025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  var target;
148125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if (!e) e = window.event;
148225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if (e.target) target = e.target;
148325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  else if (e.srcElement) target = e.srcElement;
148425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
148525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if (target) {
148625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    var asm = target.nextSibling;
148725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    if (asm && asm.className == "asm") {
148825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      asm.style.display = (asm.style.display == "block" ? "" : "block");
148925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      e.preventDefault();
149025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      return false;
149125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    }
149225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
149325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
149425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans</script>
149525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans</head>
149625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans<body>
149725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason EvansEOF
149825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
149925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
150025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evanssub HtmlListingFooter {
150125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  return <<'EOF';
150225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans</body>
150325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans</html>
150425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason EvansEOF
150525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
150625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
150725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evanssub HtmlEscape {
150825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $text = shift;
150925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  $text =~ s/&/&amp;/g;
151025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  $text =~ s/</&lt;/g;
151125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  $text =~ s/>/&gt;/g;
151225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  return $text;
1513a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1514a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1515a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Returns the indentation of the line, if it has any non-whitespace
1516a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# characters.  Otherwise, returns -1.
1517a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub Indentation {
1518a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $line = shift;
1519a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (m/^(\s*)\S/) {
1520a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return length($1);
1521a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
1522a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return -1;
1523a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1524a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1525a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
152625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# If the symbol table contains inlining info, Disassemble() may tag an
152725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# instruction with a location inside an inlined function.  But for
152825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# source listings, we prefer to use the location in the function we
152925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# are listing.  So use MapToSymbols() to fetch full location
153025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# information for each instruction and then pick out the first
153125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# location from a location list (location list contains callers before
153225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# callees in case of inlining).
153325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans#
153425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans# After this routine has run, each entry in $instructions contains:
153525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans#   [0] start address
153625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans#   [1] filename for function we are listing
153725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans#   [2] line number for function we are listing
153825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans#   [3] disassembly
153925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans#   [4] limit address
154025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans#   [5] most specific filename (may be different from [1] due to inlining)
154125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans#   [6] most specific line number (may be different from [2] due to inlining)
154225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evanssub GetTopLevelLineNumbers {
154325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my ($lib, $offset, $instructions) = @_;
154425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $pcs = [];
154525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  for (my $i = 0; $i <= $#{$instructions}; $i++) {
154625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    push(@{$pcs}, $instructions->[$i]->[0]);
154725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
154825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $symbols = {};
154925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  MapToSymbols($lib, $offset, $pcs, $symbols);
155025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  for (my $i = 0; $i <= $#{$instructions}; $i++) {
155125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $e = $instructions->[$i];
155225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    push(@{$e}, $e->[1]);
155325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    push(@{$e}, $e->[2]);
155425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $addr = $e->[0];
155525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $sym = $symbols->{$addr};
155625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    if (defined($sym)) {
155725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      if ($#{$sym} >= 2 && $sym->[1] =~ m/^(.*):(\d+)$/) {
155825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        $e->[1] = $1;  # File name
155925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        $e->[2] = $2;  # Line number
156025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      }
156125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    }
156225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
156325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans}
156425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
1565a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Print source-listing for one routine
1566a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintSource {
1567a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $prog = shift;
1568a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $offset = shift;
1569a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $routine = shift;
1570a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $flat = shift;
1571a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $cumulative = shift;
1572a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $start_addr = shift;
1573a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $end_addr = shift;
157425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $html = shift;
157525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $output = shift;
1576a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1577a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Disassemble all instructions (just to get line numbers)
1578a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
157925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  GetTopLevelLineNumbers($prog, $offset, \@instructions);
1580a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1581a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Hack 1: assume that the first source file encountered in the
1582a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # disassembly contains the routine
1583a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $filename = undef;
1584a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  for (my $i = 0; $i <= $#instructions; $i++) {
1585a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($instructions[$i]->[2] >= 0) {
1586a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $filename = $instructions[$i]->[1];
1587a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      last;
1588a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1589a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1590a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (!defined($filename)) {
1591a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print STDERR "no filename found in $routine\n";
159225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    return 0;
1593a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1594a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1595a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Hack 2: assume that the largest line number from $filename is the
1596a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # end of the procedure.  This is typically safe since if P1 contains
1597a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # an inlined call to P2, then P2 usually occurs earlier in the
1598a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # source file.  If this does not work, we might have to compute a
1599a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # density profile or just print all regions we find.
1600a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $lastline = 0;
1601a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  for (my $i = 0; $i <= $#instructions; $i++) {
1602a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $f = $instructions[$i]->[1];
1603a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $l = $instructions[$i]->[2];
1604a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (($f eq $filename) && ($l > $lastline)) {
1605a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $lastline = $l;
1606a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1607a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1608a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1609a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Hack 3: assume the first source location from "filename" is the start of
1610a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # the source code.
1611a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $firstline = 1;
1612a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  for (my $i = 0; $i <= $#instructions; $i++) {
1613a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($instructions[$i]->[1] eq $filename) {
1614a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $firstline = $instructions[$i]->[2];
1615a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      last;
1616a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1617a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1618a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1619a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Hack 4: Extend last line forward until its indentation is less than
1620a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # the indentation we saw on $firstline
1621a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $oldlastline = $lastline;
1622a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  {
1623a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (!open(FILE, "<$filename")) {
1624a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      print STDERR "$filename: $!\n";
162525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      return 0;
1626a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1627a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $l = 0;
1628a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $first_indentation = -1;
1629a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    while (<FILE>) {
1630a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      s/\r//g;         # turn windows-looking lines into unix-looking lines
1631a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $l++;
1632a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $indent = Indentation($_);
1633a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if ($l >= $firstline) {
1634a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        if ($first_indentation < 0 && $indent >= 0) {
1635a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          $first_indentation = $indent;
1636a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          last if ($first_indentation == 0);
1637a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        }
1638a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
1639a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if ($l >= $lastline && $indent >= 0) {
1640a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        if ($indent >= $first_indentation) {
1641a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          $lastline = $l+1;
1642a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        } else {
1643a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          last;
1644a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        }
1645a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
1646a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1647a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    close(FILE);
1648a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1649a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1650a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Assign all samples to the range $firstline,$lastline,
1651a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Hack 4: If an instruction does not occur in the range, its samples
1652a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # are moved to the next instruction that occurs in the range.
165325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $samples1 = {};        # Map from line number to flat count
165425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $samples2 = {};        # Map from line number to cumulative count
165525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $running1 = 0;         # Unassigned flat counts
165625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $running2 = 0;         # Unassigned cumulative counts
165725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $total1 = 0;           # Total flat counts
165825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $total2 = 0;           # Total cumulative counts
165925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my %disasm = ();          # Map from line number to disassembly
166025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $running_disasm = "";  # Unassigned disassembly
166125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $skip_marker = "---\n";
166225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if ($html) {
166325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $skip_marker = "";
166425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    for (my $l = $firstline; $l <= $lastline; $l++) {
166525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $disasm{$l} = "";
166625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    }
166725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
166825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $last_dis_filename = '';
166925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $last_dis_linenum = -1;
167025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $last_touched_line = -1;  # To detect gaps in disassembly for a line
1671a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $e (@instructions) {
1672a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Add up counts for all address that fall inside this instruction
1673a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $c1 = 0;
1674a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $c2 = 0;
1675a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
1676a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $c1 += GetEntry($flat, $a);
1677a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $c2 += GetEntry($cumulative, $a);
1678a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
167925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
168025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    if ($html) {
168125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      my $dis = sprintf("      %6s %6s \t\t%8s: %s ",
168225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        HtmlPrintNumber($c1),
168325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        HtmlPrintNumber($c2),
168425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        UnparseAddress($offset, $e->[0]),
168525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        CleanDisassembly($e->[3]));
168625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      
168725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      # Append the most specific source line associated with this instruction
168825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      if (length($dis) < 80) { $dis .= (' ' x (80 - length($dis))) };
168925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $dis = HtmlEscape($dis);
169025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      my $f = $e->[5];
169125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      my $l = $e->[6];
169225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      if ($f ne $last_dis_filename) {
169325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        $dis .= sprintf("<span class=disasmloc>%s:%d</span>", 
169425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        HtmlEscape(CleanFileName($f)), $l);
169525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      } elsif ($l ne $last_dis_linenum) {
169625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        # De-emphasize the unchanged file name portion
169725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        $dis .= sprintf("<span class=unimportant>%s</span>" .
169825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        "<span class=disasmloc>:%d</span>", 
169925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        HtmlEscape(CleanFileName($f)), $l);
170025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      } else {
170125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        # De-emphasize the entire location
170225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        $dis .= sprintf("<span class=unimportant>%s:%d</span>", 
170325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                        HtmlEscape(CleanFileName($f)), $l);
170425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      }
170525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $last_dis_filename = $f;
170625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $last_dis_linenum = $l;
170725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $running_disasm .= $dis;
170825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $running_disasm .= "\n";
170925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    }
171025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
1711a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $running1 += $c1;
1712a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $running2 += $c2;
1713a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $total1 += $c1;
1714a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $total2 += $c2;
1715a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $file = $e->[1];
1716a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $line = $e->[2];
1717a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (($file eq $filename) &&
1718a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        ($line >= $firstline) &&
1719a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        ($line <= $lastline)) {
1720a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Assign all accumulated samples to this line
1721a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      AddEntry($samples1, $line, $running1);
1722a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      AddEntry($samples2, $line, $running2);
1723a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $running1 = 0;
1724a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $running2 = 0;
172525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      if ($html) {
172625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        if ($line != $last_touched_line && $disasm{$line} ne '') {
172725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          $disasm{$line} .= "\n";
172825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        }
172925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        $disasm{$line} .= $running_disasm;
173025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        $running_disasm = '';
173125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        $last_touched_line = $line;
173225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      }
1733a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1734a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1735a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1736a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Assign any leftover samples to $lastline
1737a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  AddEntry($samples1, $lastline, $running1);
1738a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  AddEntry($samples2, $lastline, $running2);
173925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if ($html) {
174025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    if ($lastline != $last_touched_line && $disasm{$lastline} ne '') {
174125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      $disasm{$lastline} .= "\n";
174225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    }
174325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $disasm{$lastline} .= $running_disasm;
174425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
174525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans
174625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if ($html) {
174725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    printf $output (
174825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      "<h1>%s</h1>%s\n<pre onClick=\"pprof_toggle_asm()\">\n" .
174925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      "Total:%6s %6s (flat / cumulative %s)\n",
175025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      HtmlEscape(ShortFunctionName($routine)),
175125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      HtmlEscape(CleanFileName($filename)),
175225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      Unparse($total1),
175325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      Unparse($total2),
175425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      Units());
175525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  } else {
175625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    printf $output (
175725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      "ROUTINE ====================== %s in %s\n" .
175825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      "%6s %6s Total %s (flat / cumulative)\n",
175925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      ShortFunctionName($routine),
176025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      CleanFileName($filename),
176125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      Unparse($total1),
176225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      Unparse($total2),
176325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      Units());
176425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
1765a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (!open(FILE, "<$filename")) {
1766a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print STDERR "$filename: $!\n";
176725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    return 0;
1768a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1769a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $l = 0;
1770a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  while (<FILE>) {
1771a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    s/\r//g;         # turn windows-looking lines into unix-looking lines
1772a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $l++;
1773a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($l >= $firstline - 5 &&
1774a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        (($l <= $oldlastline + 5) || ($l <= $lastline))) {
1775a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      chop;
1776a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $text = $_;
177725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      if ($l == $firstline) { print $output $skip_marker; }
177825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      my $n1 = GetEntry($samples1, $l);
177925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      my $n2 = GetEntry($samples2, $l);
178025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      if ($html) {
178125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        # Emit a span that has one of the following classes:
178225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        #    livesrc -- has samples
178325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        #    deadsrc -- has disassembly, but with no samples
178425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        #    nop     -- has no matching disasembly
178525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        # Also emit an optional span containing disassembly.
178625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        my $dis = $disasm{$l};
178725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        my $asm = "";
178825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        if (defined($dis) && $dis ne '') {
178925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          $asm = "<span class=\"asm\">" . $dis . "</span>";
179025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        }
179125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        my $source_class = (($n1 + $n2 > 0) 
179225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                            ? "livesrc" 
179325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                            : (($asm ne "") ? "deadsrc" : "nop"));
179425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        printf $output (
179525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          "<span class=\"line\">%5d</span> " .
179625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          "<span class=\"%s\">%6s %6s %s</span>%s\n",
179725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          $l, $source_class,
179825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          HtmlPrintNumber($n1),
179925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          HtmlPrintNumber($n2),
180025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          HtmlEscape($text),
180125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          $asm);
180225a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      } else {
180325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans        printf $output(
180425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          "%6s %6s %4d: %s\n",
180525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          UnparseAlt($n1),
180625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          UnparseAlt($n2),
180725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          $l,
180825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans          $text);
180925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      }
181025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans      if ($l == $lastline)  { print $output $skip_marker; }
1811a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    };
1812a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1813a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  close(FILE);
181425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  if ($html) {
181525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    print $output "</pre>\n";
181625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  }
181725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  return 1;
1818a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1819a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1820a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Return the source line for the specified file/linenumber.
1821a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Returns undef if not found.
1822a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub SourceLine {
1823a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $file = shift;
1824a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $line = shift;
1825a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1826a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Look in cache
1827a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (!defined($main::source_cache{$file})) {
1828a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (100 < scalar keys(%main::source_cache)) {
1829a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Clear the cache when it gets too big
1830a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::source_cache = ();
1831a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1832a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1833a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Read all lines from the file
1834a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if (!open(FILE, "<$file")) {
1835a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      print STDERR "$file: $!\n";
1836a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $main::source_cache{$file} = [];  # Cache the negative result
1837a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      return undef;
1838a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1839a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $lines = [];
1840a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    push(@{$lines}, "");        # So we can use 1-based line numbers as indices
1841a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    while (<FILE>) {
1842a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      push(@{$lines}, $_);
1843a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1844a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    close(FILE);
1845a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1846a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Save the lines in the cache
1847a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $main::source_cache{$file} = $lines;
1848a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1849a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1850a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $lines = $main::source_cache{$file};
1851a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if (($line < 0) || ($line > $#{$lines})) {
1852a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return undef;
1853a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
1854a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return $lines->[$line];
1855a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1856a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1857a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1858a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Print disassembly for one routine with interspersed source if available
1859a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintDisassembledFunction {
1860a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $prog = shift;
1861a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $offset = shift;
1862a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $routine = shift;
1863a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $flat = shift;
1864a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $cumulative = shift;
1865a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $start_addr = shift;
1866a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $end_addr = shift;
1867a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $total = shift;
1868a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1869a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Disassemble all instructions
1870a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
1871a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1872a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Make array of counts per instruction
1873a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my @flat_count = ();
1874a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my @cum_count = ();
1875a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $flat_total = 0;
1876a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $cum_total = 0;
1877a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $e (@instructions) {
1878a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Add up counts for all address that fall inside this instruction
1879a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $c1 = 0;
1880a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $c2 = 0;
1881a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
1882a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $c1 += GetEntry($flat, $a);
1883a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $c2 += GetEntry($cumulative, $a);
1884a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1885a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    push(@flat_count, $c1);
1886a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    push(@cum_count, $c2);
1887a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $flat_total += $c1;
1888a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $cum_total += $c2;
1889a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1890a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1891a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Print header with total counts
1892a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  printf("ROUTINE ====================== %s\n" .
1893a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans         "%6s %6s %s (flat, cumulative) %.1f%% of total\n",
1894a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans         ShortFunctionName($routine),
1895a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans         Unparse($flat_total),
1896a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans         Unparse($cum_total),
1897a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans         Units(),
1898a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans         ($cum_total * 100.0) / $total);
1899a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1900a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Process instructions in order
1901a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $current_file = "";
1902a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  for (my $i = 0; $i <= $#instructions; ) {
1903a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $e = $instructions[$i];
1904a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1905a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Print the new file name whenever we switch files
1906a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($e->[1] ne $current_file) {
1907a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $current_file = $e->[1];
1908a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $fname = $current_file;
1909a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $fname =~ s|^\./||;   # Trim leading "./"
1910a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1911a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Shorten long file names
1912a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if (length($fname) >= 58) {
1913a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $fname = "..." . substr($fname, -55);
1914a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
1915a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      printf("-------------------- %s\n", $fname);
1916a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1917a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1918a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # TODO: Compute range of lines to print together to deal with
1919a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # small reorderings.
1920a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $first_line = $e->[2];
1921a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $last_line = $first_line;
1922a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my %flat_sum = ();
1923a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my %cum_sum = ();
1924a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    for (my $l = $first_line; $l <= $last_line; $l++) {
1925a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $flat_sum{$l} = 0;
1926a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $cum_sum{$l} = 0;
1927a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1928a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1929a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Find run of instructions for this range of source lines
1930a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $first_inst = $i;
1931a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    while (($i <= $#instructions) &&
1932a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans           ($instructions[$i]->[2] >= $first_line) &&
1933a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans           ($instructions[$i]->[2] <= $last_line)) {
1934a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $e = $instructions[$i];
1935a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $flat_sum{$e->[2]} += $flat_count[$i];
1936a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $cum_sum{$e->[2]} += $cum_count[$i];
1937a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $i++;
1938a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1939a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $last_inst = $i - 1;
1940a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1941a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Print source lines
1942a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    for (my $l = $first_line; $l <= $last_line; $l++) {
1943a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $line = SourceLine($current_file, $l);
1944a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if (!defined($line)) {
1945a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $line = "?\n";
1946a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        next;
1947a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      } else {
1948a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $line =~ s/^\s+//;
1949a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
1950a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      printf("%6s %6s %5d: %s",
1951a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             UnparseAlt($flat_sum{$l}),
1952a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             UnparseAlt($cum_sum{$l}),
1953a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             $l,
1954a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             $line);
1955a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1956a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1957a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Print disassembly
1958a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    for (my $x = $first_inst; $x <= $last_inst; $x++) {
1959a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $e = $instructions[$x];
1960a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      printf("%6s %6s    %8s: %6s\n",
1961a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             UnparseAlt($flat_count[$x]),
1962a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans             UnparseAlt($cum_count[$x]),
196325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans             UnparseAddress($offset, $e->[0]),
196425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans             CleanDisassembly($e->[3]));
1965a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
1966a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1967a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans}
1968a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1969a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans# Print DOT graph
1970a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evanssub PrintDot {
1971a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $prog = shift;
1972a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $symbols = shift;
1973a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $raw = shift;
1974a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $flat = shift;
1975a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $cumulative = shift;
1976a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $overall_total = shift;
1977a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1978a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Get total
1979a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $local_total = TotalProfile($flat);
1980a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $nodelimit = int($main::opt_nodefraction * $local_total);
1981a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $edgelimit = int($main::opt_edgefraction * $local_total);
1982a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $nodecount = $main::opt_nodecount;
1983a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
1984a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Find nodes to include
1985a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my @list = (sort { abs(GetEntry($cumulative, $b)) <=>
1986a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                     abs(GetEntry($cumulative, $a))
1987a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                     || $a cmp $b }
1988a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              keys(%{$cumulative}));
1989a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $last = $nodecount - 1;
1990a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($last > $#list) {
1991a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $last = $#list;
1992a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1993a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  while (($last >= 0) &&
1994a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans         (abs(GetEntry($cumulative, $list[$last])) <= $nodelimit)) {
1995a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $last--;
1996a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
1997a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($last < 0) {
1998a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    print STDERR "No nodes to print\n";
1999a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    return 0;
2000a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
2001a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2002a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($nodelimit > 0 || $edgelimit > 0) {
2003a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    printf STDERR ("Dropping nodes with <= %s %s; edges with <= %s abs(%s)\n",
2004a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                   Unparse($nodelimit), Units(),
2005a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                   Unparse($edgelimit), Units());
2006a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
2007a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2008a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Open DOT output file
2009a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $output;
201025a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $escaped_dot = ShellEscape(@DOT);
201125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $escaped_ps2pdf = ShellEscape(@PS2PDF);
2012a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_gv) {
201325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "ps"));
201425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $output = "| $escaped_dot -Tps2 >$escaped_outfile";
20159a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  } elsif ($main::opt_evince) {
201625a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "pdf"));
201725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - $escaped_outfile";
2018a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } elsif ($main::opt_ps) {
201925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $output = "| $escaped_dot -Tps2";
2020a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } elsif ($main::opt_pdf) {
202125a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - -";
2022d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  } elsif ($main::opt_web || $main::opt_svg) {
2023d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    # We need to post-process the SVG, so write to a temporary file always.
202425a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "svg"));
202525a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $output = "| $escaped_dot -Tsvg >$escaped_outfile";
2026a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } elsif ($main::opt_gif) {
202725a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    $output = "| $escaped_dot -Tgif";
2028a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  } else {
2029a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $output = ">&STDOUT";
2030a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
2031a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  open(DOT, $output) || error("$output: $!\n");
2032a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2033a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Title
2034a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  printf DOT ("digraph \"%s; %s %s\" {\n",
2035a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              $prog,
2036a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              Unparse($overall_total),
2037a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              Units());
2038a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  if ($main::opt_pdf) {
2039a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # The output is more printable if we set the page size for dot.
2040a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    printf DOT ("size=\"8,11\"\n");
2041a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
2042a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  printf DOT ("node [width=0.375,height=0.25];\n");
2043a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2044a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Print legend
2045a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  printf DOT ("Legend [shape=box,fontsize=24,shape=plaintext," .
2046a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              "label=\"%s\\l%s\\l%s\\l%s\\l%s\\l\"];\n",
2047a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              $prog,
2048a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              sprintf("Total %s: %s", Units(), Unparse($overall_total)),
2049a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              sprintf("Focusing on: %s", Unparse($local_total)),
2050a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              sprintf("Dropped nodes with <= %s abs(%s)",
2051a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                      Unparse($nodelimit), Units()),
2052a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              sprintf("Dropped edges with <= %s %s",
2053a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                      Unparse($edgelimit), Units())
2054a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans              );
2055a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2056a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Print nodes
2057a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my %node = ();
2058a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $nextnode = 1;
2059a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $a (@list[0..$last]) {
2060a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Pick font size
2061a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $f = GetEntry($flat, $a);
2062a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $c = GetEntry($cumulative, $a);
2063a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2064a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $fs = 8;
2065a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($local_total > 0) {
2066a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $fs = 8 + (50.0 * sqrt(abs($f * 1.0 / $local_total)));
2067a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
2068a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2069a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $node{$a} = $nextnode++;
2070a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $sym = $a;
2071a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $sym =~ s/\s+/\\n/g;
2072a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $sym =~ s/::/\\n/g;
2073a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2074a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # Extra cumulative info to print for non-leaves
2075a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $extra = "";
2076a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($f != $c) {
2077a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $extra = sprintf("\\rof %s (%s)",
2078a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                       Unparse($c),
207925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                       Percent($c, $local_total));
2080a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
2081a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my $style = "";
2082a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    if ($main::opt_heapcheck) {
2083a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if ($f > 0) {
2084a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        # make leak-causing nodes more visible (add a background)
2085a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $style = ",style=filled,fillcolor=gray"
2086a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      } elsif ($f < 0) {
2087a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        # make anti-leak-causing nodes (which almost never occur)
2088a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        # stand out as well (triple border)
2089a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $style = ",peripheries=3"
2090a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
2091a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
2092a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2093a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    printf DOT ("N%d [label=\"%s\\n%s (%s)%s\\r" .
2094a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                "\",shape=box,fontsize=%.1f%s];\n",
2095a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                $node{$a},
2096a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                $sym,
2097a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                Unparse($f),
209825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans                Percent($f, $local_total),
2099a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                $extra,
2100a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                $fs,
2101a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                $style,
2102a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans               );
2103a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
2104a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2105a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  # Get edges and counts per edge
2106a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my %edge = ();
2107a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  my $n;
210825a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  my $fullname_to_shortname_map = {};
210925a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans  FillFullnameToShortnameMap($symbols, $fullname_to_shortname_map);
2110a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  foreach my $k (keys(%{$raw})) {
2111a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    # TODO: omit low %age edges
2112a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $n = $raw->{$k};
211325a000e89649d9ce5aacc1089408b8b3bafeb5e4Jason Evans    my @translated = TranslateStack($symbols, $fullname_to_shortname_map, $k);
2114a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    for (my $i = 1; $i <= $#translated; $i++) {
2115a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $src = $translated[$i];
2116a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $dst = $translated[$i-1];
2117a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      #next if ($src eq $dst);  # Avoid self-edges?
2118a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if (exists($node{$src}) && exists($node{$dst})) {
2119a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        my $edge_label = "$src\001$dst";
2120a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        if (!exists($edge{$edge_label})) {
2121a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans          $edge{$edge_label} = 0;
2122a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        }
2123a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $edge{$edge_label} += $n;
2124a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
2125a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
2126a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
2127a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
21289a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  # Print edges (process in order of decreasing counts)
21299a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  my %indegree = ();   # Number of incoming edges added per node so far
21309a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  my %outdegree = ();  # Number of outgoing edges added per node so far
21319a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans  foreach my $e (sort { $edge{$b} <=> $edge{$a} } keys(%edge)) {
2132a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    my @x = split(/\001/, $e);
2133a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    $n = $edge{$e};
2134a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
21359a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    # Initialize degree of kept incoming and outgoing edges if necessary
21369a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    my $src = $x[0];
21379a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    my $dst = $x[1];
21389a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    if (!exists($outdegree{$src})) { $outdegree{$src} = 0; }
21399a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    if (!exists($indegree{$dst})) { $indegree{$dst} = 0; }
21409a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans
21419a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    my $keep;
21429a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    if ($indegree{$dst} == 0) {
21439a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      # Keep edge if needed for reachability
21449a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      $keep = 1;
21459a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    } elsif (abs($n) <= $edgelimit) {
21469a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      # Drop if we are below --edgefraction
21479a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      $keep = 0;
21489a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    } elsif ($outdegree{$src} >= $main::opt_maxdegree ||
21499a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans             $indegree{$dst} >= $main::opt_maxdegree) {
21509a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      # Keep limited number of in/out edges per node
21519a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      $keep = 0;
21529a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    } else {
21539a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      $keep = 1;
21549a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    }
21559a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans
21569a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans    if ($keep) {
21579a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      $outdegree{$src}++;
21589a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans      $indegree{$dst}++;
21599a8fc41bb9752129510f3387f5c20cb798ff6b1aJason Evans
2160a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Compute line width based on edge count
2161a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0);
2162a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if ($fraction > 1) { $fraction = 1; }
2163a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $w = $fraction * 2;
2164d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      if ($w < 1 && ($main::opt_web || $main::opt_svg)) {
2165d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans        # SVG output treats line widths < 1 poorly.
2166d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans        $w = 1;
2167d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans      }
2168a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2169a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Dot sometimes segfaults if given edge weights that are too large, so
2170a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # we cap the weights at a large value
2171a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $edgeweight = abs($n) ** 0.7;
2172a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if ($edgeweight > 100000) { $edgeweight = 100000; }
2173a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      $edgeweight = int($edgeweight);
2174a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2175a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      my $style = sprintf("setlinewidth(%f)", $w);
2176a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      if ($x[1] =~ m/\(inline\)/) {
2177a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans        $style .= ",dashed";
2178a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      }
2179a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2180a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      # Use a slightly squashed function of the edge count as the weight
2181a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans      printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n",
2182a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                  $node{$x[0]},
2183a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                  $node{$x[1]},
2184a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                  Unparse($n),
2185a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                  $edgeweight,
2186a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans                  $style);
2187a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans    }
2188a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  }
2189a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans
2190a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  print DOT ("}\n");
2191a91f2109292f4f4522f75d0636fdba30bda26e76Jason Evans  close(DOT);
2192d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans
2193d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans  if ($main::opt_web || $main::opt_svg) {
2194d65cdfe23310253f065bea02ba8e0016dc9b6aeeJason Evans    # Rewrite SVG to be more usable inside web browser.
2195