xref: /aosp_15_r20/external/jemalloc_new/bin/jeprof.in (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
1*1208bc7eSAndroid Build Coastguard Worker#! /usr/bin/env perl
2*1208bc7eSAndroid Build Coastguard Worker
3*1208bc7eSAndroid Build Coastguard Worker# Copyright (c) 1998-2007, Google Inc.
4*1208bc7eSAndroid Build Coastguard Worker# All rights reserved.
5*1208bc7eSAndroid Build Coastguard Worker#
6*1208bc7eSAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without
7*1208bc7eSAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are
8*1208bc7eSAndroid Build Coastguard Worker# met:
9*1208bc7eSAndroid Build Coastguard Worker#
10*1208bc7eSAndroid Build Coastguard Worker#     * Redistributions of source code must retain the above copyright
11*1208bc7eSAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer.
12*1208bc7eSAndroid Build Coastguard Worker#     * Redistributions in binary form must reproduce the above
13*1208bc7eSAndroid Build Coastguard Worker# copyright notice, this list of conditions and the following disclaimer
14*1208bc7eSAndroid Build Coastguard Worker# in the documentation and/or other materials provided with the
15*1208bc7eSAndroid Build Coastguard Worker# distribution.
16*1208bc7eSAndroid Build Coastguard Worker#     * Neither the name of Google Inc. nor the names of its
17*1208bc7eSAndroid Build Coastguard Worker# contributors may be used to endorse or promote products derived from
18*1208bc7eSAndroid Build Coastguard Worker# this software without specific prior written permission.
19*1208bc7eSAndroid Build Coastguard Worker#
20*1208bc7eSAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*1208bc7eSAndroid Build Coastguard Worker# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*1208bc7eSAndroid Build Coastguard Worker# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*1208bc7eSAndroid Build Coastguard Worker# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*1208bc7eSAndroid Build Coastguard Worker# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*1208bc7eSAndroid Build Coastguard Worker# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*1208bc7eSAndroid Build Coastguard Worker# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*1208bc7eSAndroid Build Coastguard Worker# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*1208bc7eSAndroid Build Coastguard Worker# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*1208bc7eSAndroid Build Coastguard Worker# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*1208bc7eSAndroid Build Coastguard Worker# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*1208bc7eSAndroid Build Coastguard Worker
32*1208bc7eSAndroid Build Coastguard Worker# ---
33*1208bc7eSAndroid Build Coastguard Worker# Program for printing the profile generated by common/profiler.cc,
34*1208bc7eSAndroid Build Coastguard Worker# or by the heap profiler (common/debugallocation.cc)
35*1208bc7eSAndroid Build Coastguard Worker#
36*1208bc7eSAndroid Build Coastguard Worker# The profile contains a sequence of entries of the form:
37*1208bc7eSAndroid Build Coastguard Worker#       <count> <stack trace>
38*1208bc7eSAndroid Build Coastguard Worker# This program parses the profile, and generates user-readable
39*1208bc7eSAndroid Build Coastguard Worker# output.
40*1208bc7eSAndroid Build Coastguard Worker#
41*1208bc7eSAndroid Build Coastguard Worker# Examples:
42*1208bc7eSAndroid Build Coastguard Worker#
43*1208bc7eSAndroid Build Coastguard Worker# % tools/jeprof "program" "profile"
44*1208bc7eSAndroid Build Coastguard Worker#   Enters "interactive" mode
45*1208bc7eSAndroid Build Coastguard Worker#
46*1208bc7eSAndroid Build Coastguard Worker# % tools/jeprof --text "program" "profile"
47*1208bc7eSAndroid Build Coastguard Worker#   Generates one line per procedure
48*1208bc7eSAndroid Build Coastguard Worker#
49*1208bc7eSAndroid Build Coastguard Worker# % tools/jeprof --gv "program" "profile"
50*1208bc7eSAndroid Build Coastguard Worker#   Generates annotated call-graph and displays via "gv"
51*1208bc7eSAndroid Build Coastguard Worker#
52*1208bc7eSAndroid Build Coastguard Worker# % tools/jeprof --gv --focus=Mutex "program" "profile"
53*1208bc7eSAndroid Build Coastguard Worker#   Restrict to code paths that involve an entry that matches "Mutex"
54*1208bc7eSAndroid Build Coastguard Worker#
55*1208bc7eSAndroid Build Coastguard Worker# % tools/jeprof --gv --focus=Mutex --ignore=string "program" "profile"
56*1208bc7eSAndroid Build Coastguard Worker#   Restrict to code paths that involve an entry that matches "Mutex"
57*1208bc7eSAndroid Build Coastguard Worker#   and does not match "string"
58*1208bc7eSAndroid Build Coastguard Worker#
59*1208bc7eSAndroid Build Coastguard Worker# % tools/jeprof --list=IBF_CheckDocid "program" "profile"
60*1208bc7eSAndroid Build Coastguard Worker#   Generates disassembly listing of all routines with at least one
61*1208bc7eSAndroid Build Coastguard Worker#   sample that match the --list=<regexp> pattern.  The listing is
62*1208bc7eSAndroid Build Coastguard Worker#   annotated with the flat and cumulative sample counts at each line.
63*1208bc7eSAndroid Build Coastguard Worker#
64*1208bc7eSAndroid Build Coastguard Worker# % tools/jeprof --disasm=IBF_CheckDocid "program" "profile"
65*1208bc7eSAndroid Build Coastguard Worker#   Generates disassembly listing of all routines with at least one
66*1208bc7eSAndroid Build Coastguard Worker#   sample that match the --disasm=<regexp> pattern.  The listing is
67*1208bc7eSAndroid Build Coastguard Worker#   annotated with the flat and cumulative sample counts at each PC value.
68*1208bc7eSAndroid Build Coastguard Worker#
69*1208bc7eSAndroid Build Coastguard Worker# TODO: Use color to indicate files?
70*1208bc7eSAndroid Build Coastguard Worker
71*1208bc7eSAndroid Build Coastguard Workeruse strict;
72*1208bc7eSAndroid Build Coastguard Workeruse warnings;
73*1208bc7eSAndroid Build Coastguard Workeruse Getopt::Long;
74*1208bc7eSAndroid Build Coastguard Workeruse Cwd;
75*1208bc7eSAndroid Build Coastguard Worker
76*1208bc7eSAndroid Build Coastguard Workermy $JEPROF_VERSION = "@jemalloc_version@";
77*1208bc7eSAndroid Build Coastguard Workermy $PPROF_VERSION = "2.0";
78*1208bc7eSAndroid Build Coastguard Worker
79*1208bc7eSAndroid Build Coastguard Worker# These are the object tools we use which can come from a
80*1208bc7eSAndroid Build Coastguard Worker# user-specified location using --tools, from the JEPROF_TOOLS
81*1208bc7eSAndroid Build Coastguard Worker# environment variable, or from the environment.
82*1208bc7eSAndroid Build Coastguard Workermy %obj_tool_map = (
83*1208bc7eSAndroid Build Coastguard Worker  "objdump" => "objdump",
84*1208bc7eSAndroid Build Coastguard Worker  "nm" => "nm",
85*1208bc7eSAndroid Build Coastguard Worker  "addr2line" => "addr2line",
86*1208bc7eSAndroid Build Coastguard Worker  "c++filt" => "c++filt",
87*1208bc7eSAndroid Build Coastguard Worker  ## ConfigureObjTools may add architecture-specific entries:
88*1208bc7eSAndroid Build Coastguard Worker  #"nm_pdb" => "nm-pdb",       # for reading windows (PDB-format) executables
89*1208bc7eSAndroid Build Coastguard Worker  #"addr2line_pdb" => "addr2line-pdb",                                # ditto
90*1208bc7eSAndroid Build Coastguard Worker  #"otool" => "otool",         # equivalent of objdump on OS X
91*1208bc7eSAndroid Build Coastguard Worker);
92*1208bc7eSAndroid Build Coastguard Worker# NOTE: these are lists, so you can put in commandline flags if you want.
93*1208bc7eSAndroid Build Coastguard Workermy @DOT = ("dot");          # leave non-absolute, since it may be in /usr/local
94*1208bc7eSAndroid Build Coastguard Workermy @GV = ("gv");
95*1208bc7eSAndroid Build Coastguard Workermy @EVINCE = ("evince");    # could also be xpdf or perhaps acroread
96*1208bc7eSAndroid Build Coastguard Workermy @KCACHEGRIND = ("kcachegrind");
97*1208bc7eSAndroid Build Coastguard Workermy @PS2PDF = ("ps2pdf");
98*1208bc7eSAndroid Build Coastguard Worker# These are used for dynamic profiles
99*1208bc7eSAndroid Build Coastguard Workermy @URL_FETCHER = ("curl", "-s", "--fail");
100*1208bc7eSAndroid Build Coastguard Worker
101*1208bc7eSAndroid Build Coastguard Worker# These are the web pages that servers need to support for dynamic profiles
102*1208bc7eSAndroid Build Coastguard Workermy $HEAP_PAGE = "/pprof/heap";
103*1208bc7eSAndroid Build Coastguard Workermy $PROFILE_PAGE = "/pprof/profile";   # must support cgi-param "?seconds=#"
104*1208bc7eSAndroid Build Coastguard Workermy $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param
105*1208bc7eSAndroid Build Coastguard Worker                                                # ?seconds=#&event=x&period=n
106*1208bc7eSAndroid Build Coastguard Workermy $GROWTH_PAGE = "/pprof/growth";
107*1208bc7eSAndroid Build Coastguard Workermy $CONTENTION_PAGE = "/pprof/contention";
108*1208bc7eSAndroid Build Coastguard Workermy $WALL_PAGE = "/pprof/wall(?:\\?.*)?";  # accepts options like namefilter
109*1208bc7eSAndroid Build Coastguard Workermy $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?";
110*1208bc7eSAndroid Build Coastguard Workermy $CENSUSPROFILE_PAGE = "/pprof/censusprofile(?:\\?.*)?"; # must support cgi-param
111*1208bc7eSAndroid Build Coastguard Worker                                                       # "?seconds=#",
112*1208bc7eSAndroid Build Coastguard Worker                                                       # "?tags_regexp=#" and
113*1208bc7eSAndroid Build Coastguard Worker                                                       # "?type=#".
114*1208bc7eSAndroid Build Coastguard Workermy $SYMBOL_PAGE = "/pprof/symbol";     # must support symbol lookup via POST
115*1208bc7eSAndroid Build Coastguard Workermy $PROGRAM_NAME_PAGE = "/pprof/cmdline";
116*1208bc7eSAndroid Build Coastguard Worker
117*1208bc7eSAndroid Build Coastguard Worker# These are the web pages that can be named on the command line.
118*1208bc7eSAndroid Build Coastguard Worker# All the alternatives must begin with /.
119*1208bc7eSAndroid Build Coastguard Workermy $PROFILES = "($HEAP_PAGE|$PROFILE_PAGE|$PMUPROFILE_PAGE|" .
120*1208bc7eSAndroid Build Coastguard Worker               "$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|" .
121*1208bc7eSAndroid Build Coastguard Worker               "$FILTEREDPROFILE_PAGE|$CENSUSPROFILE_PAGE)";
122*1208bc7eSAndroid Build Coastguard Worker
123*1208bc7eSAndroid Build Coastguard Worker# default binary name
124*1208bc7eSAndroid Build Coastguard Workermy $UNKNOWN_BINARY = "(unknown)";
125*1208bc7eSAndroid Build Coastguard Worker
126*1208bc7eSAndroid Build Coastguard Worker# There is a pervasive dependency on the length (in hex characters,
127*1208bc7eSAndroid Build Coastguard Worker# i.e., nibbles) of an address, distinguishing between 32-bit and
128*1208bc7eSAndroid Build Coastguard Worker# 64-bit profiles.  To err on the safe size, default to 64-bit here:
129*1208bc7eSAndroid Build Coastguard Workermy $address_length = 16;
130*1208bc7eSAndroid Build Coastguard Worker
131*1208bc7eSAndroid Build Coastguard Workermy $dev_null = "/dev/null";
132*1208bc7eSAndroid Build Coastguard Workerif (! -e $dev_null && $^O =~ /MSWin/) {    # $^O is the OS perl was built for
133*1208bc7eSAndroid Build Coastguard Worker  $dev_null = "nul";
134*1208bc7eSAndroid Build Coastguard Worker}
135*1208bc7eSAndroid Build Coastguard Worker
136*1208bc7eSAndroid Build Coastguard Worker# A list of paths to search for shared object files
137*1208bc7eSAndroid Build Coastguard Workermy @prefix_list = ();
138*1208bc7eSAndroid Build Coastguard Worker
139*1208bc7eSAndroid Build Coastguard Worker# Special routine name that should not have any symbols.
140*1208bc7eSAndroid Build Coastguard Worker# Used as separator to parse "addr2line -i" output.
141*1208bc7eSAndroid Build Coastguard Workermy $sep_symbol = '_fini';
142*1208bc7eSAndroid Build Coastguard Workermy $sep_address = undef;
143*1208bc7eSAndroid Build Coastguard Worker
144*1208bc7eSAndroid Build Coastguard Worker##### Argument parsing #####
145*1208bc7eSAndroid Build Coastguard Worker
146*1208bc7eSAndroid Build Coastguard Workersub usage_string {
147*1208bc7eSAndroid Build Coastguard Worker  return <<EOF;
148*1208bc7eSAndroid Build Coastguard WorkerUsage:
149*1208bc7eSAndroid Build Coastguard Workerjeprof [options] <program> <profiles>
150*1208bc7eSAndroid Build Coastguard Worker   <profiles> is a space separated list of profile names.
151*1208bc7eSAndroid Build Coastguard Workerjeprof [options] <symbolized-profiles>
152*1208bc7eSAndroid Build Coastguard Worker   <symbolized-profiles> is a list of profile files where each file contains
153*1208bc7eSAndroid Build Coastguard Worker   the necessary symbol mappings  as well as profile data (likely generated
154*1208bc7eSAndroid Build Coastguard Worker   with --raw).
155*1208bc7eSAndroid Build Coastguard Workerjeprof [options] <profile>
156*1208bc7eSAndroid Build Coastguard Worker   <profile> is a remote form.  Symbols are obtained from host:port$SYMBOL_PAGE
157*1208bc7eSAndroid Build Coastguard Worker
158*1208bc7eSAndroid Build Coastguard Worker   Each name can be:
159*1208bc7eSAndroid Build Coastguard Worker   /path/to/profile        - a path to a profile file
160*1208bc7eSAndroid Build Coastguard Worker   host:port[/<service>]   - a location of a service to get profile from
161*1208bc7eSAndroid Build Coastguard Worker
162*1208bc7eSAndroid Build Coastguard Worker   The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
163*1208bc7eSAndroid Build Coastguard Worker                         $GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
164*1208bc7eSAndroid Build Coastguard Worker                         $CENSUSPROFILE_PAGE, or /pprof/filteredprofile.
165*1208bc7eSAndroid Build Coastguard Worker   For instance:
166*1208bc7eSAndroid Build Coastguard Worker     jeprof http://myserver.com:80$HEAP_PAGE
167*1208bc7eSAndroid Build Coastguard Worker   If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
168*1208bc7eSAndroid Build Coastguard Workerjeprof --symbols <program>
169*1208bc7eSAndroid Build Coastguard Worker   Maps addresses to symbol names.  In this mode, stdin should be a
170*1208bc7eSAndroid Build Coastguard Worker   list of library mappings, in the same format as is found in the heap-
171*1208bc7eSAndroid Build Coastguard Worker   and cpu-profile files (this loosely matches that of /proc/self/maps
172*1208bc7eSAndroid Build Coastguard Worker   on linux), followed by a list of hex addresses to map, one per line.
173*1208bc7eSAndroid Build Coastguard Worker
174*1208bc7eSAndroid Build Coastguard Worker   For more help with querying remote servers, including how to add the
175*1208bc7eSAndroid Build Coastguard Worker   necessary server-side support code, see this filename (or one like it):
176*1208bc7eSAndroid Build Coastguard Worker
177*1208bc7eSAndroid Build Coastguard Worker   /usr/doc/gperftools-$PPROF_VERSION/pprof_remote_servers.html
178*1208bc7eSAndroid Build Coastguard Worker
179*1208bc7eSAndroid Build Coastguard WorkerOptions:
180*1208bc7eSAndroid Build Coastguard Worker   --cum               Sort by cumulative data
181*1208bc7eSAndroid Build Coastguard Worker   --base=<base>       Subtract <base> from <profile> before display
182*1208bc7eSAndroid Build Coastguard Worker   --interactive       Run in interactive mode (interactive "help" gives help) [default]
183*1208bc7eSAndroid Build Coastguard Worker   --seconds=<n>       Length of time for dynamic profiles [default=30 secs]
184*1208bc7eSAndroid Build Coastguard Worker   --add_lib=<file>    Read additional symbols and line info from the given library
185*1208bc7eSAndroid Build Coastguard Worker   --lib_prefix=<dir>  Comma separated list of library path prefixes
186*1208bc7eSAndroid Build Coastguard Worker
187*1208bc7eSAndroid Build Coastguard WorkerReporting Granularity:
188*1208bc7eSAndroid Build Coastguard Worker   --addresses         Report at address level
189*1208bc7eSAndroid Build Coastguard Worker   --lines             Report at source line level
190*1208bc7eSAndroid Build Coastguard Worker   --functions         Report at function level [default]
191*1208bc7eSAndroid Build Coastguard Worker   --files             Report at source file level
192*1208bc7eSAndroid Build Coastguard Worker
193*1208bc7eSAndroid Build Coastguard WorkerOutput type:
194*1208bc7eSAndroid Build Coastguard Worker   --text              Generate text report
195*1208bc7eSAndroid Build Coastguard Worker   --callgrind         Generate callgrind format to stdout
196*1208bc7eSAndroid Build Coastguard Worker   --gv                Generate Postscript and display
197*1208bc7eSAndroid Build Coastguard Worker   --evince            Generate PDF and display
198*1208bc7eSAndroid Build Coastguard Worker   --web               Generate SVG and display
199*1208bc7eSAndroid Build Coastguard Worker   --list=<regexp>     Generate source listing of matching routines
200*1208bc7eSAndroid Build Coastguard Worker   --disasm=<regexp>   Generate disassembly of matching routines
201*1208bc7eSAndroid Build Coastguard Worker   --symbols           Print demangled symbol names found at given addresses
202*1208bc7eSAndroid Build Coastguard Worker   --dot               Generate DOT file to stdout
203*1208bc7eSAndroid Build Coastguard Worker   --ps                Generate Postcript to stdout
204*1208bc7eSAndroid Build Coastguard Worker   --pdf               Generate PDF to stdout
205*1208bc7eSAndroid Build Coastguard Worker   --svg               Generate SVG to stdout
206*1208bc7eSAndroid Build Coastguard Worker   --gif               Generate GIF to stdout
207*1208bc7eSAndroid Build Coastguard Worker   --raw               Generate symbolized jeprof data (useful with remote fetch)
208*1208bc7eSAndroid Build Coastguard Worker
209*1208bc7eSAndroid Build Coastguard WorkerHeap-Profile Options:
210*1208bc7eSAndroid Build Coastguard Worker   --inuse_space       Display in-use (mega)bytes [default]
211*1208bc7eSAndroid Build Coastguard Worker   --inuse_objects     Display in-use objects
212*1208bc7eSAndroid Build Coastguard Worker   --alloc_space       Display allocated (mega)bytes
213*1208bc7eSAndroid Build Coastguard Worker   --alloc_objects     Display allocated objects
214*1208bc7eSAndroid Build Coastguard Worker   --show_bytes        Display space in bytes
215*1208bc7eSAndroid Build Coastguard Worker   --drop_negative     Ignore negative differences
216*1208bc7eSAndroid Build Coastguard Worker
217*1208bc7eSAndroid Build Coastguard WorkerContention-profile options:
218*1208bc7eSAndroid Build Coastguard Worker   --total_delay       Display total delay at each region [default]
219*1208bc7eSAndroid Build Coastguard Worker   --contentions       Display number of delays at each region
220*1208bc7eSAndroid Build Coastguard Worker   --mean_delay        Display mean delay at each region
221*1208bc7eSAndroid Build Coastguard Worker
222*1208bc7eSAndroid Build Coastguard WorkerCall-graph Options:
223*1208bc7eSAndroid Build Coastguard Worker   --nodecount=<n>     Show at most so many nodes [default=80]
224*1208bc7eSAndroid Build Coastguard Worker   --nodefraction=<f>  Hide nodes below <f>*total [default=.005]
225*1208bc7eSAndroid Build Coastguard Worker   --edgefraction=<f>  Hide edges below <f>*total [default=.001]
226*1208bc7eSAndroid Build Coastguard Worker   --maxdegree=<n>     Max incoming/outgoing edges per node [default=8]
227*1208bc7eSAndroid Build Coastguard Worker   --focus=<regexp>    Focus on backtraces with nodes matching <regexp>
228*1208bc7eSAndroid Build Coastguard Worker   --thread=<n>        Show profile for thread <n>
229*1208bc7eSAndroid Build Coastguard Worker   --ignore=<regexp>   Ignore backtraces with nodes matching <regexp>
230*1208bc7eSAndroid Build Coastguard Worker   --scale=<n>         Set GV scaling [default=0]
231*1208bc7eSAndroid Build Coastguard Worker   --heapcheck         Make nodes with non-0 object counts
232*1208bc7eSAndroid Build Coastguard Worker                       (i.e. direct leak generators) more visible
233*1208bc7eSAndroid Build Coastguard Worker   --retain=<regexp>   Retain only nodes that match <regexp>
234*1208bc7eSAndroid Build Coastguard Worker   --exclude=<regexp>  Exclude all nodes that match <regexp>
235*1208bc7eSAndroid Build Coastguard Worker
236*1208bc7eSAndroid Build Coastguard WorkerMiscellaneous:
237*1208bc7eSAndroid Build Coastguard Worker   --tools=<prefix or binary:fullpath>[,...]   \$PATH for object tool pathnames
238*1208bc7eSAndroid Build Coastguard Worker   --test              Run unit tests
239*1208bc7eSAndroid Build Coastguard Worker   --help              This message
240*1208bc7eSAndroid Build Coastguard Worker   --version           Version information
241*1208bc7eSAndroid Build Coastguard Worker
242*1208bc7eSAndroid Build Coastguard WorkerEnvironment Variables:
243*1208bc7eSAndroid Build Coastguard Worker   JEPROF_TMPDIR        Profiles directory. Defaults to \$HOME/jeprof
244*1208bc7eSAndroid Build Coastguard Worker   JEPROF_TOOLS         Prefix for object tools pathnames
245*1208bc7eSAndroid Build Coastguard Worker
246*1208bc7eSAndroid Build Coastguard WorkerExamples:
247*1208bc7eSAndroid Build Coastguard Worker
248*1208bc7eSAndroid Build Coastguard Workerjeprof /bin/ls ls.prof
249*1208bc7eSAndroid Build Coastguard Worker                       Enters "interactive" mode
250*1208bc7eSAndroid Build Coastguard Workerjeprof --text /bin/ls ls.prof
251*1208bc7eSAndroid Build Coastguard Worker                       Outputs one line per procedure
252*1208bc7eSAndroid Build Coastguard Workerjeprof --web /bin/ls ls.prof
253*1208bc7eSAndroid Build Coastguard Worker                       Displays annotated call-graph in web browser
254*1208bc7eSAndroid Build Coastguard Workerjeprof --gv /bin/ls ls.prof
255*1208bc7eSAndroid Build Coastguard Worker                       Displays annotated call-graph via 'gv'
256*1208bc7eSAndroid Build Coastguard Workerjeprof --gv --focus=Mutex /bin/ls ls.prof
257*1208bc7eSAndroid Build Coastguard Worker                       Restricts to code paths including a .*Mutex.* entry
258*1208bc7eSAndroid Build Coastguard Workerjeprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof
259*1208bc7eSAndroid Build Coastguard Worker                       Code paths including Mutex but not string
260*1208bc7eSAndroid Build Coastguard Workerjeprof --list=getdir /bin/ls ls.prof
261*1208bc7eSAndroid Build Coastguard Worker                       (Per-line) annotated source listing for getdir()
262*1208bc7eSAndroid Build Coastguard Workerjeprof --disasm=getdir /bin/ls ls.prof
263*1208bc7eSAndroid Build Coastguard Worker                       (Per-PC) annotated disassembly for getdir()
264*1208bc7eSAndroid Build Coastguard Worker
265*1208bc7eSAndroid Build Coastguard Workerjeprof http://localhost:1234/
266*1208bc7eSAndroid Build Coastguard Worker                       Enters "interactive" mode
267*1208bc7eSAndroid Build Coastguard Workerjeprof --text localhost:1234
268*1208bc7eSAndroid Build Coastguard Worker                       Outputs one line per procedure for localhost:1234
269*1208bc7eSAndroid Build Coastguard Workerjeprof --raw localhost:1234 > ./local.raw
270*1208bc7eSAndroid Build Coastguard Workerjeprof --text ./local.raw
271*1208bc7eSAndroid Build Coastguard Worker                       Fetches a remote profile for later analysis and then
272*1208bc7eSAndroid Build Coastguard Worker                       analyzes it in text mode.
273*1208bc7eSAndroid Build Coastguard WorkerEOF
274*1208bc7eSAndroid Build Coastguard Worker}
275*1208bc7eSAndroid Build Coastguard Worker
276*1208bc7eSAndroid Build Coastguard Workersub version_string {
277*1208bc7eSAndroid Build Coastguard Worker  return <<EOF
278*1208bc7eSAndroid Build Coastguard Workerjeprof (part of jemalloc $JEPROF_VERSION)
279*1208bc7eSAndroid Build Coastguard Workerbased on pprof (part of gperftools $PPROF_VERSION)
280*1208bc7eSAndroid Build Coastguard Worker
281*1208bc7eSAndroid Build Coastguard WorkerCopyright 1998-2007 Google Inc.
282*1208bc7eSAndroid Build Coastguard Worker
283*1208bc7eSAndroid Build Coastguard WorkerThis is BSD licensed software; see the source for copying conditions
284*1208bc7eSAndroid Build Coastguard Workerand license information.
285*1208bc7eSAndroid Build Coastguard WorkerThere is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
286*1208bc7eSAndroid Build Coastguard WorkerPARTICULAR PURPOSE.
287*1208bc7eSAndroid Build Coastguard WorkerEOF
288*1208bc7eSAndroid Build Coastguard Worker}
289*1208bc7eSAndroid Build Coastguard Worker
290*1208bc7eSAndroid Build Coastguard Workersub usage {
291*1208bc7eSAndroid Build Coastguard Worker  my $msg = shift;
292*1208bc7eSAndroid Build Coastguard Worker  print STDERR "$msg\n\n";
293*1208bc7eSAndroid Build Coastguard Worker  print STDERR usage_string();
294*1208bc7eSAndroid Build Coastguard Worker  print STDERR "\nFATAL ERROR: $msg\n";    # just as a reminder
295*1208bc7eSAndroid Build Coastguard Worker  exit(1);
296*1208bc7eSAndroid Build Coastguard Worker}
297*1208bc7eSAndroid Build Coastguard Worker
298*1208bc7eSAndroid Build Coastguard Workersub Init() {
299*1208bc7eSAndroid Build Coastguard Worker  # Setup tmp-file name and handler to clean it up.
300*1208bc7eSAndroid Build Coastguard Worker  # We do this in the very beginning so that we can use
301*1208bc7eSAndroid Build Coastguard Worker  # error() and cleanup() function anytime here after.
302*1208bc7eSAndroid Build Coastguard Worker  $main::tmpfile_sym = "/tmp/jeprof$$.sym";
303*1208bc7eSAndroid Build Coastguard Worker  $main::tmpfile_ps = "/tmp/jeprof$$";
304*1208bc7eSAndroid Build Coastguard Worker  $main::next_tmpfile = 0;
305*1208bc7eSAndroid Build Coastguard Worker  $SIG{'INT'} = \&sighandler;
306*1208bc7eSAndroid Build Coastguard Worker
307*1208bc7eSAndroid Build Coastguard Worker  # Cache from filename/linenumber to source code
308*1208bc7eSAndroid Build Coastguard Worker  $main::source_cache = ();
309*1208bc7eSAndroid Build Coastguard Worker
310*1208bc7eSAndroid Build Coastguard Worker  $main::opt_help = 0;
311*1208bc7eSAndroid Build Coastguard Worker  $main::opt_version = 0;
312*1208bc7eSAndroid Build Coastguard Worker
313*1208bc7eSAndroid Build Coastguard Worker  $main::opt_cum = 0;
314*1208bc7eSAndroid Build Coastguard Worker  $main::opt_base = '';
315*1208bc7eSAndroid Build Coastguard Worker  $main::opt_addresses = 0;
316*1208bc7eSAndroid Build Coastguard Worker  $main::opt_lines = 0;
317*1208bc7eSAndroid Build Coastguard Worker  $main::opt_functions = 0;
318*1208bc7eSAndroid Build Coastguard Worker  $main::opt_files = 0;
319*1208bc7eSAndroid Build Coastguard Worker  $main::opt_lib_prefix = "";
320*1208bc7eSAndroid Build Coastguard Worker
321*1208bc7eSAndroid Build Coastguard Worker  $main::opt_text = 0;
322*1208bc7eSAndroid Build Coastguard Worker  $main::opt_callgrind = 0;
323*1208bc7eSAndroid Build Coastguard Worker  $main::opt_list = "";
324*1208bc7eSAndroid Build Coastguard Worker  $main::opt_disasm = "";
325*1208bc7eSAndroid Build Coastguard Worker  $main::opt_symbols = 0;
326*1208bc7eSAndroid Build Coastguard Worker  $main::opt_gv = 0;
327*1208bc7eSAndroid Build Coastguard Worker  $main::opt_evince = 0;
328*1208bc7eSAndroid Build Coastguard Worker  $main::opt_web = 0;
329*1208bc7eSAndroid Build Coastguard Worker  $main::opt_dot = 0;
330*1208bc7eSAndroid Build Coastguard Worker  $main::opt_ps = 0;
331*1208bc7eSAndroid Build Coastguard Worker  $main::opt_pdf = 0;
332*1208bc7eSAndroid Build Coastguard Worker  $main::opt_gif = 0;
333*1208bc7eSAndroid Build Coastguard Worker  $main::opt_svg = 0;
334*1208bc7eSAndroid Build Coastguard Worker  $main::opt_raw = 0;
335*1208bc7eSAndroid Build Coastguard Worker
336*1208bc7eSAndroid Build Coastguard Worker  $main::opt_nodecount = 80;
337*1208bc7eSAndroid Build Coastguard Worker  $main::opt_nodefraction = 0.005;
338*1208bc7eSAndroid Build Coastguard Worker  $main::opt_edgefraction = 0.001;
339*1208bc7eSAndroid Build Coastguard Worker  $main::opt_maxdegree = 8;
340*1208bc7eSAndroid Build Coastguard Worker  $main::opt_focus = '';
341*1208bc7eSAndroid Build Coastguard Worker  $main::opt_thread = undef;
342*1208bc7eSAndroid Build Coastguard Worker  $main::opt_ignore = '';
343*1208bc7eSAndroid Build Coastguard Worker  $main::opt_scale = 0;
344*1208bc7eSAndroid Build Coastguard Worker  $main::opt_heapcheck = 0;
345*1208bc7eSAndroid Build Coastguard Worker  $main::opt_retain = '';
346*1208bc7eSAndroid Build Coastguard Worker  $main::opt_exclude = '';
347*1208bc7eSAndroid Build Coastguard Worker  $main::opt_seconds = 30;
348*1208bc7eSAndroid Build Coastguard Worker  $main::opt_lib = "";
349*1208bc7eSAndroid Build Coastguard Worker
350*1208bc7eSAndroid Build Coastguard Worker  $main::opt_inuse_space   = 0;
351*1208bc7eSAndroid Build Coastguard Worker  $main::opt_inuse_objects = 0;
352*1208bc7eSAndroid Build Coastguard Worker  $main::opt_alloc_space   = 0;
353*1208bc7eSAndroid Build Coastguard Worker  $main::opt_alloc_objects = 0;
354*1208bc7eSAndroid Build Coastguard Worker  $main::opt_show_bytes    = 0;
355*1208bc7eSAndroid Build Coastguard Worker  $main::opt_drop_negative = 0;
356*1208bc7eSAndroid Build Coastguard Worker  $main::opt_interactive   = 0;
357*1208bc7eSAndroid Build Coastguard Worker
358*1208bc7eSAndroid Build Coastguard Worker  $main::opt_total_delay = 0;
359*1208bc7eSAndroid Build Coastguard Worker  $main::opt_contentions = 0;
360*1208bc7eSAndroid Build Coastguard Worker  $main::opt_mean_delay = 0;
361*1208bc7eSAndroid Build Coastguard Worker
362*1208bc7eSAndroid Build Coastguard Worker  $main::opt_tools   = "";
363*1208bc7eSAndroid Build Coastguard Worker  $main::opt_debug   = 0;
364*1208bc7eSAndroid Build Coastguard Worker  $main::opt_test    = 0;
365*1208bc7eSAndroid Build Coastguard Worker
366*1208bc7eSAndroid Build Coastguard Worker  # These are undocumented flags used only by unittests.
367*1208bc7eSAndroid Build Coastguard Worker  $main::opt_test_stride = 0;
368*1208bc7eSAndroid Build Coastguard Worker
369*1208bc7eSAndroid Build Coastguard Worker  # Are we using $SYMBOL_PAGE?
370*1208bc7eSAndroid Build Coastguard Worker  $main::use_symbol_page = 0;
371*1208bc7eSAndroid Build Coastguard Worker
372*1208bc7eSAndroid Build Coastguard Worker  # Files returned by TempName.
373*1208bc7eSAndroid Build Coastguard Worker  %main::tempnames = ();
374*1208bc7eSAndroid Build Coastguard Worker
375*1208bc7eSAndroid Build Coastguard Worker  # Type of profile we are dealing with
376*1208bc7eSAndroid Build Coastguard Worker  # Supported types:
377*1208bc7eSAndroid Build Coastguard Worker  #     cpu
378*1208bc7eSAndroid Build Coastguard Worker  #     heap
379*1208bc7eSAndroid Build Coastguard Worker  #     growth
380*1208bc7eSAndroid Build Coastguard Worker  #     contention
381*1208bc7eSAndroid Build Coastguard Worker  $main::profile_type = '';     # Empty type means "unknown"
382*1208bc7eSAndroid Build Coastguard Worker
383*1208bc7eSAndroid Build Coastguard Worker  GetOptions("help!"          => \$main::opt_help,
384*1208bc7eSAndroid Build Coastguard Worker             "version!"       => \$main::opt_version,
385*1208bc7eSAndroid Build Coastguard Worker             "cum!"           => \$main::opt_cum,
386*1208bc7eSAndroid Build Coastguard Worker             "base=s"         => \$main::opt_base,
387*1208bc7eSAndroid Build Coastguard Worker             "seconds=i"      => \$main::opt_seconds,
388*1208bc7eSAndroid Build Coastguard Worker             "add_lib=s"      => \$main::opt_lib,
389*1208bc7eSAndroid Build Coastguard Worker             "lib_prefix=s"   => \$main::opt_lib_prefix,
390*1208bc7eSAndroid Build Coastguard Worker             "functions!"     => \$main::opt_functions,
391*1208bc7eSAndroid Build Coastguard Worker             "lines!"         => \$main::opt_lines,
392*1208bc7eSAndroid Build Coastguard Worker             "addresses!"     => \$main::opt_addresses,
393*1208bc7eSAndroid Build Coastguard Worker             "files!"         => \$main::opt_files,
394*1208bc7eSAndroid Build Coastguard Worker             "text!"          => \$main::opt_text,
395*1208bc7eSAndroid Build Coastguard Worker             "callgrind!"     => \$main::opt_callgrind,
396*1208bc7eSAndroid Build Coastguard Worker             "list=s"         => \$main::opt_list,
397*1208bc7eSAndroid Build Coastguard Worker             "disasm=s"       => \$main::opt_disasm,
398*1208bc7eSAndroid Build Coastguard Worker             "symbols!"       => \$main::opt_symbols,
399*1208bc7eSAndroid Build Coastguard Worker             "gv!"            => \$main::opt_gv,
400*1208bc7eSAndroid Build Coastguard Worker             "evince!"        => \$main::opt_evince,
401*1208bc7eSAndroid Build Coastguard Worker             "web!"           => \$main::opt_web,
402*1208bc7eSAndroid Build Coastguard Worker             "dot!"           => \$main::opt_dot,
403*1208bc7eSAndroid Build Coastguard Worker             "ps!"            => \$main::opt_ps,
404*1208bc7eSAndroid Build Coastguard Worker             "pdf!"           => \$main::opt_pdf,
405*1208bc7eSAndroid Build Coastguard Worker             "svg!"           => \$main::opt_svg,
406*1208bc7eSAndroid Build Coastguard Worker             "gif!"           => \$main::opt_gif,
407*1208bc7eSAndroid Build Coastguard Worker             "raw!"           => \$main::opt_raw,
408*1208bc7eSAndroid Build Coastguard Worker             "interactive!"   => \$main::opt_interactive,
409*1208bc7eSAndroid Build Coastguard Worker             "nodecount=i"    => \$main::opt_nodecount,
410*1208bc7eSAndroid Build Coastguard Worker             "nodefraction=f" => \$main::opt_nodefraction,
411*1208bc7eSAndroid Build Coastguard Worker             "edgefraction=f" => \$main::opt_edgefraction,
412*1208bc7eSAndroid Build Coastguard Worker             "maxdegree=i"    => \$main::opt_maxdegree,
413*1208bc7eSAndroid Build Coastguard Worker             "focus=s"        => \$main::opt_focus,
414*1208bc7eSAndroid Build Coastguard Worker             "thread=s"       => \$main::opt_thread,
415*1208bc7eSAndroid Build Coastguard Worker             "ignore=s"       => \$main::opt_ignore,
416*1208bc7eSAndroid Build Coastguard Worker             "scale=i"        => \$main::opt_scale,
417*1208bc7eSAndroid Build Coastguard Worker             "heapcheck"      => \$main::opt_heapcheck,
418*1208bc7eSAndroid Build Coastguard Worker             "retain=s"       => \$main::opt_retain,
419*1208bc7eSAndroid Build Coastguard Worker             "exclude=s"      => \$main::opt_exclude,
420*1208bc7eSAndroid Build Coastguard Worker             "inuse_space!"   => \$main::opt_inuse_space,
421*1208bc7eSAndroid Build Coastguard Worker             "inuse_objects!" => \$main::opt_inuse_objects,
422*1208bc7eSAndroid Build Coastguard Worker             "alloc_space!"   => \$main::opt_alloc_space,
423*1208bc7eSAndroid Build Coastguard Worker             "alloc_objects!" => \$main::opt_alloc_objects,
424*1208bc7eSAndroid Build Coastguard Worker             "show_bytes!"    => \$main::opt_show_bytes,
425*1208bc7eSAndroid Build Coastguard Worker             "drop_negative!" => \$main::opt_drop_negative,
426*1208bc7eSAndroid Build Coastguard Worker             "total_delay!"   => \$main::opt_total_delay,
427*1208bc7eSAndroid Build Coastguard Worker             "contentions!"   => \$main::opt_contentions,
428*1208bc7eSAndroid Build Coastguard Worker             "mean_delay!"    => \$main::opt_mean_delay,
429*1208bc7eSAndroid Build Coastguard Worker             "tools=s"        => \$main::opt_tools,
430*1208bc7eSAndroid Build Coastguard Worker             "test!"          => \$main::opt_test,
431*1208bc7eSAndroid Build Coastguard Worker             "debug!"         => \$main::opt_debug,
432*1208bc7eSAndroid Build Coastguard Worker             # Undocumented flags used only by unittests:
433*1208bc7eSAndroid Build Coastguard Worker             "test_stride=i"  => \$main::opt_test_stride,
434*1208bc7eSAndroid Build Coastguard Worker      ) || usage("Invalid option(s)");
435*1208bc7eSAndroid Build Coastguard Worker
436*1208bc7eSAndroid Build Coastguard Worker  # Deal with the standard --help and --version
437*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_help) {
438*1208bc7eSAndroid Build Coastguard Worker    print usage_string();
439*1208bc7eSAndroid Build Coastguard Worker    exit(0);
440*1208bc7eSAndroid Build Coastguard Worker  }
441*1208bc7eSAndroid Build Coastguard Worker
442*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_version) {
443*1208bc7eSAndroid Build Coastguard Worker    print version_string();
444*1208bc7eSAndroid Build Coastguard Worker    exit(0);
445*1208bc7eSAndroid Build Coastguard Worker  }
446*1208bc7eSAndroid Build Coastguard Worker
447*1208bc7eSAndroid Build Coastguard Worker  # Disassembly/listing/symbols mode requires address-level info
448*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) {
449*1208bc7eSAndroid Build Coastguard Worker    $main::opt_functions = 0;
450*1208bc7eSAndroid Build Coastguard Worker    $main::opt_lines = 0;
451*1208bc7eSAndroid Build Coastguard Worker    $main::opt_addresses = 1;
452*1208bc7eSAndroid Build Coastguard Worker    $main::opt_files = 0;
453*1208bc7eSAndroid Build Coastguard Worker  }
454*1208bc7eSAndroid Build Coastguard Worker
455*1208bc7eSAndroid Build Coastguard Worker  # Check heap-profiling flags
456*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_inuse_space +
457*1208bc7eSAndroid Build Coastguard Worker      $main::opt_inuse_objects +
458*1208bc7eSAndroid Build Coastguard Worker      $main::opt_alloc_space +
459*1208bc7eSAndroid Build Coastguard Worker      $main::opt_alloc_objects > 1) {
460*1208bc7eSAndroid Build Coastguard Worker    usage("Specify at most on of --inuse/--alloc options");
461*1208bc7eSAndroid Build Coastguard Worker  }
462*1208bc7eSAndroid Build Coastguard Worker
463*1208bc7eSAndroid Build Coastguard Worker  # Check output granularities
464*1208bc7eSAndroid Build Coastguard Worker  my $grains =
465*1208bc7eSAndroid Build Coastguard Worker      $main::opt_functions +
466*1208bc7eSAndroid Build Coastguard Worker      $main::opt_lines +
467*1208bc7eSAndroid Build Coastguard Worker      $main::opt_addresses +
468*1208bc7eSAndroid Build Coastguard Worker      $main::opt_files +
469*1208bc7eSAndroid Build Coastguard Worker      0;
470*1208bc7eSAndroid Build Coastguard Worker  if ($grains > 1) {
471*1208bc7eSAndroid Build Coastguard Worker    usage("Only specify one output granularity option");
472*1208bc7eSAndroid Build Coastguard Worker  }
473*1208bc7eSAndroid Build Coastguard Worker  if ($grains == 0) {
474*1208bc7eSAndroid Build Coastguard Worker    $main::opt_functions = 1;
475*1208bc7eSAndroid Build Coastguard Worker  }
476*1208bc7eSAndroid Build Coastguard Worker
477*1208bc7eSAndroid Build Coastguard Worker  # Check output modes
478*1208bc7eSAndroid Build Coastguard Worker  my $modes =
479*1208bc7eSAndroid Build Coastguard Worker      $main::opt_text +
480*1208bc7eSAndroid Build Coastguard Worker      $main::opt_callgrind +
481*1208bc7eSAndroid Build Coastguard Worker      ($main::opt_list eq '' ? 0 : 1) +
482*1208bc7eSAndroid Build Coastguard Worker      ($main::opt_disasm eq '' ? 0 : 1) +
483*1208bc7eSAndroid Build Coastguard Worker      ($main::opt_symbols == 0 ? 0 : 1) +
484*1208bc7eSAndroid Build Coastguard Worker      $main::opt_gv +
485*1208bc7eSAndroid Build Coastguard Worker      $main::opt_evince +
486*1208bc7eSAndroid Build Coastguard Worker      $main::opt_web +
487*1208bc7eSAndroid Build Coastguard Worker      $main::opt_dot +
488*1208bc7eSAndroid Build Coastguard Worker      $main::opt_ps +
489*1208bc7eSAndroid Build Coastguard Worker      $main::opt_pdf +
490*1208bc7eSAndroid Build Coastguard Worker      $main::opt_svg +
491*1208bc7eSAndroid Build Coastguard Worker      $main::opt_gif +
492*1208bc7eSAndroid Build Coastguard Worker      $main::opt_raw +
493*1208bc7eSAndroid Build Coastguard Worker      $main::opt_interactive +
494*1208bc7eSAndroid Build Coastguard Worker      0;
495*1208bc7eSAndroid Build Coastguard Worker  if ($modes > 1) {
496*1208bc7eSAndroid Build Coastguard Worker    usage("Only specify one output mode");
497*1208bc7eSAndroid Build Coastguard Worker  }
498*1208bc7eSAndroid Build Coastguard Worker  if ($modes == 0) {
499*1208bc7eSAndroid Build Coastguard Worker    if (-t STDOUT) {  # If STDOUT is a tty, activate interactive mode
500*1208bc7eSAndroid Build Coastguard Worker      $main::opt_interactive = 1;
501*1208bc7eSAndroid Build Coastguard Worker    } else {
502*1208bc7eSAndroid Build Coastguard Worker      $main::opt_text = 1;
503*1208bc7eSAndroid Build Coastguard Worker    }
504*1208bc7eSAndroid Build Coastguard Worker  }
505*1208bc7eSAndroid Build Coastguard Worker
506*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_test) {
507*1208bc7eSAndroid Build Coastguard Worker    RunUnitTests();
508*1208bc7eSAndroid Build Coastguard Worker    # Should not return
509*1208bc7eSAndroid Build Coastguard Worker    exit(1);
510*1208bc7eSAndroid Build Coastguard Worker  }
511*1208bc7eSAndroid Build Coastguard Worker
512*1208bc7eSAndroid Build Coastguard Worker  # Binary name and profile arguments list
513*1208bc7eSAndroid Build Coastguard Worker  $main::prog = "";
514*1208bc7eSAndroid Build Coastguard Worker  @main::pfile_args = ();
515*1208bc7eSAndroid Build Coastguard Worker
516*1208bc7eSAndroid Build Coastguard Worker  # Remote profiling without a binary (using $SYMBOL_PAGE instead)
517*1208bc7eSAndroid Build Coastguard Worker  if (@ARGV > 0) {
518*1208bc7eSAndroid Build Coastguard Worker    if (IsProfileURL($ARGV[0])) {
519*1208bc7eSAndroid Build Coastguard Worker      $main::use_symbol_page = 1;
520*1208bc7eSAndroid Build Coastguard Worker    } elsif (IsSymbolizedProfileFile($ARGV[0])) {
521*1208bc7eSAndroid Build Coastguard Worker      $main::use_symbolized_profile = 1;
522*1208bc7eSAndroid Build Coastguard Worker      $main::prog = $UNKNOWN_BINARY;  # will be set later from the profile file
523*1208bc7eSAndroid Build Coastguard Worker    }
524*1208bc7eSAndroid Build Coastguard Worker  }
525*1208bc7eSAndroid Build Coastguard Worker
526*1208bc7eSAndroid Build Coastguard Worker  if ($main::use_symbol_page || $main::use_symbolized_profile) {
527*1208bc7eSAndroid Build Coastguard Worker    # We don't need a binary!
528*1208bc7eSAndroid Build Coastguard Worker    my %disabled = ('--lines' => $main::opt_lines,
529*1208bc7eSAndroid Build Coastguard Worker                    '--disasm' => $main::opt_disasm);
530*1208bc7eSAndroid Build Coastguard Worker    for my $option (keys %disabled) {
531*1208bc7eSAndroid Build Coastguard Worker      usage("$option cannot be used without a binary") if $disabled{$option};
532*1208bc7eSAndroid Build Coastguard Worker    }
533*1208bc7eSAndroid Build Coastguard Worker    # Set $main::prog later...
534*1208bc7eSAndroid Build Coastguard Worker    scalar(@ARGV) || usage("Did not specify profile file");
535*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_symbols) {
536*1208bc7eSAndroid Build Coastguard Worker    # --symbols needs a binary-name (to run nm on, etc) but not profiles
537*1208bc7eSAndroid Build Coastguard Worker    $main::prog = shift(@ARGV) || usage("Did not specify program");
538*1208bc7eSAndroid Build Coastguard Worker  } else {
539*1208bc7eSAndroid Build Coastguard Worker    $main::prog = shift(@ARGV) || usage("Did not specify program");
540*1208bc7eSAndroid Build Coastguard Worker    scalar(@ARGV) || usage("Did not specify profile file");
541*1208bc7eSAndroid Build Coastguard Worker  }
542*1208bc7eSAndroid Build Coastguard Worker
543*1208bc7eSAndroid Build Coastguard Worker  # Parse profile file/location arguments
544*1208bc7eSAndroid Build Coastguard Worker  foreach my $farg (@ARGV) {
545*1208bc7eSAndroid Build Coastguard Worker    if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) {
546*1208bc7eSAndroid Build Coastguard Worker      my $machine = $1;
547*1208bc7eSAndroid Build Coastguard Worker      my $num_machines = $2;
548*1208bc7eSAndroid Build Coastguard Worker      my $path = $3;
549*1208bc7eSAndroid Build Coastguard Worker      for (my $i = 0; $i < $num_machines; $i++) {
550*1208bc7eSAndroid Build Coastguard Worker        unshift(@main::pfile_args, "$i.$machine$path");
551*1208bc7eSAndroid Build Coastguard Worker      }
552*1208bc7eSAndroid Build Coastguard Worker    } else {
553*1208bc7eSAndroid Build Coastguard Worker      unshift(@main::pfile_args, $farg);
554*1208bc7eSAndroid Build Coastguard Worker    }
555*1208bc7eSAndroid Build Coastguard Worker  }
556*1208bc7eSAndroid Build Coastguard Worker
557*1208bc7eSAndroid Build Coastguard Worker  if ($main::use_symbol_page) {
558*1208bc7eSAndroid Build Coastguard Worker    unless (IsProfileURL($main::pfile_args[0])) {
559*1208bc7eSAndroid Build Coastguard Worker      error("The first profile should be a remote form to use $SYMBOL_PAGE\n");
560*1208bc7eSAndroid Build Coastguard Worker    }
561*1208bc7eSAndroid Build Coastguard Worker    CheckSymbolPage();
562*1208bc7eSAndroid Build Coastguard Worker    $main::prog = FetchProgramName();
563*1208bc7eSAndroid Build Coastguard Worker  } elsif (!$main::use_symbolized_profile) {  # may not need objtools!
564*1208bc7eSAndroid Build Coastguard Worker    ConfigureObjTools($main::prog)
565*1208bc7eSAndroid Build Coastguard Worker  }
566*1208bc7eSAndroid Build Coastguard Worker
567*1208bc7eSAndroid Build Coastguard Worker  # Break the opt_lib_prefix into the prefix_list array
568*1208bc7eSAndroid Build Coastguard Worker  @prefix_list = split (',', $main::opt_lib_prefix);
569*1208bc7eSAndroid Build Coastguard Worker
570*1208bc7eSAndroid Build Coastguard Worker  # Remove trailing / from the prefixes, in the list to prevent
571*1208bc7eSAndroid Build Coastguard Worker  # searching things like /my/path//lib/mylib.so
572*1208bc7eSAndroid Build Coastguard Worker  foreach (@prefix_list) {
573*1208bc7eSAndroid Build Coastguard Worker    s|/+$||;
574*1208bc7eSAndroid Build Coastguard Worker  }
575*1208bc7eSAndroid Build Coastguard Worker}
576*1208bc7eSAndroid Build Coastguard Worker
577*1208bc7eSAndroid Build Coastguard Workersub FilterAndPrint {
578*1208bc7eSAndroid Build Coastguard Worker  my ($profile, $symbols, $libs, $thread) = @_;
579*1208bc7eSAndroid Build Coastguard Worker
580*1208bc7eSAndroid Build Coastguard Worker  # Get total data in profile
581*1208bc7eSAndroid Build Coastguard Worker  my $total = TotalProfile($profile);
582*1208bc7eSAndroid Build Coastguard Worker
583*1208bc7eSAndroid Build Coastguard Worker  # Remove uniniteresting stack items
584*1208bc7eSAndroid Build Coastguard Worker  $profile = RemoveUninterestingFrames($symbols, $profile);
585*1208bc7eSAndroid Build Coastguard Worker
586*1208bc7eSAndroid Build Coastguard Worker  # Focus?
587*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_focus ne '') {
588*1208bc7eSAndroid Build Coastguard Worker    $profile = FocusProfile($symbols, $profile, $main::opt_focus);
589*1208bc7eSAndroid Build Coastguard Worker  }
590*1208bc7eSAndroid Build Coastguard Worker
591*1208bc7eSAndroid Build Coastguard Worker  # Ignore?
592*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_ignore ne '') {
593*1208bc7eSAndroid Build Coastguard Worker    $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore);
594*1208bc7eSAndroid Build Coastguard Worker  }
595*1208bc7eSAndroid Build Coastguard Worker
596*1208bc7eSAndroid Build Coastguard Worker  my $calls = ExtractCalls($symbols, $profile);
597*1208bc7eSAndroid Build Coastguard Worker
598*1208bc7eSAndroid Build Coastguard Worker  # Reduce profiles to required output granularity, and also clean
599*1208bc7eSAndroid Build Coastguard Worker  # each stack trace so a given entry exists at most once.
600*1208bc7eSAndroid Build Coastguard Worker  my $reduced = ReduceProfile($symbols, $profile);
601*1208bc7eSAndroid Build Coastguard Worker
602*1208bc7eSAndroid Build Coastguard Worker  # Get derived profiles
603*1208bc7eSAndroid Build Coastguard Worker  my $flat = FlatProfile($reduced);
604*1208bc7eSAndroid Build Coastguard Worker  my $cumulative = CumulativeProfile($reduced);
605*1208bc7eSAndroid Build Coastguard Worker
606*1208bc7eSAndroid Build Coastguard Worker  # Print
607*1208bc7eSAndroid Build Coastguard Worker  if (!$main::opt_interactive) {
608*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_disasm) {
609*1208bc7eSAndroid Build Coastguard Worker      PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm);
610*1208bc7eSAndroid Build Coastguard Worker    } elsif ($main::opt_list) {
611*1208bc7eSAndroid Build Coastguard Worker      PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
612*1208bc7eSAndroid Build Coastguard Worker    } elsif ($main::opt_text) {
613*1208bc7eSAndroid Build Coastguard Worker      # Make sure the output is empty when have nothing to report
614*1208bc7eSAndroid Build Coastguard Worker      # (only matters when --heapcheck is given but we must be
615*1208bc7eSAndroid Build Coastguard Worker      # compatible with old branches that did not pass --heapcheck always):
616*1208bc7eSAndroid Build Coastguard Worker      if ($total != 0) {
617*1208bc7eSAndroid Build Coastguard Worker        printf("Total%s: %s %s\n",
618*1208bc7eSAndroid Build Coastguard Worker               (defined($thread) ? " (t$thread)" : ""),
619*1208bc7eSAndroid Build Coastguard Worker               Unparse($total), Units());
620*1208bc7eSAndroid Build Coastguard Worker      }
621*1208bc7eSAndroid Build Coastguard Worker      PrintText($symbols, $flat, $cumulative, -1);
622*1208bc7eSAndroid Build Coastguard Worker    } elsif ($main::opt_raw) {
623*1208bc7eSAndroid Build Coastguard Worker      PrintSymbolizedProfile($symbols, $profile, $main::prog);
624*1208bc7eSAndroid Build Coastguard Worker    } elsif ($main::opt_callgrind) {
625*1208bc7eSAndroid Build Coastguard Worker      PrintCallgrind($calls);
626*1208bc7eSAndroid Build Coastguard Worker    } else {
627*1208bc7eSAndroid Build Coastguard Worker      if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
628*1208bc7eSAndroid Build Coastguard Worker        if ($main::opt_gv) {
629*1208bc7eSAndroid Build Coastguard Worker          RunGV(TempName($main::next_tmpfile, "ps"), "");
630*1208bc7eSAndroid Build Coastguard Worker        } elsif ($main::opt_evince) {
631*1208bc7eSAndroid Build Coastguard Worker          RunEvince(TempName($main::next_tmpfile, "pdf"), "");
632*1208bc7eSAndroid Build Coastguard Worker        } elsif ($main::opt_web) {
633*1208bc7eSAndroid Build Coastguard Worker          my $tmp = TempName($main::next_tmpfile, "svg");
634*1208bc7eSAndroid Build Coastguard Worker          RunWeb($tmp);
635*1208bc7eSAndroid Build Coastguard Worker          # The command we run might hand the file name off
636*1208bc7eSAndroid Build Coastguard Worker          # to an already running browser instance and then exit.
637*1208bc7eSAndroid Build Coastguard Worker          # Normally, we'd remove $tmp on exit (right now),
638*1208bc7eSAndroid Build Coastguard Worker          # but fork a child to remove $tmp a little later, so that the
639*1208bc7eSAndroid Build Coastguard Worker          # browser has time to load it first.
640*1208bc7eSAndroid Build Coastguard Worker          delete $main::tempnames{$tmp};
641*1208bc7eSAndroid Build Coastguard Worker          if (fork() == 0) {
642*1208bc7eSAndroid Build Coastguard Worker            sleep 5;
643*1208bc7eSAndroid Build Coastguard Worker            unlink($tmp);
644*1208bc7eSAndroid Build Coastguard Worker            exit(0);
645*1208bc7eSAndroid Build Coastguard Worker          }
646*1208bc7eSAndroid Build Coastguard Worker        }
647*1208bc7eSAndroid Build Coastguard Worker      } else {
648*1208bc7eSAndroid Build Coastguard Worker        cleanup();
649*1208bc7eSAndroid Build Coastguard Worker        exit(1);
650*1208bc7eSAndroid Build Coastguard Worker      }
651*1208bc7eSAndroid Build Coastguard Worker    }
652*1208bc7eSAndroid Build Coastguard Worker  } else {
653*1208bc7eSAndroid Build Coastguard Worker    InteractiveMode($profile, $symbols, $libs, $total);
654*1208bc7eSAndroid Build Coastguard Worker  }
655*1208bc7eSAndroid Build Coastguard Worker}
656*1208bc7eSAndroid Build Coastguard Worker
657*1208bc7eSAndroid Build Coastguard Workersub Main() {
658*1208bc7eSAndroid Build Coastguard Worker  Init();
659*1208bc7eSAndroid Build Coastguard Worker  $main::collected_profile = undef;
660*1208bc7eSAndroid Build Coastguard Worker  @main::profile_files = ();
661*1208bc7eSAndroid Build Coastguard Worker  $main::op_time = time();
662*1208bc7eSAndroid Build Coastguard Worker
663*1208bc7eSAndroid Build Coastguard Worker  # Printing symbols is special and requires a lot less info that most.
664*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_symbols) {
665*1208bc7eSAndroid Build Coastguard Worker    PrintSymbols(*STDIN);   # Get /proc/maps and symbols output from stdin
666*1208bc7eSAndroid Build Coastguard Worker    return;
667*1208bc7eSAndroid Build Coastguard Worker  }
668*1208bc7eSAndroid Build Coastguard Worker
669*1208bc7eSAndroid Build Coastguard Worker  # Fetch all profile data
670*1208bc7eSAndroid Build Coastguard Worker  FetchDynamicProfiles();
671*1208bc7eSAndroid Build Coastguard Worker
672*1208bc7eSAndroid Build Coastguard Worker  # this will hold symbols that we read from the profile files
673*1208bc7eSAndroid Build Coastguard Worker  my $symbol_map = {};
674*1208bc7eSAndroid Build Coastguard Worker
675*1208bc7eSAndroid Build Coastguard Worker  # Read one profile, pick the last item on the list
676*1208bc7eSAndroid Build Coastguard Worker  my $data = ReadProfile($main::prog, pop(@main::profile_files));
677*1208bc7eSAndroid Build Coastguard Worker  my $profile = $data->{profile};
678*1208bc7eSAndroid Build Coastguard Worker  my $pcs = $data->{pcs};
679*1208bc7eSAndroid Build Coastguard Worker  my $libs = $data->{libs};   # Info about main program and shared libraries
680*1208bc7eSAndroid Build Coastguard Worker  $symbol_map = MergeSymbols($symbol_map, $data->{symbols});
681*1208bc7eSAndroid Build Coastguard Worker
682*1208bc7eSAndroid Build Coastguard Worker  # Add additional profiles, if available.
683*1208bc7eSAndroid Build Coastguard Worker  if (scalar(@main::profile_files) > 0) {
684*1208bc7eSAndroid Build Coastguard Worker    foreach my $pname (@main::profile_files) {
685*1208bc7eSAndroid Build Coastguard Worker      my $data2 = ReadProfile($main::prog, $pname);
686*1208bc7eSAndroid Build Coastguard Worker      $profile = AddProfile($profile, $data2->{profile});
687*1208bc7eSAndroid Build Coastguard Worker      $pcs = AddPcs($pcs, $data2->{pcs});
688*1208bc7eSAndroid Build Coastguard Worker      $symbol_map = MergeSymbols($symbol_map, $data2->{symbols});
689*1208bc7eSAndroid Build Coastguard Worker    }
690*1208bc7eSAndroid Build Coastguard Worker  }
691*1208bc7eSAndroid Build Coastguard Worker
692*1208bc7eSAndroid Build Coastguard Worker  # Subtract base from profile, if specified
693*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_base ne '') {
694*1208bc7eSAndroid Build Coastguard Worker    my $base = ReadProfile($main::prog, $main::opt_base);
695*1208bc7eSAndroid Build Coastguard Worker    $profile = SubtractProfile($profile, $base->{profile});
696*1208bc7eSAndroid Build Coastguard Worker    $pcs = AddPcs($pcs, $base->{pcs});
697*1208bc7eSAndroid Build Coastguard Worker    $symbol_map = MergeSymbols($symbol_map, $base->{symbols});
698*1208bc7eSAndroid Build Coastguard Worker  }
699*1208bc7eSAndroid Build Coastguard Worker
700*1208bc7eSAndroid Build Coastguard Worker  # Collect symbols
701*1208bc7eSAndroid Build Coastguard Worker  my $symbols;
702*1208bc7eSAndroid Build Coastguard Worker  if ($main::use_symbolized_profile) {
703*1208bc7eSAndroid Build Coastguard Worker    $symbols = FetchSymbols($pcs, $symbol_map);
704*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::use_symbol_page) {
705*1208bc7eSAndroid Build Coastguard Worker    $symbols = FetchSymbols($pcs);
706*1208bc7eSAndroid Build Coastguard Worker  } else {
707*1208bc7eSAndroid Build Coastguard Worker    # TODO(csilvers): $libs uses the /proc/self/maps data from profile1,
708*1208bc7eSAndroid Build Coastguard Worker    # which may differ from the data from subsequent profiles, especially
709*1208bc7eSAndroid Build Coastguard Worker    # if they were run on different machines.  Use appropriate libs for
710*1208bc7eSAndroid Build Coastguard Worker    # each pc somehow.
711*1208bc7eSAndroid Build Coastguard Worker    $symbols = ExtractSymbols($libs, $pcs);
712*1208bc7eSAndroid Build Coastguard Worker  }
713*1208bc7eSAndroid Build Coastguard Worker
714*1208bc7eSAndroid Build Coastguard Worker  if (!defined($main::opt_thread)) {
715*1208bc7eSAndroid Build Coastguard Worker    FilterAndPrint($profile, $symbols, $libs);
716*1208bc7eSAndroid Build Coastguard Worker  }
717*1208bc7eSAndroid Build Coastguard Worker  if (defined($data->{threads})) {
718*1208bc7eSAndroid Build Coastguard Worker    foreach my $thread (sort { $a <=> $b } keys(%{$data->{threads}})) {
719*1208bc7eSAndroid Build Coastguard Worker      if (defined($main::opt_thread) &&
720*1208bc7eSAndroid Build Coastguard Worker          ($main::opt_thread eq '*' || $main::opt_thread == $thread)) {
721*1208bc7eSAndroid Build Coastguard Worker        my $thread_profile = $data->{threads}{$thread};
722*1208bc7eSAndroid Build Coastguard Worker        FilterAndPrint($thread_profile, $symbols, $libs, $thread);
723*1208bc7eSAndroid Build Coastguard Worker      }
724*1208bc7eSAndroid Build Coastguard Worker    }
725*1208bc7eSAndroid Build Coastguard Worker  }
726*1208bc7eSAndroid Build Coastguard Worker
727*1208bc7eSAndroid Build Coastguard Worker  cleanup();
728*1208bc7eSAndroid Build Coastguard Worker  exit(0);
729*1208bc7eSAndroid Build Coastguard Worker}
730*1208bc7eSAndroid Build Coastguard Worker
731*1208bc7eSAndroid Build Coastguard Worker##### Entry Point #####
732*1208bc7eSAndroid Build Coastguard Worker
733*1208bc7eSAndroid Build Coastguard WorkerMain();
734*1208bc7eSAndroid Build Coastguard Worker
735*1208bc7eSAndroid Build Coastguard Worker# Temporary code to detect if we're running on a Goobuntu system.
736*1208bc7eSAndroid Build Coastguard Worker# These systems don't have the right stuff installed for the special
737*1208bc7eSAndroid Build Coastguard Worker# Readline libraries to work, so as a temporary workaround, we default
738*1208bc7eSAndroid Build Coastguard Worker# to using the normal stdio code, rather than the fancier readline-based
739*1208bc7eSAndroid Build Coastguard Worker# code
740*1208bc7eSAndroid Build Coastguard Workersub ReadlineMightFail {
741*1208bc7eSAndroid Build Coastguard Worker  if (-e '/lib/libtermcap.so.2') {
742*1208bc7eSAndroid Build Coastguard Worker    return 0;  # libtermcap exists, so readline should be okay
743*1208bc7eSAndroid Build Coastguard Worker  } else {
744*1208bc7eSAndroid Build Coastguard Worker    return 1;
745*1208bc7eSAndroid Build Coastguard Worker  }
746*1208bc7eSAndroid Build Coastguard Worker}
747*1208bc7eSAndroid Build Coastguard Worker
748*1208bc7eSAndroid Build Coastguard Workersub RunGV {
749*1208bc7eSAndroid Build Coastguard Worker  my $fname = shift;
750*1208bc7eSAndroid Build Coastguard Worker  my $bg = shift;       # "" or " &" if we should run in background
751*1208bc7eSAndroid Build Coastguard Worker  if (!system(ShellEscape(@GV, "--version") . " >$dev_null 2>&1")) {
752*1208bc7eSAndroid Build Coastguard Worker    # Options using double dash are supported by this gv version.
753*1208bc7eSAndroid Build Coastguard Worker    # Also, turn on noantialias to better handle bug in gv for
754*1208bc7eSAndroid Build Coastguard Worker    # postscript files with large dimensions.
755*1208bc7eSAndroid Build Coastguard Worker    # TODO: Maybe we should not pass the --noantialias flag
756*1208bc7eSAndroid Build Coastguard Worker    # if the gv version is known to work properly without the flag.
757*1208bc7eSAndroid Build Coastguard Worker    system(ShellEscape(@GV, "--scale=$main::opt_scale", "--noantialias", $fname)
758*1208bc7eSAndroid Build Coastguard Worker           . $bg);
759*1208bc7eSAndroid Build Coastguard Worker  } else {
760*1208bc7eSAndroid Build Coastguard Worker    # Old gv version - only supports options that use single dash.
761*1208bc7eSAndroid Build Coastguard Worker    print STDERR ShellEscape(@GV, "-scale", $main::opt_scale) . "\n";
762*1208bc7eSAndroid Build Coastguard Worker    system(ShellEscape(@GV, "-scale", "$main::opt_scale", $fname) . $bg);
763*1208bc7eSAndroid Build Coastguard Worker  }
764*1208bc7eSAndroid Build Coastguard Worker}
765*1208bc7eSAndroid Build Coastguard Worker
766*1208bc7eSAndroid Build Coastguard Workersub RunEvince {
767*1208bc7eSAndroid Build Coastguard Worker  my $fname = shift;
768*1208bc7eSAndroid Build Coastguard Worker  my $bg = shift;       # "" or " &" if we should run in background
769*1208bc7eSAndroid Build Coastguard Worker  system(ShellEscape(@EVINCE, $fname) . $bg);
770*1208bc7eSAndroid Build Coastguard Worker}
771*1208bc7eSAndroid Build Coastguard Worker
772*1208bc7eSAndroid Build Coastguard Workersub RunWeb {
773*1208bc7eSAndroid Build Coastguard Worker  my $fname = shift;
774*1208bc7eSAndroid Build Coastguard Worker  print STDERR "Loading web page file:///$fname\n";
775*1208bc7eSAndroid Build Coastguard Worker
776*1208bc7eSAndroid Build Coastguard Worker  if (`uname` =~ /Darwin/) {
777*1208bc7eSAndroid Build Coastguard Worker    # OS X: open will use standard preference for SVG files.
778*1208bc7eSAndroid Build Coastguard Worker    system("/usr/bin/open", $fname);
779*1208bc7eSAndroid Build Coastguard Worker    return;
780*1208bc7eSAndroid Build Coastguard Worker  }
781*1208bc7eSAndroid Build Coastguard Worker
782*1208bc7eSAndroid Build Coastguard Worker  # Some kind of Unix; try generic symlinks, then specific browsers.
783*1208bc7eSAndroid Build Coastguard Worker  # (Stop once we find one.)
784*1208bc7eSAndroid Build Coastguard Worker  # Works best if the browser is already running.
785*1208bc7eSAndroid Build Coastguard Worker  my @alt = (
786*1208bc7eSAndroid Build Coastguard Worker    "/etc/alternatives/gnome-www-browser",
787*1208bc7eSAndroid Build Coastguard Worker    "/etc/alternatives/x-www-browser",
788*1208bc7eSAndroid Build Coastguard Worker    "google-chrome",
789*1208bc7eSAndroid Build Coastguard Worker    "firefox",
790*1208bc7eSAndroid Build Coastguard Worker  );
791*1208bc7eSAndroid Build Coastguard Worker  foreach my $b (@alt) {
792*1208bc7eSAndroid Build Coastguard Worker    if (system($b, $fname) == 0) {
793*1208bc7eSAndroid Build Coastguard Worker      return;
794*1208bc7eSAndroid Build Coastguard Worker    }
795*1208bc7eSAndroid Build Coastguard Worker  }
796*1208bc7eSAndroid Build Coastguard Worker
797*1208bc7eSAndroid Build Coastguard Worker  print STDERR "Could not load web browser.\n";
798*1208bc7eSAndroid Build Coastguard Worker}
799*1208bc7eSAndroid Build Coastguard Worker
800*1208bc7eSAndroid Build Coastguard Workersub RunKcachegrind {
801*1208bc7eSAndroid Build Coastguard Worker  my $fname = shift;
802*1208bc7eSAndroid Build Coastguard Worker  my $bg = shift;       # "" or " &" if we should run in background
803*1208bc7eSAndroid Build Coastguard Worker  print STDERR "Starting '@KCACHEGRIND " . $fname . $bg . "'\n";
804*1208bc7eSAndroid Build Coastguard Worker  system(ShellEscape(@KCACHEGRIND, $fname) . $bg);
805*1208bc7eSAndroid Build Coastguard Worker}
806*1208bc7eSAndroid Build Coastguard Worker
807*1208bc7eSAndroid Build Coastguard Worker
808*1208bc7eSAndroid Build Coastguard Worker##### Interactive helper routines #####
809*1208bc7eSAndroid Build Coastguard Worker
810*1208bc7eSAndroid Build Coastguard Workersub InteractiveMode {
811*1208bc7eSAndroid Build Coastguard Worker  $| = 1;  # Make output unbuffered for interactive mode
812*1208bc7eSAndroid Build Coastguard Worker  my ($orig_profile, $symbols, $libs, $total) = @_;
813*1208bc7eSAndroid Build Coastguard Worker
814*1208bc7eSAndroid Build Coastguard Worker  print STDERR "Welcome to jeprof!  For help, type 'help'.\n";
815*1208bc7eSAndroid Build Coastguard Worker
816*1208bc7eSAndroid Build Coastguard Worker  # Use ReadLine if it's installed and input comes from a console.
817*1208bc7eSAndroid Build Coastguard Worker  if ( -t STDIN &&
818*1208bc7eSAndroid Build Coastguard Worker       !ReadlineMightFail() &&
819*1208bc7eSAndroid Build Coastguard Worker       defined(eval {require Term::ReadLine}) ) {
820*1208bc7eSAndroid Build Coastguard Worker    my $term = new Term::ReadLine 'jeprof';
821*1208bc7eSAndroid Build Coastguard Worker    while ( defined ($_ = $term->readline('(jeprof) '))) {
822*1208bc7eSAndroid Build Coastguard Worker      $term->addhistory($_) if /\S/;
823*1208bc7eSAndroid Build Coastguard Worker      if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
824*1208bc7eSAndroid Build Coastguard Worker        last;    # exit when we get an interactive command to quit
825*1208bc7eSAndroid Build Coastguard Worker      }
826*1208bc7eSAndroid Build Coastguard Worker    }
827*1208bc7eSAndroid Build Coastguard Worker  } else {       # don't have readline
828*1208bc7eSAndroid Build Coastguard Worker    while (1) {
829*1208bc7eSAndroid Build Coastguard Worker      print STDERR "(jeprof) ";
830*1208bc7eSAndroid Build Coastguard Worker      $_ = <STDIN>;
831*1208bc7eSAndroid Build Coastguard Worker      last if ! defined $_ ;
832*1208bc7eSAndroid Build Coastguard Worker      s/\r//g;         # turn windows-looking lines into unix-looking lines
833*1208bc7eSAndroid Build Coastguard Worker
834*1208bc7eSAndroid Build Coastguard Worker      # Save some flags that might be reset by InteractiveCommand()
835*1208bc7eSAndroid Build Coastguard Worker      my $save_opt_lines = $main::opt_lines;
836*1208bc7eSAndroid Build Coastguard Worker
837*1208bc7eSAndroid Build Coastguard Worker      if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
838*1208bc7eSAndroid Build Coastguard Worker        last;    # exit when we get an interactive command to quit
839*1208bc7eSAndroid Build Coastguard Worker      }
840*1208bc7eSAndroid Build Coastguard Worker
841*1208bc7eSAndroid Build Coastguard Worker      # Restore flags
842*1208bc7eSAndroid Build Coastguard Worker      $main::opt_lines = $save_opt_lines;
843*1208bc7eSAndroid Build Coastguard Worker    }
844*1208bc7eSAndroid Build Coastguard Worker  }
845*1208bc7eSAndroid Build Coastguard Worker}
846*1208bc7eSAndroid Build Coastguard Worker
847*1208bc7eSAndroid Build Coastguard Worker# Takes two args: orig profile, and command to run.
848*1208bc7eSAndroid Build Coastguard Worker# Returns 1 if we should keep going, or 0 if we were asked to quit
849*1208bc7eSAndroid Build Coastguard Workersub InteractiveCommand {
850*1208bc7eSAndroid Build Coastguard Worker  my($orig_profile, $symbols, $libs, $total, $command) = @_;
851*1208bc7eSAndroid Build Coastguard Worker  $_ = $command;                # just to make future m//'s easier
852*1208bc7eSAndroid Build Coastguard Worker  if (!defined($_)) {
853*1208bc7eSAndroid Build Coastguard Worker    print STDERR "\n";
854*1208bc7eSAndroid Build Coastguard Worker    return 0;
855*1208bc7eSAndroid Build Coastguard Worker  }
856*1208bc7eSAndroid Build Coastguard Worker  if (m/^\s*quit/) {
857*1208bc7eSAndroid Build Coastguard Worker    return 0;
858*1208bc7eSAndroid Build Coastguard Worker  }
859*1208bc7eSAndroid Build Coastguard Worker  if (m/^\s*help/) {
860*1208bc7eSAndroid Build Coastguard Worker    InteractiveHelpMessage();
861*1208bc7eSAndroid Build Coastguard Worker    return 1;
862*1208bc7eSAndroid Build Coastguard Worker  }
863*1208bc7eSAndroid Build Coastguard Worker  # Clear all the mode options -- mode is controlled by "$command"
864*1208bc7eSAndroid Build Coastguard Worker  $main::opt_text = 0;
865*1208bc7eSAndroid Build Coastguard Worker  $main::opt_callgrind = 0;
866*1208bc7eSAndroid Build Coastguard Worker  $main::opt_disasm = 0;
867*1208bc7eSAndroid Build Coastguard Worker  $main::opt_list = 0;
868*1208bc7eSAndroid Build Coastguard Worker  $main::opt_gv = 0;
869*1208bc7eSAndroid Build Coastguard Worker  $main::opt_evince = 0;
870*1208bc7eSAndroid Build Coastguard Worker  $main::opt_cum = 0;
871*1208bc7eSAndroid Build Coastguard Worker
872*1208bc7eSAndroid Build Coastguard Worker  if (m/^\s*(text|top)(\d*)\s*(.*)/) {
873*1208bc7eSAndroid Build Coastguard Worker    $main::opt_text = 1;
874*1208bc7eSAndroid Build Coastguard Worker
875*1208bc7eSAndroid Build Coastguard Worker    my $line_limit = ($2 ne "") ? int($2) : 10;
876*1208bc7eSAndroid Build Coastguard Worker
877*1208bc7eSAndroid Build Coastguard Worker    my $routine;
878*1208bc7eSAndroid Build Coastguard Worker    my $ignore;
879*1208bc7eSAndroid Build Coastguard Worker    ($routine, $ignore) = ParseInteractiveArgs($3);
880*1208bc7eSAndroid Build Coastguard Worker
881*1208bc7eSAndroid Build Coastguard Worker    my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
882*1208bc7eSAndroid Build Coastguard Worker    my $reduced = ReduceProfile($symbols, $profile);
883*1208bc7eSAndroid Build Coastguard Worker
884*1208bc7eSAndroid Build Coastguard Worker    # Get derived profiles
885*1208bc7eSAndroid Build Coastguard Worker    my $flat = FlatProfile($reduced);
886*1208bc7eSAndroid Build Coastguard Worker    my $cumulative = CumulativeProfile($reduced);
887*1208bc7eSAndroid Build Coastguard Worker
888*1208bc7eSAndroid Build Coastguard Worker    PrintText($symbols, $flat, $cumulative, $line_limit);
889*1208bc7eSAndroid Build Coastguard Worker    return 1;
890*1208bc7eSAndroid Build Coastguard Worker  }
891*1208bc7eSAndroid Build Coastguard Worker  if (m/^\s*callgrind\s*([^ \n]*)/) {
892*1208bc7eSAndroid Build Coastguard Worker    $main::opt_callgrind = 1;
893*1208bc7eSAndroid Build Coastguard Worker
894*1208bc7eSAndroid Build Coastguard Worker    # Get derived profiles
895*1208bc7eSAndroid Build Coastguard Worker    my $calls = ExtractCalls($symbols, $orig_profile);
896*1208bc7eSAndroid Build Coastguard Worker    my $filename = $1;
897*1208bc7eSAndroid Build Coastguard Worker    if ( $1 eq '' ) {
898*1208bc7eSAndroid Build Coastguard Worker      $filename = TempName($main::next_tmpfile, "callgrind");
899*1208bc7eSAndroid Build Coastguard Worker    }
900*1208bc7eSAndroid Build Coastguard Worker    PrintCallgrind($calls, $filename);
901*1208bc7eSAndroid Build Coastguard Worker    if ( $1 eq '' ) {
902*1208bc7eSAndroid Build Coastguard Worker      RunKcachegrind($filename, " & ");
903*1208bc7eSAndroid Build Coastguard Worker      $main::next_tmpfile++;
904*1208bc7eSAndroid Build Coastguard Worker    }
905*1208bc7eSAndroid Build Coastguard Worker
906*1208bc7eSAndroid Build Coastguard Worker    return 1;
907*1208bc7eSAndroid Build Coastguard Worker  }
908*1208bc7eSAndroid Build Coastguard Worker  if (m/^\s*(web)?list\s*(.+)/) {
909*1208bc7eSAndroid Build Coastguard Worker    my $html = (defined($1) && ($1 eq "web"));
910*1208bc7eSAndroid Build Coastguard Worker    $main::opt_list = 1;
911*1208bc7eSAndroid Build Coastguard Worker
912*1208bc7eSAndroid Build Coastguard Worker    my $routine;
913*1208bc7eSAndroid Build Coastguard Worker    my $ignore;
914*1208bc7eSAndroid Build Coastguard Worker    ($routine, $ignore) = ParseInteractiveArgs($2);
915*1208bc7eSAndroid Build Coastguard Worker
916*1208bc7eSAndroid Build Coastguard Worker    my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
917*1208bc7eSAndroid Build Coastguard Worker    my $reduced = ReduceProfile($symbols, $profile);
918*1208bc7eSAndroid Build Coastguard Worker
919*1208bc7eSAndroid Build Coastguard Worker    # Get derived profiles
920*1208bc7eSAndroid Build Coastguard Worker    my $flat = FlatProfile($reduced);
921*1208bc7eSAndroid Build Coastguard Worker    my $cumulative = CumulativeProfile($reduced);
922*1208bc7eSAndroid Build Coastguard Worker
923*1208bc7eSAndroid Build Coastguard Worker    PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
924*1208bc7eSAndroid Build Coastguard Worker    return 1;
925*1208bc7eSAndroid Build Coastguard Worker  }
926*1208bc7eSAndroid Build Coastguard Worker  if (m/^\s*disasm\s*(.+)/) {
927*1208bc7eSAndroid Build Coastguard Worker    $main::opt_disasm = 1;
928*1208bc7eSAndroid Build Coastguard Worker
929*1208bc7eSAndroid Build Coastguard Worker    my $routine;
930*1208bc7eSAndroid Build Coastguard Worker    my $ignore;
931*1208bc7eSAndroid Build Coastguard Worker    ($routine, $ignore) = ParseInteractiveArgs($1);
932*1208bc7eSAndroid Build Coastguard Worker
933*1208bc7eSAndroid Build Coastguard Worker    # Process current profile to account for various settings
934*1208bc7eSAndroid Build Coastguard Worker    my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
935*1208bc7eSAndroid Build Coastguard Worker    my $reduced = ReduceProfile($symbols, $profile);
936*1208bc7eSAndroid Build Coastguard Worker
937*1208bc7eSAndroid Build Coastguard Worker    # Get derived profiles
938*1208bc7eSAndroid Build Coastguard Worker    my $flat = FlatProfile($reduced);
939*1208bc7eSAndroid Build Coastguard Worker    my $cumulative = CumulativeProfile($reduced);
940*1208bc7eSAndroid Build Coastguard Worker
941*1208bc7eSAndroid Build Coastguard Worker    PrintDisassembly($libs, $flat, $cumulative, $routine);
942*1208bc7eSAndroid Build Coastguard Worker    return 1;
943*1208bc7eSAndroid Build Coastguard Worker  }
944*1208bc7eSAndroid Build Coastguard Worker  if (m/^\s*(gv|web|evince)\s*(.*)/) {
945*1208bc7eSAndroid Build Coastguard Worker    $main::opt_gv = 0;
946*1208bc7eSAndroid Build Coastguard Worker    $main::opt_evince = 0;
947*1208bc7eSAndroid Build Coastguard Worker    $main::opt_web = 0;
948*1208bc7eSAndroid Build Coastguard Worker    if ($1 eq "gv") {
949*1208bc7eSAndroid Build Coastguard Worker      $main::opt_gv = 1;
950*1208bc7eSAndroid Build Coastguard Worker    } elsif ($1 eq "evince") {
951*1208bc7eSAndroid Build Coastguard Worker      $main::opt_evince = 1;
952*1208bc7eSAndroid Build Coastguard Worker    } elsif ($1 eq "web") {
953*1208bc7eSAndroid Build Coastguard Worker      $main::opt_web = 1;
954*1208bc7eSAndroid Build Coastguard Worker    }
955*1208bc7eSAndroid Build Coastguard Worker
956*1208bc7eSAndroid Build Coastguard Worker    my $focus;
957*1208bc7eSAndroid Build Coastguard Worker    my $ignore;
958*1208bc7eSAndroid Build Coastguard Worker    ($focus, $ignore) = ParseInteractiveArgs($2);
959*1208bc7eSAndroid Build Coastguard Worker
960*1208bc7eSAndroid Build Coastguard Worker    # Process current profile to account for various settings
961*1208bc7eSAndroid Build Coastguard Worker    my $profile = ProcessProfile($total, $orig_profile, $symbols,
962*1208bc7eSAndroid Build Coastguard Worker                                 $focus, $ignore);
963*1208bc7eSAndroid Build Coastguard Worker    my $reduced = ReduceProfile($symbols, $profile);
964*1208bc7eSAndroid Build Coastguard Worker
965*1208bc7eSAndroid Build Coastguard Worker    # Get derived profiles
966*1208bc7eSAndroid Build Coastguard Worker    my $flat = FlatProfile($reduced);
967*1208bc7eSAndroid Build Coastguard Worker    my $cumulative = CumulativeProfile($reduced);
968*1208bc7eSAndroid Build Coastguard Worker
969*1208bc7eSAndroid Build Coastguard Worker    if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
970*1208bc7eSAndroid Build Coastguard Worker      if ($main::opt_gv) {
971*1208bc7eSAndroid Build Coastguard Worker        RunGV(TempName($main::next_tmpfile, "ps"), " &");
972*1208bc7eSAndroid Build Coastguard Worker      } elsif ($main::opt_evince) {
973*1208bc7eSAndroid Build Coastguard Worker        RunEvince(TempName($main::next_tmpfile, "pdf"), " &");
974*1208bc7eSAndroid Build Coastguard Worker      } elsif ($main::opt_web) {
975*1208bc7eSAndroid Build Coastguard Worker        RunWeb(TempName($main::next_tmpfile, "svg"));
976*1208bc7eSAndroid Build Coastguard Worker      }
977*1208bc7eSAndroid Build Coastguard Worker      $main::next_tmpfile++;
978*1208bc7eSAndroid Build Coastguard Worker    }
979*1208bc7eSAndroid Build Coastguard Worker    return 1;
980*1208bc7eSAndroid Build Coastguard Worker  }
981*1208bc7eSAndroid Build Coastguard Worker  if (m/^\s*$/) {
982*1208bc7eSAndroid Build Coastguard Worker    return 1;
983*1208bc7eSAndroid Build Coastguard Worker  }
984*1208bc7eSAndroid Build Coastguard Worker  print STDERR "Unknown command: try 'help'.\n";
985*1208bc7eSAndroid Build Coastguard Worker  return 1;
986*1208bc7eSAndroid Build Coastguard Worker}
987*1208bc7eSAndroid Build Coastguard Worker
988*1208bc7eSAndroid Build Coastguard Worker
989*1208bc7eSAndroid Build Coastguard Workersub ProcessProfile {
990*1208bc7eSAndroid Build Coastguard Worker  my $total_count = shift;
991*1208bc7eSAndroid Build Coastguard Worker  my $orig_profile = shift;
992*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
993*1208bc7eSAndroid Build Coastguard Worker  my $focus = shift;
994*1208bc7eSAndroid Build Coastguard Worker  my $ignore = shift;
995*1208bc7eSAndroid Build Coastguard Worker
996*1208bc7eSAndroid Build Coastguard Worker  # Process current profile to account for various settings
997*1208bc7eSAndroid Build Coastguard Worker  my $profile = $orig_profile;
998*1208bc7eSAndroid Build Coastguard Worker  printf("Total: %s %s\n", Unparse($total_count), Units());
999*1208bc7eSAndroid Build Coastguard Worker  if ($focus ne '') {
1000*1208bc7eSAndroid Build Coastguard Worker    $profile = FocusProfile($symbols, $profile, $focus);
1001*1208bc7eSAndroid Build Coastguard Worker    my $focus_count = TotalProfile($profile);
1002*1208bc7eSAndroid Build Coastguard Worker    printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
1003*1208bc7eSAndroid Build Coastguard Worker           $focus,
1004*1208bc7eSAndroid Build Coastguard Worker           Unparse($focus_count), Units(),
1005*1208bc7eSAndroid Build Coastguard Worker           Unparse($total_count), ($focus_count*100.0) / $total_count);
1006*1208bc7eSAndroid Build Coastguard Worker  }
1007*1208bc7eSAndroid Build Coastguard Worker  if ($ignore ne '') {
1008*1208bc7eSAndroid Build Coastguard Worker    $profile = IgnoreProfile($symbols, $profile, $ignore);
1009*1208bc7eSAndroid Build Coastguard Worker    my $ignore_count = TotalProfile($profile);
1010*1208bc7eSAndroid Build Coastguard Worker    printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
1011*1208bc7eSAndroid Build Coastguard Worker           $ignore,
1012*1208bc7eSAndroid Build Coastguard Worker           Unparse($ignore_count), Units(),
1013*1208bc7eSAndroid Build Coastguard Worker           Unparse($total_count),
1014*1208bc7eSAndroid Build Coastguard Worker           ($ignore_count*100.0) / $total_count);
1015*1208bc7eSAndroid Build Coastguard Worker  }
1016*1208bc7eSAndroid Build Coastguard Worker
1017*1208bc7eSAndroid Build Coastguard Worker  return $profile;
1018*1208bc7eSAndroid Build Coastguard Worker}
1019*1208bc7eSAndroid Build Coastguard Worker
1020*1208bc7eSAndroid Build Coastguard Workersub InteractiveHelpMessage {
1021*1208bc7eSAndroid Build Coastguard Worker  print STDERR <<ENDOFHELP;
1022*1208bc7eSAndroid Build Coastguard WorkerInteractive jeprof mode
1023*1208bc7eSAndroid Build Coastguard Worker
1024*1208bc7eSAndroid Build Coastguard WorkerCommands:
1025*1208bc7eSAndroid Build Coastguard Worker  gv
1026*1208bc7eSAndroid Build Coastguard Worker  gv [focus] [-ignore1] [-ignore2]
1027*1208bc7eSAndroid Build Coastguard Worker      Show graphical hierarchical display of current profile.  Without
1028*1208bc7eSAndroid Build Coastguard Worker      any arguments, shows all samples in the profile.  With the optional
1029*1208bc7eSAndroid Build Coastguard Worker      "focus" argument, restricts the samples shown to just those where
1030*1208bc7eSAndroid Build Coastguard Worker      the "focus" regular expression matches a routine name on the stack
1031*1208bc7eSAndroid Build Coastguard Worker      trace.
1032*1208bc7eSAndroid Build Coastguard Worker
1033*1208bc7eSAndroid Build Coastguard Worker  web
1034*1208bc7eSAndroid Build Coastguard Worker  web [focus] [-ignore1] [-ignore2]
1035*1208bc7eSAndroid Build Coastguard Worker      Like GV, but displays profile in your web browser instead of using
1036*1208bc7eSAndroid Build Coastguard Worker      Ghostview. Works best if your web browser is already running.
1037*1208bc7eSAndroid Build Coastguard Worker      To change the browser that gets used:
1038*1208bc7eSAndroid Build Coastguard Worker      On Linux, set the /etc/alternatives/gnome-www-browser symlink.
1039*1208bc7eSAndroid Build Coastguard Worker      On OS X, change the Finder association for SVG files.
1040*1208bc7eSAndroid Build Coastguard Worker
1041*1208bc7eSAndroid Build Coastguard Worker  list [routine_regexp] [-ignore1] [-ignore2]
1042*1208bc7eSAndroid Build Coastguard Worker      Show source listing of routines whose names match "routine_regexp"
1043*1208bc7eSAndroid Build Coastguard Worker
1044*1208bc7eSAndroid Build Coastguard Worker  weblist [routine_regexp] [-ignore1] [-ignore2]
1045*1208bc7eSAndroid Build Coastguard Worker     Displays a source listing of routines whose names match "routine_regexp"
1046*1208bc7eSAndroid Build Coastguard Worker     in a web browser.  You can click on source lines to view the
1047*1208bc7eSAndroid Build Coastguard Worker     corresponding disassembly.
1048*1208bc7eSAndroid Build Coastguard Worker
1049*1208bc7eSAndroid Build Coastguard Worker  top [--cum] [-ignore1] [-ignore2]
1050*1208bc7eSAndroid Build Coastguard Worker  top20 [--cum] [-ignore1] [-ignore2]
1051*1208bc7eSAndroid Build Coastguard Worker  top37 [--cum] [-ignore1] [-ignore2]
1052*1208bc7eSAndroid Build Coastguard Worker      Show top lines ordered by flat profile count, or cumulative count
1053*1208bc7eSAndroid Build Coastguard Worker      if --cum is specified.  If a number is present after 'top', the
1054*1208bc7eSAndroid Build Coastguard Worker      top K routines will be shown (defaults to showing the top 10)
1055*1208bc7eSAndroid Build Coastguard Worker
1056*1208bc7eSAndroid Build Coastguard Worker  disasm [routine_regexp] [-ignore1] [-ignore2]
1057*1208bc7eSAndroid Build Coastguard Worker      Show disassembly of routines whose names match "routine_regexp",
1058*1208bc7eSAndroid Build Coastguard Worker      annotated with sample counts.
1059*1208bc7eSAndroid Build Coastguard Worker
1060*1208bc7eSAndroid Build Coastguard Worker  callgrind
1061*1208bc7eSAndroid Build Coastguard Worker  callgrind [filename]
1062*1208bc7eSAndroid Build Coastguard Worker      Generates callgrind file. If no filename is given, kcachegrind is called.
1063*1208bc7eSAndroid Build Coastguard Worker
1064*1208bc7eSAndroid Build Coastguard Worker  help - This listing
1065*1208bc7eSAndroid Build Coastguard Worker  quit or ^D - End jeprof
1066*1208bc7eSAndroid Build Coastguard Worker
1067*1208bc7eSAndroid Build Coastguard WorkerFor commands that accept optional -ignore tags, samples where any routine in
1068*1208bc7eSAndroid Build Coastguard Workerthe stack trace matches the regular expression in any of the -ignore
1069*1208bc7eSAndroid Build Coastguard Workerparameters will be ignored.
1070*1208bc7eSAndroid Build Coastguard Worker
1071*1208bc7eSAndroid Build Coastguard WorkerFurther pprof details are available at this location (or one similar):
1072*1208bc7eSAndroid Build Coastguard Worker
1073*1208bc7eSAndroid Build Coastguard Worker /usr/doc/gperftools-$PPROF_VERSION/cpu_profiler.html
1074*1208bc7eSAndroid Build Coastguard Worker /usr/doc/gperftools-$PPROF_VERSION/heap_profiler.html
1075*1208bc7eSAndroid Build Coastguard Worker
1076*1208bc7eSAndroid Build Coastguard WorkerENDOFHELP
1077*1208bc7eSAndroid Build Coastguard Worker}
1078*1208bc7eSAndroid Build Coastguard Workersub ParseInteractiveArgs {
1079*1208bc7eSAndroid Build Coastguard Worker  my $args = shift;
1080*1208bc7eSAndroid Build Coastguard Worker  my $focus = "";
1081*1208bc7eSAndroid Build Coastguard Worker  my $ignore = "";
1082*1208bc7eSAndroid Build Coastguard Worker  my @x = split(/ +/, $args);
1083*1208bc7eSAndroid Build Coastguard Worker  foreach $a (@x) {
1084*1208bc7eSAndroid Build Coastguard Worker    if ($a =~ m/^(--|-)lines$/) {
1085*1208bc7eSAndroid Build Coastguard Worker      $main::opt_lines = 1;
1086*1208bc7eSAndroid Build Coastguard Worker    } elsif ($a =~ m/^(--|-)cum$/) {
1087*1208bc7eSAndroid Build Coastguard Worker      $main::opt_cum = 1;
1088*1208bc7eSAndroid Build Coastguard Worker    } elsif ($a =~ m/^-(.*)/) {
1089*1208bc7eSAndroid Build Coastguard Worker      $ignore .= (($ignore ne "") ? "|" : "" ) . $1;
1090*1208bc7eSAndroid Build Coastguard Worker    } else {
1091*1208bc7eSAndroid Build Coastguard Worker      $focus .= (($focus ne "") ? "|" : "" ) . $a;
1092*1208bc7eSAndroid Build Coastguard Worker    }
1093*1208bc7eSAndroid Build Coastguard Worker  }
1094*1208bc7eSAndroid Build Coastguard Worker  if ($ignore ne "") {
1095*1208bc7eSAndroid Build Coastguard Worker    print STDERR "Ignoring samples in call stacks that match '$ignore'\n";
1096*1208bc7eSAndroid Build Coastguard Worker  }
1097*1208bc7eSAndroid Build Coastguard Worker  return ($focus, $ignore);
1098*1208bc7eSAndroid Build Coastguard Worker}
1099*1208bc7eSAndroid Build Coastguard Worker
1100*1208bc7eSAndroid Build Coastguard Worker##### Output code #####
1101*1208bc7eSAndroid Build Coastguard Worker
1102*1208bc7eSAndroid Build Coastguard Workersub TempName {
1103*1208bc7eSAndroid Build Coastguard Worker  my $fnum = shift;
1104*1208bc7eSAndroid Build Coastguard Worker  my $ext = shift;
1105*1208bc7eSAndroid Build Coastguard Worker  my $file = "$main::tmpfile_ps.$fnum.$ext";
1106*1208bc7eSAndroid Build Coastguard Worker  $main::tempnames{$file} = 1;
1107*1208bc7eSAndroid Build Coastguard Worker  return $file;
1108*1208bc7eSAndroid Build Coastguard Worker}
1109*1208bc7eSAndroid Build Coastguard Worker
1110*1208bc7eSAndroid Build Coastguard Worker# Print profile data in packed binary format (64-bit) to standard out
1111*1208bc7eSAndroid Build Coastguard Workersub PrintProfileData {
1112*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
1113*1208bc7eSAndroid Build Coastguard Worker
1114*1208bc7eSAndroid Build Coastguard Worker  # print header (64-bit style)
1115*1208bc7eSAndroid Build Coastguard Worker  # (zero) (header-size) (version) (sample-period) (zero)
1116*1208bc7eSAndroid Build Coastguard Worker  print pack('L*', 0, 0, 3, 0, 0, 0, 1, 0, 0, 0);
1117*1208bc7eSAndroid Build Coastguard Worker
1118*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
1119*1208bc7eSAndroid Build Coastguard Worker    my $count = $profile->{$k};
1120*1208bc7eSAndroid Build Coastguard Worker    my @addrs = split(/\n/, $k);
1121*1208bc7eSAndroid Build Coastguard Worker    if ($#addrs >= 0) {
1122*1208bc7eSAndroid Build Coastguard Worker      my $depth = $#addrs + 1;
1123*1208bc7eSAndroid Build Coastguard Worker      # int(foo / 2**32) is the only reliable way to get rid of bottom
1124*1208bc7eSAndroid Build Coastguard Worker      # 32 bits on both 32- and 64-bit systems.
1125*1208bc7eSAndroid Build Coastguard Worker      print pack('L*', $count & 0xFFFFFFFF, int($count / 2**32));
1126*1208bc7eSAndroid Build Coastguard Worker      print pack('L*', $depth & 0xFFFFFFFF, int($depth / 2**32));
1127*1208bc7eSAndroid Build Coastguard Worker
1128*1208bc7eSAndroid Build Coastguard Worker      foreach my $full_addr (@addrs) {
1129*1208bc7eSAndroid Build Coastguard Worker        my $addr = $full_addr;
1130*1208bc7eSAndroid Build Coastguard Worker        $addr =~ s/0x0*//;  # strip off leading 0x, zeroes
1131*1208bc7eSAndroid Build Coastguard Worker        if (length($addr) > 16) {
1132*1208bc7eSAndroid Build Coastguard Worker          print STDERR "Invalid address in profile: $full_addr\n";
1133*1208bc7eSAndroid Build Coastguard Worker          next;
1134*1208bc7eSAndroid Build Coastguard Worker        }
1135*1208bc7eSAndroid Build Coastguard Worker        my $low_addr = substr($addr, -8);       # get last 8 hex chars
1136*1208bc7eSAndroid Build Coastguard Worker        my $high_addr = substr($addr, -16, 8);  # get up to 8 more hex chars
1137*1208bc7eSAndroid Build Coastguard Worker        print pack('L*', hex('0x' . $low_addr), hex('0x' . $high_addr));
1138*1208bc7eSAndroid Build Coastguard Worker      }
1139*1208bc7eSAndroid Build Coastguard Worker    }
1140*1208bc7eSAndroid Build Coastguard Worker  }
1141*1208bc7eSAndroid Build Coastguard Worker}
1142*1208bc7eSAndroid Build Coastguard Worker
1143*1208bc7eSAndroid Build Coastguard Worker# Print symbols and profile data
1144*1208bc7eSAndroid Build Coastguard Workersub PrintSymbolizedProfile {
1145*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
1146*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
1147*1208bc7eSAndroid Build Coastguard Worker  my $prog = shift;
1148*1208bc7eSAndroid Build Coastguard Worker
1149*1208bc7eSAndroid Build Coastguard Worker  $SYMBOL_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
1150*1208bc7eSAndroid Build Coastguard Worker  my $symbol_marker = $&;
1151*1208bc7eSAndroid Build Coastguard Worker
1152*1208bc7eSAndroid Build Coastguard Worker  print '--- ', $symbol_marker, "\n";
1153*1208bc7eSAndroid Build Coastguard Worker  if (defined($prog)) {
1154*1208bc7eSAndroid Build Coastguard Worker    print 'binary=', $prog, "\n";
1155*1208bc7eSAndroid Build Coastguard Worker  }
1156*1208bc7eSAndroid Build Coastguard Worker  while (my ($pc, $name) = each(%{$symbols})) {
1157*1208bc7eSAndroid Build Coastguard Worker    my $sep = ' ';
1158*1208bc7eSAndroid Build Coastguard Worker    print '0x', $pc;
1159*1208bc7eSAndroid Build Coastguard Worker    # We have a list of function names, which include the inlined
1160*1208bc7eSAndroid Build Coastguard Worker    # calls.  They are separated (and terminated) by --, which is
1161*1208bc7eSAndroid Build Coastguard Worker    # illegal in function names.
1162*1208bc7eSAndroid Build Coastguard Worker    for (my $j = 2; $j <= $#{$name}; $j += 3) {
1163*1208bc7eSAndroid Build Coastguard Worker      print $sep, $name->[$j];
1164*1208bc7eSAndroid Build Coastguard Worker      $sep = '--';
1165*1208bc7eSAndroid Build Coastguard Worker    }
1166*1208bc7eSAndroid Build Coastguard Worker    print "\n";
1167*1208bc7eSAndroid Build Coastguard Worker  }
1168*1208bc7eSAndroid Build Coastguard Worker  print '---', "\n";
1169*1208bc7eSAndroid Build Coastguard Worker
1170*1208bc7eSAndroid Build Coastguard Worker  my $profile_marker;
1171*1208bc7eSAndroid Build Coastguard Worker  if ($main::profile_type eq 'heap') {
1172*1208bc7eSAndroid Build Coastguard Worker    $HEAP_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
1173*1208bc7eSAndroid Build Coastguard Worker    $profile_marker = $&;
1174*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::profile_type eq 'growth') {
1175*1208bc7eSAndroid Build Coastguard Worker    $GROWTH_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
1176*1208bc7eSAndroid Build Coastguard Worker    $profile_marker = $&;
1177*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::profile_type eq 'contention') {
1178*1208bc7eSAndroid Build Coastguard Worker    $CONTENTION_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
1179*1208bc7eSAndroid Build Coastguard Worker    $profile_marker = $&;
1180*1208bc7eSAndroid Build Coastguard Worker  } else { # elsif ($main::profile_type eq 'cpu')
1181*1208bc7eSAndroid Build Coastguard Worker    $PROFILE_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
1182*1208bc7eSAndroid Build Coastguard Worker    $profile_marker = $&;
1183*1208bc7eSAndroid Build Coastguard Worker  }
1184*1208bc7eSAndroid Build Coastguard Worker
1185*1208bc7eSAndroid Build Coastguard Worker  print '--- ', $profile_marker, "\n";
1186*1208bc7eSAndroid Build Coastguard Worker  if (defined($main::collected_profile)) {
1187*1208bc7eSAndroid Build Coastguard Worker    # if used with remote fetch, simply dump the collected profile to output.
1188*1208bc7eSAndroid Build Coastguard Worker    open(SRC, "<$main::collected_profile");
1189*1208bc7eSAndroid Build Coastguard Worker    while (<SRC>) {
1190*1208bc7eSAndroid Build Coastguard Worker      print $_;
1191*1208bc7eSAndroid Build Coastguard Worker    }
1192*1208bc7eSAndroid Build Coastguard Worker    close(SRC);
1193*1208bc7eSAndroid Build Coastguard Worker  } else {
1194*1208bc7eSAndroid Build Coastguard Worker    # --raw/http: For everything to work correctly for non-remote profiles, we
1195*1208bc7eSAndroid Build Coastguard Worker    # would need to extend PrintProfileData() to handle all possible profile
1196*1208bc7eSAndroid Build Coastguard Worker    # types, re-enable the code that is currently disabled in ReadCPUProfile()
1197*1208bc7eSAndroid Build Coastguard Worker    # and FixCallerAddresses(), and remove the remote profile dumping code in
1198*1208bc7eSAndroid Build Coastguard Worker    # the block above.
1199*1208bc7eSAndroid Build Coastguard Worker    die "--raw/http: jeprof can only dump remote profiles for --raw\n";
1200*1208bc7eSAndroid Build Coastguard Worker    # dump a cpu-format profile to standard out
1201*1208bc7eSAndroid Build Coastguard Worker    PrintProfileData($profile);
1202*1208bc7eSAndroid Build Coastguard Worker  }
1203*1208bc7eSAndroid Build Coastguard Worker}
1204*1208bc7eSAndroid Build Coastguard Worker
1205*1208bc7eSAndroid Build Coastguard Worker# Print text output
1206*1208bc7eSAndroid Build Coastguard Workersub PrintText {
1207*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
1208*1208bc7eSAndroid Build Coastguard Worker  my $flat = shift;
1209*1208bc7eSAndroid Build Coastguard Worker  my $cumulative = shift;
1210*1208bc7eSAndroid Build Coastguard Worker  my $line_limit = shift;
1211*1208bc7eSAndroid Build Coastguard Worker
1212*1208bc7eSAndroid Build Coastguard Worker  my $total = TotalProfile($flat);
1213*1208bc7eSAndroid Build Coastguard Worker
1214*1208bc7eSAndroid Build Coastguard Worker  # Which profile to sort by?
1215*1208bc7eSAndroid Build Coastguard Worker  my $s = $main::opt_cum ? $cumulative : $flat;
1216*1208bc7eSAndroid Build Coastguard Worker
1217*1208bc7eSAndroid Build Coastguard Worker  my $running_sum = 0;
1218*1208bc7eSAndroid Build Coastguard Worker  my $lines = 0;
1219*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (sort { GetEntry($s, $b) <=> GetEntry($s, $a) || $a cmp $b }
1220*1208bc7eSAndroid Build Coastguard Worker                 keys(%{$cumulative})) {
1221*1208bc7eSAndroid Build Coastguard Worker    my $f = GetEntry($flat, $k);
1222*1208bc7eSAndroid Build Coastguard Worker    my $c = GetEntry($cumulative, $k);
1223*1208bc7eSAndroid Build Coastguard Worker    $running_sum += $f;
1224*1208bc7eSAndroid Build Coastguard Worker
1225*1208bc7eSAndroid Build Coastguard Worker    my $sym = $k;
1226*1208bc7eSAndroid Build Coastguard Worker    if (exists($symbols->{$k})) {
1227*1208bc7eSAndroid Build Coastguard Worker      $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1];
1228*1208bc7eSAndroid Build Coastguard Worker      if ($main::opt_addresses) {
1229*1208bc7eSAndroid Build Coastguard Worker        $sym = $k . " " . $sym;
1230*1208bc7eSAndroid Build Coastguard Worker      }
1231*1208bc7eSAndroid Build Coastguard Worker    }
1232*1208bc7eSAndroid Build Coastguard Worker
1233*1208bc7eSAndroid Build Coastguard Worker    if ($f != 0 || $c != 0) {
1234*1208bc7eSAndroid Build Coastguard Worker      printf("%8s %6s %6s %8s %6s %s\n",
1235*1208bc7eSAndroid Build Coastguard Worker             Unparse($f),
1236*1208bc7eSAndroid Build Coastguard Worker             Percent($f, $total),
1237*1208bc7eSAndroid Build Coastguard Worker             Percent($running_sum, $total),
1238*1208bc7eSAndroid Build Coastguard Worker             Unparse($c),
1239*1208bc7eSAndroid Build Coastguard Worker             Percent($c, $total),
1240*1208bc7eSAndroid Build Coastguard Worker             $sym);
1241*1208bc7eSAndroid Build Coastguard Worker    }
1242*1208bc7eSAndroid Build Coastguard Worker    $lines++;
1243*1208bc7eSAndroid Build Coastguard Worker    last if ($line_limit >= 0 && $lines >= $line_limit);
1244*1208bc7eSAndroid Build Coastguard Worker  }
1245*1208bc7eSAndroid Build Coastguard Worker}
1246*1208bc7eSAndroid Build Coastguard Worker
1247*1208bc7eSAndroid Build Coastguard Worker# Callgrind format has a compression for repeated function and file
1248*1208bc7eSAndroid Build Coastguard Worker# names.  You show the name the first time, and just use its number
1249*1208bc7eSAndroid Build Coastguard Worker# subsequently.  This can cut down the file to about a third or a
1250*1208bc7eSAndroid Build Coastguard Worker# quarter of its uncompressed size.  $key and $val are the key/value
1251*1208bc7eSAndroid Build Coastguard Worker# pair that would normally be printed by callgrind; $map is a map from
1252*1208bc7eSAndroid Build Coastguard Worker# value to number.
1253*1208bc7eSAndroid Build Coastguard Workersub CompressedCGName {
1254*1208bc7eSAndroid Build Coastguard Worker  my($key, $val, $map) = @_;
1255*1208bc7eSAndroid Build Coastguard Worker  my $idx = $map->{$val};
1256*1208bc7eSAndroid Build Coastguard Worker  # For very short keys, providing an index hurts rather than helps.
1257*1208bc7eSAndroid Build Coastguard Worker  if (length($val) <= 3) {
1258*1208bc7eSAndroid Build Coastguard Worker    return "$key=$val\n";
1259*1208bc7eSAndroid Build Coastguard Worker  } elsif (defined($idx)) {
1260*1208bc7eSAndroid Build Coastguard Worker    return "$key=($idx)\n";
1261*1208bc7eSAndroid Build Coastguard Worker  } else {
1262*1208bc7eSAndroid Build Coastguard Worker    # scalar(keys $map) gives the number of items in the map.
1263*1208bc7eSAndroid Build Coastguard Worker    $idx = scalar(keys(%{$map})) + 1;
1264*1208bc7eSAndroid Build Coastguard Worker    $map->{$val} = $idx;
1265*1208bc7eSAndroid Build Coastguard Worker    return "$key=($idx) $val\n";
1266*1208bc7eSAndroid Build Coastguard Worker  }
1267*1208bc7eSAndroid Build Coastguard Worker}
1268*1208bc7eSAndroid Build Coastguard Worker
1269*1208bc7eSAndroid Build Coastguard Worker# Print the call graph in a way that's suiteable for callgrind.
1270*1208bc7eSAndroid Build Coastguard Workersub PrintCallgrind {
1271*1208bc7eSAndroid Build Coastguard Worker  my $calls = shift;
1272*1208bc7eSAndroid Build Coastguard Worker  my $filename;
1273*1208bc7eSAndroid Build Coastguard Worker  my %filename_to_index_map;
1274*1208bc7eSAndroid Build Coastguard Worker  my %fnname_to_index_map;
1275*1208bc7eSAndroid Build Coastguard Worker
1276*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_interactive) {
1277*1208bc7eSAndroid Build Coastguard Worker    $filename = shift;
1278*1208bc7eSAndroid Build Coastguard Worker    print STDERR "Writing callgrind file to '$filename'.\n"
1279*1208bc7eSAndroid Build Coastguard Worker  } else {
1280*1208bc7eSAndroid Build Coastguard Worker    $filename = "&STDOUT";
1281*1208bc7eSAndroid Build Coastguard Worker  }
1282*1208bc7eSAndroid Build Coastguard Worker  open(CG, ">$filename");
1283*1208bc7eSAndroid Build Coastguard Worker  printf CG ("events: Hits\n\n");
1284*1208bc7eSAndroid Build Coastguard Worker  foreach my $call ( map { $_->[0] }
1285*1208bc7eSAndroid Build Coastguard Worker                     sort { $a->[1] cmp $b ->[1] ||
1286*1208bc7eSAndroid Build Coastguard Worker                            $a->[2] <=> $b->[2] }
1287*1208bc7eSAndroid Build Coastguard Worker                     map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
1288*1208bc7eSAndroid Build Coastguard Worker                           [$_, $1, $2] }
1289*1208bc7eSAndroid Build Coastguard Worker                     keys %$calls ) {
1290*1208bc7eSAndroid Build Coastguard Worker    my $count = int($calls->{$call});
1291*1208bc7eSAndroid Build Coastguard Worker    $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
1292*1208bc7eSAndroid Build Coastguard Worker    my ( $caller_file, $caller_line, $caller_function,
1293*1208bc7eSAndroid Build Coastguard Worker         $callee_file, $callee_line, $callee_function ) =
1294*1208bc7eSAndroid Build Coastguard Worker       ( $1, $2, $3, $5, $6, $7 );
1295*1208bc7eSAndroid Build Coastguard Worker
1296*1208bc7eSAndroid Build Coastguard Worker    # TODO(csilvers): for better compression, collect all the
1297*1208bc7eSAndroid Build Coastguard Worker    # caller/callee_files and functions first, before printing
1298*1208bc7eSAndroid Build Coastguard Worker    # anything, and only compress those referenced more than once.
1299*1208bc7eSAndroid Build Coastguard Worker    printf CG CompressedCGName("fl", $caller_file, \%filename_to_index_map);
1300*1208bc7eSAndroid Build Coastguard Worker    printf CG CompressedCGName("fn", $caller_function, \%fnname_to_index_map);
1301*1208bc7eSAndroid Build Coastguard Worker    if (defined $6) {
1302*1208bc7eSAndroid Build Coastguard Worker      printf CG CompressedCGName("cfl", $callee_file, \%filename_to_index_map);
1303*1208bc7eSAndroid Build Coastguard Worker      printf CG CompressedCGName("cfn", $callee_function, \%fnname_to_index_map);
1304*1208bc7eSAndroid Build Coastguard Worker      printf CG ("calls=$count $callee_line\n");
1305*1208bc7eSAndroid Build Coastguard Worker    }
1306*1208bc7eSAndroid Build Coastguard Worker    printf CG ("$caller_line $count\n\n");
1307*1208bc7eSAndroid Build Coastguard Worker  }
1308*1208bc7eSAndroid Build Coastguard Worker}
1309*1208bc7eSAndroid Build Coastguard Worker
1310*1208bc7eSAndroid Build Coastguard Worker# Print disassembly for all all routines that match $main::opt_disasm
1311*1208bc7eSAndroid Build Coastguard Workersub PrintDisassembly {
1312*1208bc7eSAndroid Build Coastguard Worker  my $libs = shift;
1313*1208bc7eSAndroid Build Coastguard Worker  my $flat = shift;
1314*1208bc7eSAndroid Build Coastguard Worker  my $cumulative = shift;
1315*1208bc7eSAndroid Build Coastguard Worker  my $disasm_opts = shift;
1316*1208bc7eSAndroid Build Coastguard Worker
1317*1208bc7eSAndroid Build Coastguard Worker  my $total = TotalProfile($flat);
1318*1208bc7eSAndroid Build Coastguard Worker
1319*1208bc7eSAndroid Build Coastguard Worker  foreach my $lib (@{$libs}) {
1320*1208bc7eSAndroid Build Coastguard Worker    my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts);
1321*1208bc7eSAndroid Build Coastguard Worker    my $offset = AddressSub($lib->[1], $lib->[3]);
1322*1208bc7eSAndroid Build Coastguard Worker    foreach my $routine (sort ByName keys(%{$symbol_table})) {
1323*1208bc7eSAndroid Build Coastguard Worker      my $start_addr = $symbol_table->{$routine}->[0];
1324*1208bc7eSAndroid Build Coastguard Worker      my $end_addr = $symbol_table->{$routine}->[1];
1325*1208bc7eSAndroid Build Coastguard Worker      # See if there are any samples in this routine
1326*1208bc7eSAndroid Build Coastguard Worker      my $length = hex(AddressSub($end_addr, $start_addr));
1327*1208bc7eSAndroid Build Coastguard Worker      my $addr = AddressAdd($start_addr, $offset);
1328*1208bc7eSAndroid Build Coastguard Worker      for (my $i = 0; $i < $length; $i++) {
1329*1208bc7eSAndroid Build Coastguard Worker        if (defined($cumulative->{$addr})) {
1330*1208bc7eSAndroid Build Coastguard Worker          PrintDisassembledFunction($lib->[0], $offset,
1331*1208bc7eSAndroid Build Coastguard Worker                                    $routine, $flat, $cumulative,
1332*1208bc7eSAndroid Build Coastguard Worker                                    $start_addr, $end_addr, $total);
1333*1208bc7eSAndroid Build Coastguard Worker          last;
1334*1208bc7eSAndroid Build Coastguard Worker        }
1335*1208bc7eSAndroid Build Coastguard Worker        $addr = AddressInc($addr);
1336*1208bc7eSAndroid Build Coastguard Worker      }
1337*1208bc7eSAndroid Build Coastguard Worker    }
1338*1208bc7eSAndroid Build Coastguard Worker  }
1339*1208bc7eSAndroid Build Coastguard Worker}
1340*1208bc7eSAndroid Build Coastguard Worker
1341*1208bc7eSAndroid Build Coastguard Worker# Return reference to array of tuples of the form:
1342*1208bc7eSAndroid Build Coastguard Worker#       [start_address, filename, linenumber, instruction, limit_address]
1343*1208bc7eSAndroid Build Coastguard Worker# E.g.,
1344*1208bc7eSAndroid Build Coastguard Worker#       ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"]
1345*1208bc7eSAndroid Build Coastguard Workersub Disassemble {
1346*1208bc7eSAndroid Build Coastguard Worker  my $prog = shift;
1347*1208bc7eSAndroid Build Coastguard Worker  my $offset = shift;
1348*1208bc7eSAndroid Build Coastguard Worker  my $start_addr = shift;
1349*1208bc7eSAndroid Build Coastguard Worker  my $end_addr = shift;
1350*1208bc7eSAndroid Build Coastguard Worker
1351*1208bc7eSAndroid Build Coastguard Worker  my $objdump = $obj_tool_map{"objdump"};
1352*1208bc7eSAndroid Build Coastguard Worker  my $cmd = ShellEscape($objdump, "-C", "-d", "-l", "--no-show-raw-insn",
1353*1208bc7eSAndroid Build Coastguard Worker                        "--start-address=0x$start_addr",
1354*1208bc7eSAndroid Build Coastguard Worker                        "--stop-address=0x$end_addr", $prog);
1355*1208bc7eSAndroid Build Coastguard Worker  open(OBJDUMP, "$cmd |") || error("$cmd: $!\n");
1356*1208bc7eSAndroid Build Coastguard Worker  my @result = ();
1357*1208bc7eSAndroid Build Coastguard Worker  my $filename = "";
1358*1208bc7eSAndroid Build Coastguard Worker  my $linenumber = -1;
1359*1208bc7eSAndroid Build Coastguard Worker  my $last = ["", "", "", ""];
1360*1208bc7eSAndroid Build Coastguard Worker  while (<OBJDUMP>) {
1361*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;         # turn windows-looking lines into unix-looking lines
1362*1208bc7eSAndroid Build Coastguard Worker    chop;
1363*1208bc7eSAndroid Build Coastguard Worker    if (m|\s*([^:\s]+):(\d+)\s*$|) {
1364*1208bc7eSAndroid Build Coastguard Worker      # Location line of the form:
1365*1208bc7eSAndroid Build Coastguard Worker      #   <filename>:<linenumber>
1366*1208bc7eSAndroid Build Coastguard Worker      $filename = $1;
1367*1208bc7eSAndroid Build Coastguard Worker      $linenumber = $2;
1368*1208bc7eSAndroid Build Coastguard Worker    } elsif (m/^ +([0-9a-f]+):\s*(.*)/) {
1369*1208bc7eSAndroid Build Coastguard Worker      # Disassembly line -- zero-extend address to full length
1370*1208bc7eSAndroid Build Coastguard Worker      my $addr = HexExtend($1);
1371*1208bc7eSAndroid Build Coastguard Worker      my $k = AddressAdd($addr, $offset);
1372*1208bc7eSAndroid Build Coastguard Worker      $last->[4] = $k;   # Store ending address for previous instruction
1373*1208bc7eSAndroid Build Coastguard Worker      $last = [$k, $filename, $linenumber, $2, $end_addr];
1374*1208bc7eSAndroid Build Coastguard Worker      push(@result, $last);
1375*1208bc7eSAndroid Build Coastguard Worker    }
1376*1208bc7eSAndroid Build Coastguard Worker  }
1377*1208bc7eSAndroid Build Coastguard Worker  close(OBJDUMP);
1378*1208bc7eSAndroid Build Coastguard Worker  return @result;
1379*1208bc7eSAndroid Build Coastguard Worker}
1380*1208bc7eSAndroid Build Coastguard Worker
1381*1208bc7eSAndroid Build Coastguard Worker# The input file should contain lines of the form /proc/maps-like
1382*1208bc7eSAndroid Build Coastguard Worker# output (same format as expected from the profiles) or that looks
1383*1208bc7eSAndroid Build Coastguard Worker# like hex addresses (like "0xDEADBEEF").  We will parse all
1384*1208bc7eSAndroid Build Coastguard Worker# /proc/maps output, and for all the hex addresses, we will output
1385*1208bc7eSAndroid Build Coastguard Worker# "short" symbol names, one per line, in the same order as the input.
1386*1208bc7eSAndroid Build Coastguard Workersub PrintSymbols {
1387*1208bc7eSAndroid Build Coastguard Worker  my $maps_and_symbols_file = shift;
1388*1208bc7eSAndroid Build Coastguard Worker
1389*1208bc7eSAndroid Build Coastguard Worker  # ParseLibraries expects pcs to be in a set.  Fine by us...
1390*1208bc7eSAndroid Build Coastguard Worker  my @pclist = ();   # pcs in sorted order
1391*1208bc7eSAndroid Build Coastguard Worker  my $pcs = {};
1392*1208bc7eSAndroid Build Coastguard Worker  my $map = "";
1393*1208bc7eSAndroid Build Coastguard Worker  foreach my $line (<$maps_and_symbols_file>) {
1394*1208bc7eSAndroid Build Coastguard Worker    $line =~ s/\r//g;    # turn windows-looking lines into unix-looking lines
1395*1208bc7eSAndroid Build Coastguard Worker    if ($line =~ /\b(0x[0-9a-f]+)\b/i) {
1396*1208bc7eSAndroid Build Coastguard Worker      push(@pclist, HexExtend($1));
1397*1208bc7eSAndroid Build Coastguard Worker      $pcs->{$pclist[-1]} = 1;
1398*1208bc7eSAndroid Build Coastguard Worker    } else {
1399*1208bc7eSAndroid Build Coastguard Worker      $map .= $line;
1400*1208bc7eSAndroid Build Coastguard Worker    }
1401*1208bc7eSAndroid Build Coastguard Worker  }
1402*1208bc7eSAndroid Build Coastguard Worker
1403*1208bc7eSAndroid Build Coastguard Worker  my $libs = ParseLibraries($main::prog, $map, $pcs);
1404*1208bc7eSAndroid Build Coastguard Worker  my $symbols = ExtractSymbols($libs, $pcs);
1405*1208bc7eSAndroid Build Coastguard Worker
1406*1208bc7eSAndroid Build Coastguard Worker  foreach my $pc (@pclist) {
1407*1208bc7eSAndroid Build Coastguard Worker    # ->[0] is the shortname, ->[2] is the full name
1408*1208bc7eSAndroid Build Coastguard Worker    print(($symbols->{$pc}->[0] || "??") . "\n");
1409*1208bc7eSAndroid Build Coastguard Worker  }
1410*1208bc7eSAndroid Build Coastguard Worker}
1411*1208bc7eSAndroid Build Coastguard Worker
1412*1208bc7eSAndroid Build Coastguard Worker
1413*1208bc7eSAndroid Build Coastguard Worker# For sorting functions by name
1414*1208bc7eSAndroid Build Coastguard Workersub ByName {
1415*1208bc7eSAndroid Build Coastguard Worker  return ShortFunctionName($a) cmp ShortFunctionName($b);
1416*1208bc7eSAndroid Build Coastguard Worker}
1417*1208bc7eSAndroid Build Coastguard Worker
1418*1208bc7eSAndroid Build Coastguard Worker# Print source-listing for all all routines that match $list_opts
1419*1208bc7eSAndroid Build Coastguard Workersub PrintListing {
1420*1208bc7eSAndroid Build Coastguard Worker  my $total = shift;
1421*1208bc7eSAndroid Build Coastguard Worker  my $libs = shift;
1422*1208bc7eSAndroid Build Coastguard Worker  my $flat = shift;
1423*1208bc7eSAndroid Build Coastguard Worker  my $cumulative = shift;
1424*1208bc7eSAndroid Build Coastguard Worker  my $list_opts = shift;
1425*1208bc7eSAndroid Build Coastguard Worker  my $html = shift;
1426*1208bc7eSAndroid Build Coastguard Worker
1427*1208bc7eSAndroid Build Coastguard Worker  my $output = \*STDOUT;
1428*1208bc7eSAndroid Build Coastguard Worker  my $fname = "";
1429*1208bc7eSAndroid Build Coastguard Worker
1430*1208bc7eSAndroid Build Coastguard Worker  if ($html) {
1431*1208bc7eSAndroid Build Coastguard Worker    # Arrange to write the output to a temporary file
1432*1208bc7eSAndroid Build Coastguard Worker    $fname = TempName($main::next_tmpfile, "html");
1433*1208bc7eSAndroid Build Coastguard Worker    $main::next_tmpfile++;
1434*1208bc7eSAndroid Build Coastguard Worker    if (!open(TEMP, ">$fname")) {
1435*1208bc7eSAndroid Build Coastguard Worker      print STDERR "$fname: $!\n";
1436*1208bc7eSAndroid Build Coastguard Worker      return;
1437*1208bc7eSAndroid Build Coastguard Worker    }
1438*1208bc7eSAndroid Build Coastguard Worker    $output = \*TEMP;
1439*1208bc7eSAndroid Build Coastguard Worker    print $output HtmlListingHeader();
1440*1208bc7eSAndroid Build Coastguard Worker    printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
1441*1208bc7eSAndroid Build Coastguard Worker                    $main::prog, Unparse($total), Units());
1442*1208bc7eSAndroid Build Coastguard Worker  }
1443*1208bc7eSAndroid Build Coastguard Worker
1444*1208bc7eSAndroid Build Coastguard Worker  my $listed = 0;
1445*1208bc7eSAndroid Build Coastguard Worker  foreach my $lib (@{$libs}) {
1446*1208bc7eSAndroid Build Coastguard Worker    my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
1447*1208bc7eSAndroid Build Coastguard Worker    my $offset = AddressSub($lib->[1], $lib->[3]);
1448*1208bc7eSAndroid Build Coastguard Worker    foreach my $routine (sort ByName keys(%{$symbol_table})) {
1449*1208bc7eSAndroid Build Coastguard Worker      # Print if there are any samples in this routine
1450*1208bc7eSAndroid Build Coastguard Worker      my $start_addr = $symbol_table->{$routine}->[0];
1451*1208bc7eSAndroid Build Coastguard Worker      my $end_addr = $symbol_table->{$routine}->[1];
1452*1208bc7eSAndroid Build Coastguard Worker      my $length = hex(AddressSub($end_addr, $start_addr));
1453*1208bc7eSAndroid Build Coastguard Worker      my $addr = AddressAdd($start_addr, $offset);
1454*1208bc7eSAndroid Build Coastguard Worker      for (my $i = 0; $i < $length; $i++) {
1455*1208bc7eSAndroid Build Coastguard Worker        if (defined($cumulative->{$addr})) {
1456*1208bc7eSAndroid Build Coastguard Worker          $listed += PrintSource(
1457*1208bc7eSAndroid Build Coastguard Worker            $lib->[0], $offset,
1458*1208bc7eSAndroid Build Coastguard Worker            $routine, $flat, $cumulative,
1459*1208bc7eSAndroid Build Coastguard Worker            $start_addr, $end_addr,
1460*1208bc7eSAndroid Build Coastguard Worker            $html,
1461*1208bc7eSAndroid Build Coastguard Worker            $output);
1462*1208bc7eSAndroid Build Coastguard Worker          last;
1463*1208bc7eSAndroid Build Coastguard Worker        }
1464*1208bc7eSAndroid Build Coastguard Worker        $addr = AddressInc($addr);
1465*1208bc7eSAndroid Build Coastguard Worker      }
1466*1208bc7eSAndroid Build Coastguard Worker    }
1467*1208bc7eSAndroid Build Coastguard Worker  }
1468*1208bc7eSAndroid Build Coastguard Worker
1469*1208bc7eSAndroid Build Coastguard Worker  if ($html) {
1470*1208bc7eSAndroid Build Coastguard Worker    if ($listed > 0) {
1471*1208bc7eSAndroid Build Coastguard Worker      print $output HtmlListingFooter();
1472*1208bc7eSAndroid Build Coastguard Worker      close($output);
1473*1208bc7eSAndroid Build Coastguard Worker      RunWeb($fname);
1474*1208bc7eSAndroid Build Coastguard Worker    } else {
1475*1208bc7eSAndroid Build Coastguard Worker      close($output);
1476*1208bc7eSAndroid Build Coastguard Worker      unlink($fname);
1477*1208bc7eSAndroid Build Coastguard Worker    }
1478*1208bc7eSAndroid Build Coastguard Worker  }
1479*1208bc7eSAndroid Build Coastguard Worker}
1480*1208bc7eSAndroid Build Coastguard Worker
1481*1208bc7eSAndroid Build Coastguard Workersub HtmlListingHeader {
1482*1208bc7eSAndroid Build Coastguard Worker  return <<'EOF';
1483*1208bc7eSAndroid Build Coastguard Worker<DOCTYPE html>
1484*1208bc7eSAndroid Build Coastguard Worker<html>
1485*1208bc7eSAndroid Build Coastguard Worker<head>
1486*1208bc7eSAndroid Build Coastguard Worker<title>Pprof listing</title>
1487*1208bc7eSAndroid Build Coastguard Worker<style type="text/css">
1488*1208bc7eSAndroid Build Coastguard Workerbody {
1489*1208bc7eSAndroid Build Coastguard Worker  font-family: sans-serif;
1490*1208bc7eSAndroid Build Coastguard Worker}
1491*1208bc7eSAndroid Build Coastguard Workerh1 {
1492*1208bc7eSAndroid Build Coastguard Worker  font-size: 1.5em;
1493*1208bc7eSAndroid Build Coastguard Worker  margin-bottom: 4px;
1494*1208bc7eSAndroid Build Coastguard Worker}
1495*1208bc7eSAndroid Build Coastguard Worker.legend {
1496*1208bc7eSAndroid Build Coastguard Worker  font-size: 1.25em;
1497*1208bc7eSAndroid Build Coastguard Worker}
1498*1208bc7eSAndroid Build Coastguard Worker.line {
1499*1208bc7eSAndroid Build Coastguard Worker  color: #aaaaaa;
1500*1208bc7eSAndroid Build Coastguard Worker}
1501*1208bc7eSAndroid Build Coastguard Worker.nop {
1502*1208bc7eSAndroid Build Coastguard Worker  color: #aaaaaa;
1503*1208bc7eSAndroid Build Coastguard Worker}
1504*1208bc7eSAndroid Build Coastguard Worker.unimportant {
1505*1208bc7eSAndroid Build Coastguard Worker  color: #cccccc;
1506*1208bc7eSAndroid Build Coastguard Worker}
1507*1208bc7eSAndroid Build Coastguard Worker.disasmloc {
1508*1208bc7eSAndroid Build Coastguard Worker  color: #000000;
1509*1208bc7eSAndroid Build Coastguard Worker}
1510*1208bc7eSAndroid Build Coastguard Worker.deadsrc {
1511*1208bc7eSAndroid Build Coastguard Worker  cursor: pointer;
1512*1208bc7eSAndroid Build Coastguard Worker}
1513*1208bc7eSAndroid Build Coastguard Worker.deadsrc:hover {
1514*1208bc7eSAndroid Build Coastguard Worker  background-color: #eeeeee;
1515*1208bc7eSAndroid Build Coastguard Worker}
1516*1208bc7eSAndroid Build Coastguard Worker.livesrc {
1517*1208bc7eSAndroid Build Coastguard Worker  color: #0000ff;
1518*1208bc7eSAndroid Build Coastguard Worker  cursor: pointer;
1519*1208bc7eSAndroid Build Coastguard Worker}
1520*1208bc7eSAndroid Build Coastguard Worker.livesrc:hover {
1521*1208bc7eSAndroid Build Coastguard Worker  background-color: #eeeeee;
1522*1208bc7eSAndroid Build Coastguard Worker}
1523*1208bc7eSAndroid Build Coastguard Worker.asm {
1524*1208bc7eSAndroid Build Coastguard Worker  color: #008800;
1525*1208bc7eSAndroid Build Coastguard Worker  display: none;
1526*1208bc7eSAndroid Build Coastguard Worker}
1527*1208bc7eSAndroid Build Coastguard Worker</style>
1528*1208bc7eSAndroid Build Coastguard Worker<script type="text/javascript">
1529*1208bc7eSAndroid Build Coastguard Workerfunction jeprof_toggle_asm(e) {
1530*1208bc7eSAndroid Build Coastguard Worker  var target;
1531*1208bc7eSAndroid Build Coastguard Worker  if (!e) e = window.event;
1532*1208bc7eSAndroid Build Coastguard Worker  if (e.target) target = e.target;
1533*1208bc7eSAndroid Build Coastguard Worker  else if (e.srcElement) target = e.srcElement;
1534*1208bc7eSAndroid Build Coastguard Worker
1535*1208bc7eSAndroid Build Coastguard Worker  if (target) {
1536*1208bc7eSAndroid Build Coastguard Worker    var asm = target.nextSibling;
1537*1208bc7eSAndroid Build Coastguard Worker    if (asm && asm.className == "asm") {
1538*1208bc7eSAndroid Build Coastguard Worker      asm.style.display = (asm.style.display == "block" ? "" : "block");
1539*1208bc7eSAndroid Build Coastguard Worker      e.preventDefault();
1540*1208bc7eSAndroid Build Coastguard Worker      return false;
1541*1208bc7eSAndroid Build Coastguard Worker    }
1542*1208bc7eSAndroid Build Coastguard Worker  }
1543*1208bc7eSAndroid Build Coastguard Worker}
1544*1208bc7eSAndroid Build Coastguard Worker</script>
1545*1208bc7eSAndroid Build Coastguard Worker</head>
1546*1208bc7eSAndroid Build Coastguard Worker<body>
1547*1208bc7eSAndroid Build Coastguard WorkerEOF
1548*1208bc7eSAndroid Build Coastguard Worker}
1549*1208bc7eSAndroid Build Coastguard Worker
1550*1208bc7eSAndroid Build Coastguard Workersub HtmlListingFooter {
1551*1208bc7eSAndroid Build Coastguard Worker  return <<'EOF';
1552*1208bc7eSAndroid Build Coastguard Worker</body>
1553*1208bc7eSAndroid Build Coastguard Worker</html>
1554*1208bc7eSAndroid Build Coastguard WorkerEOF
1555*1208bc7eSAndroid Build Coastguard Worker}
1556*1208bc7eSAndroid Build Coastguard Worker
1557*1208bc7eSAndroid Build Coastguard Workersub HtmlEscape {
1558*1208bc7eSAndroid Build Coastguard Worker  my $text = shift;
1559*1208bc7eSAndroid Build Coastguard Worker  $text =~ s/&/&amp;/g;
1560*1208bc7eSAndroid Build Coastguard Worker  $text =~ s/</&lt;/g;
1561*1208bc7eSAndroid Build Coastguard Worker  $text =~ s/>/&gt;/g;
1562*1208bc7eSAndroid Build Coastguard Worker  return $text;
1563*1208bc7eSAndroid Build Coastguard Worker}
1564*1208bc7eSAndroid Build Coastguard Worker
1565*1208bc7eSAndroid Build Coastguard Worker# Returns the indentation of the line, if it has any non-whitespace
1566*1208bc7eSAndroid Build Coastguard Worker# characters.  Otherwise, returns -1.
1567*1208bc7eSAndroid Build Coastguard Workersub Indentation {
1568*1208bc7eSAndroid Build Coastguard Worker  my $line = shift;
1569*1208bc7eSAndroid Build Coastguard Worker  if (m/^(\s*)\S/) {
1570*1208bc7eSAndroid Build Coastguard Worker    return length($1);
1571*1208bc7eSAndroid Build Coastguard Worker  } else {
1572*1208bc7eSAndroid Build Coastguard Worker    return -1;
1573*1208bc7eSAndroid Build Coastguard Worker  }
1574*1208bc7eSAndroid Build Coastguard Worker}
1575*1208bc7eSAndroid Build Coastguard Worker
1576*1208bc7eSAndroid Build Coastguard Worker# If the symbol table contains inlining info, Disassemble() may tag an
1577*1208bc7eSAndroid Build Coastguard Worker# instruction with a location inside an inlined function.  But for
1578*1208bc7eSAndroid Build Coastguard Worker# source listings, we prefer to use the location in the function we
1579*1208bc7eSAndroid Build Coastguard Worker# are listing.  So use MapToSymbols() to fetch full location
1580*1208bc7eSAndroid Build Coastguard Worker# information for each instruction and then pick out the first
1581*1208bc7eSAndroid Build Coastguard Worker# location from a location list (location list contains callers before
1582*1208bc7eSAndroid Build Coastguard Worker# callees in case of inlining).
1583*1208bc7eSAndroid Build Coastguard Worker#
1584*1208bc7eSAndroid Build Coastguard Worker# After this routine has run, each entry in $instructions contains:
1585*1208bc7eSAndroid Build Coastguard Worker#   [0] start address
1586*1208bc7eSAndroid Build Coastguard Worker#   [1] filename for function we are listing
1587*1208bc7eSAndroid Build Coastguard Worker#   [2] line number for function we are listing
1588*1208bc7eSAndroid Build Coastguard Worker#   [3] disassembly
1589*1208bc7eSAndroid Build Coastguard Worker#   [4] limit address
1590*1208bc7eSAndroid Build Coastguard Worker#   [5] most specific filename (may be different from [1] due to inlining)
1591*1208bc7eSAndroid Build Coastguard Worker#   [6] most specific line number (may be different from [2] due to inlining)
1592*1208bc7eSAndroid Build Coastguard Workersub GetTopLevelLineNumbers {
1593*1208bc7eSAndroid Build Coastguard Worker  my ($lib, $offset, $instructions) = @_;
1594*1208bc7eSAndroid Build Coastguard Worker  my $pcs = [];
1595*1208bc7eSAndroid Build Coastguard Worker  for (my $i = 0; $i <= $#{$instructions}; $i++) {
1596*1208bc7eSAndroid Build Coastguard Worker    push(@{$pcs}, $instructions->[$i]->[0]);
1597*1208bc7eSAndroid Build Coastguard Worker  }
1598*1208bc7eSAndroid Build Coastguard Worker  my $symbols = {};
1599*1208bc7eSAndroid Build Coastguard Worker  MapToSymbols($lib, $offset, $pcs, $symbols);
1600*1208bc7eSAndroid Build Coastguard Worker  for (my $i = 0; $i <= $#{$instructions}; $i++) {
1601*1208bc7eSAndroid Build Coastguard Worker    my $e = $instructions->[$i];
1602*1208bc7eSAndroid Build Coastguard Worker    push(@{$e}, $e->[1]);
1603*1208bc7eSAndroid Build Coastguard Worker    push(@{$e}, $e->[2]);
1604*1208bc7eSAndroid Build Coastguard Worker    my $addr = $e->[0];
1605*1208bc7eSAndroid Build Coastguard Worker    my $sym = $symbols->{$addr};
1606*1208bc7eSAndroid Build Coastguard Worker    if (defined($sym)) {
1607*1208bc7eSAndroid Build Coastguard Worker      if ($#{$sym} >= 2 && $sym->[1] =~ m/^(.*):(\d+)$/) {
1608*1208bc7eSAndroid Build Coastguard Worker        $e->[1] = $1;  # File name
1609*1208bc7eSAndroid Build Coastguard Worker        $e->[2] = $2;  # Line number
1610*1208bc7eSAndroid Build Coastguard Worker      }
1611*1208bc7eSAndroid Build Coastguard Worker    }
1612*1208bc7eSAndroid Build Coastguard Worker  }
1613*1208bc7eSAndroid Build Coastguard Worker}
1614*1208bc7eSAndroid Build Coastguard Worker
1615*1208bc7eSAndroid Build Coastguard Worker# Print source-listing for one routine
1616*1208bc7eSAndroid Build Coastguard Workersub PrintSource {
1617*1208bc7eSAndroid Build Coastguard Worker  my $prog = shift;
1618*1208bc7eSAndroid Build Coastguard Worker  my $offset = shift;
1619*1208bc7eSAndroid Build Coastguard Worker  my $routine = shift;
1620*1208bc7eSAndroid Build Coastguard Worker  my $flat = shift;
1621*1208bc7eSAndroid Build Coastguard Worker  my $cumulative = shift;
1622*1208bc7eSAndroid Build Coastguard Worker  my $start_addr = shift;
1623*1208bc7eSAndroid Build Coastguard Worker  my $end_addr = shift;
1624*1208bc7eSAndroid Build Coastguard Worker  my $html = shift;
1625*1208bc7eSAndroid Build Coastguard Worker  my $output = shift;
1626*1208bc7eSAndroid Build Coastguard Worker
1627*1208bc7eSAndroid Build Coastguard Worker  # Disassemble all instructions (just to get line numbers)
1628*1208bc7eSAndroid Build Coastguard Worker  my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
1629*1208bc7eSAndroid Build Coastguard Worker  GetTopLevelLineNumbers($prog, $offset, \@instructions);
1630*1208bc7eSAndroid Build Coastguard Worker
1631*1208bc7eSAndroid Build Coastguard Worker  # Hack 1: assume that the first source file encountered in the
1632*1208bc7eSAndroid Build Coastguard Worker  # disassembly contains the routine
1633*1208bc7eSAndroid Build Coastguard Worker  my $filename = undef;
1634*1208bc7eSAndroid Build Coastguard Worker  for (my $i = 0; $i <= $#instructions; $i++) {
1635*1208bc7eSAndroid Build Coastguard Worker    if ($instructions[$i]->[2] >= 0) {
1636*1208bc7eSAndroid Build Coastguard Worker      $filename = $instructions[$i]->[1];
1637*1208bc7eSAndroid Build Coastguard Worker      last;
1638*1208bc7eSAndroid Build Coastguard Worker    }
1639*1208bc7eSAndroid Build Coastguard Worker  }
1640*1208bc7eSAndroid Build Coastguard Worker  if (!defined($filename)) {
1641*1208bc7eSAndroid Build Coastguard Worker    print STDERR "no filename found in $routine\n";
1642*1208bc7eSAndroid Build Coastguard Worker    return 0;
1643*1208bc7eSAndroid Build Coastguard Worker  }
1644*1208bc7eSAndroid Build Coastguard Worker
1645*1208bc7eSAndroid Build Coastguard Worker  # Hack 2: assume that the largest line number from $filename is the
1646*1208bc7eSAndroid Build Coastguard Worker  # end of the procedure.  This is typically safe since if P1 contains
1647*1208bc7eSAndroid Build Coastguard Worker  # an inlined call to P2, then P2 usually occurs earlier in the
1648*1208bc7eSAndroid Build Coastguard Worker  # source file.  If this does not work, we might have to compute a
1649*1208bc7eSAndroid Build Coastguard Worker  # density profile or just print all regions we find.
1650*1208bc7eSAndroid Build Coastguard Worker  my $lastline = 0;
1651*1208bc7eSAndroid Build Coastguard Worker  for (my $i = 0; $i <= $#instructions; $i++) {
1652*1208bc7eSAndroid Build Coastguard Worker    my $f = $instructions[$i]->[1];
1653*1208bc7eSAndroid Build Coastguard Worker    my $l = $instructions[$i]->[2];
1654*1208bc7eSAndroid Build Coastguard Worker    if (($f eq $filename) && ($l > $lastline)) {
1655*1208bc7eSAndroid Build Coastguard Worker      $lastline = $l;
1656*1208bc7eSAndroid Build Coastguard Worker    }
1657*1208bc7eSAndroid Build Coastguard Worker  }
1658*1208bc7eSAndroid Build Coastguard Worker
1659*1208bc7eSAndroid Build Coastguard Worker  # Hack 3: assume the first source location from "filename" is the start of
1660*1208bc7eSAndroid Build Coastguard Worker  # the source code.
1661*1208bc7eSAndroid Build Coastguard Worker  my $firstline = 1;
1662*1208bc7eSAndroid Build Coastguard Worker  for (my $i = 0; $i <= $#instructions; $i++) {
1663*1208bc7eSAndroid Build Coastguard Worker    if ($instructions[$i]->[1] eq $filename) {
1664*1208bc7eSAndroid Build Coastguard Worker      $firstline = $instructions[$i]->[2];
1665*1208bc7eSAndroid Build Coastguard Worker      last;
1666*1208bc7eSAndroid Build Coastguard Worker    }
1667*1208bc7eSAndroid Build Coastguard Worker  }
1668*1208bc7eSAndroid Build Coastguard Worker
1669*1208bc7eSAndroid Build Coastguard Worker  # Hack 4: Extend last line forward until its indentation is less than
1670*1208bc7eSAndroid Build Coastguard Worker  # the indentation we saw on $firstline
1671*1208bc7eSAndroid Build Coastguard Worker  my $oldlastline = $lastline;
1672*1208bc7eSAndroid Build Coastguard Worker  {
1673*1208bc7eSAndroid Build Coastguard Worker    if (!open(FILE, "<$filename")) {
1674*1208bc7eSAndroid Build Coastguard Worker      print STDERR "$filename: $!\n";
1675*1208bc7eSAndroid Build Coastguard Worker      return 0;
1676*1208bc7eSAndroid Build Coastguard Worker    }
1677*1208bc7eSAndroid Build Coastguard Worker    my $l = 0;
1678*1208bc7eSAndroid Build Coastguard Worker    my $first_indentation = -1;
1679*1208bc7eSAndroid Build Coastguard Worker    while (<FILE>) {
1680*1208bc7eSAndroid Build Coastguard Worker      s/\r//g;         # turn windows-looking lines into unix-looking lines
1681*1208bc7eSAndroid Build Coastguard Worker      $l++;
1682*1208bc7eSAndroid Build Coastguard Worker      my $indent = Indentation($_);
1683*1208bc7eSAndroid Build Coastguard Worker      if ($l >= $firstline) {
1684*1208bc7eSAndroid Build Coastguard Worker        if ($first_indentation < 0 && $indent >= 0) {
1685*1208bc7eSAndroid Build Coastguard Worker          $first_indentation = $indent;
1686*1208bc7eSAndroid Build Coastguard Worker          last if ($first_indentation == 0);
1687*1208bc7eSAndroid Build Coastguard Worker        }
1688*1208bc7eSAndroid Build Coastguard Worker      }
1689*1208bc7eSAndroid Build Coastguard Worker      if ($l >= $lastline && $indent >= 0) {
1690*1208bc7eSAndroid Build Coastguard Worker        if ($indent >= $first_indentation) {
1691*1208bc7eSAndroid Build Coastguard Worker          $lastline = $l+1;
1692*1208bc7eSAndroid Build Coastguard Worker        } else {
1693*1208bc7eSAndroid Build Coastguard Worker          last;
1694*1208bc7eSAndroid Build Coastguard Worker        }
1695*1208bc7eSAndroid Build Coastguard Worker      }
1696*1208bc7eSAndroid Build Coastguard Worker    }
1697*1208bc7eSAndroid Build Coastguard Worker    close(FILE);
1698*1208bc7eSAndroid Build Coastguard Worker  }
1699*1208bc7eSAndroid Build Coastguard Worker
1700*1208bc7eSAndroid Build Coastguard Worker  # Assign all samples to the range $firstline,$lastline,
1701*1208bc7eSAndroid Build Coastguard Worker  # Hack 4: If an instruction does not occur in the range, its samples
1702*1208bc7eSAndroid Build Coastguard Worker  # are moved to the next instruction that occurs in the range.
1703*1208bc7eSAndroid Build Coastguard Worker  my $samples1 = {};        # Map from line number to flat count
1704*1208bc7eSAndroid Build Coastguard Worker  my $samples2 = {};        # Map from line number to cumulative count
1705*1208bc7eSAndroid Build Coastguard Worker  my $running1 = 0;         # Unassigned flat counts
1706*1208bc7eSAndroid Build Coastguard Worker  my $running2 = 0;         # Unassigned cumulative counts
1707*1208bc7eSAndroid Build Coastguard Worker  my $total1 = 0;           # Total flat counts
1708*1208bc7eSAndroid Build Coastguard Worker  my $total2 = 0;           # Total cumulative counts
1709*1208bc7eSAndroid Build Coastguard Worker  my %disasm = ();          # Map from line number to disassembly
1710*1208bc7eSAndroid Build Coastguard Worker  my $running_disasm = "";  # Unassigned disassembly
1711*1208bc7eSAndroid Build Coastguard Worker  my $skip_marker = "---\n";
1712*1208bc7eSAndroid Build Coastguard Worker  if ($html) {
1713*1208bc7eSAndroid Build Coastguard Worker    $skip_marker = "";
1714*1208bc7eSAndroid Build Coastguard Worker    for (my $l = $firstline; $l <= $lastline; $l++) {
1715*1208bc7eSAndroid Build Coastguard Worker      $disasm{$l} = "";
1716*1208bc7eSAndroid Build Coastguard Worker    }
1717*1208bc7eSAndroid Build Coastguard Worker  }
1718*1208bc7eSAndroid Build Coastguard Worker  my $last_dis_filename = '';
1719*1208bc7eSAndroid Build Coastguard Worker  my $last_dis_linenum = -1;
1720*1208bc7eSAndroid Build Coastguard Worker  my $last_touched_line = -1;  # To detect gaps in disassembly for a line
1721*1208bc7eSAndroid Build Coastguard Worker  foreach my $e (@instructions) {
1722*1208bc7eSAndroid Build Coastguard Worker    # Add up counts for all address that fall inside this instruction
1723*1208bc7eSAndroid Build Coastguard Worker    my $c1 = 0;
1724*1208bc7eSAndroid Build Coastguard Worker    my $c2 = 0;
1725*1208bc7eSAndroid Build Coastguard Worker    for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
1726*1208bc7eSAndroid Build Coastguard Worker      $c1 += GetEntry($flat, $a);
1727*1208bc7eSAndroid Build Coastguard Worker      $c2 += GetEntry($cumulative, $a);
1728*1208bc7eSAndroid Build Coastguard Worker    }
1729*1208bc7eSAndroid Build Coastguard Worker
1730*1208bc7eSAndroid Build Coastguard Worker    if ($html) {
1731*1208bc7eSAndroid Build Coastguard Worker      my $dis = sprintf("      %6s %6s \t\t%8s: %s ",
1732*1208bc7eSAndroid Build Coastguard Worker                        HtmlPrintNumber($c1),
1733*1208bc7eSAndroid Build Coastguard Worker                        HtmlPrintNumber($c2),
1734*1208bc7eSAndroid Build Coastguard Worker                        UnparseAddress($offset, $e->[0]),
1735*1208bc7eSAndroid Build Coastguard Worker                        CleanDisassembly($e->[3]));
1736*1208bc7eSAndroid Build Coastguard Worker
1737*1208bc7eSAndroid Build Coastguard Worker      # Append the most specific source line associated with this instruction
1738*1208bc7eSAndroid Build Coastguard Worker      if (length($dis) < 80) { $dis .= (' ' x (80 - length($dis))) };
1739*1208bc7eSAndroid Build Coastguard Worker      $dis = HtmlEscape($dis);
1740*1208bc7eSAndroid Build Coastguard Worker      my $f = $e->[5];
1741*1208bc7eSAndroid Build Coastguard Worker      my $l = $e->[6];
1742*1208bc7eSAndroid Build Coastguard Worker      if ($f ne $last_dis_filename) {
1743*1208bc7eSAndroid Build Coastguard Worker        $dis .= sprintf("<span class=disasmloc>%s:%d</span>",
1744*1208bc7eSAndroid Build Coastguard Worker                        HtmlEscape(CleanFileName($f)), $l);
1745*1208bc7eSAndroid Build Coastguard Worker      } elsif ($l ne $last_dis_linenum) {
1746*1208bc7eSAndroid Build Coastguard Worker        # De-emphasize the unchanged file name portion
1747*1208bc7eSAndroid Build Coastguard Worker        $dis .= sprintf("<span class=unimportant>%s</span>" .
1748*1208bc7eSAndroid Build Coastguard Worker                        "<span class=disasmloc>:%d</span>",
1749*1208bc7eSAndroid Build Coastguard Worker                        HtmlEscape(CleanFileName($f)), $l);
1750*1208bc7eSAndroid Build Coastguard Worker      } else {
1751*1208bc7eSAndroid Build Coastguard Worker        # De-emphasize the entire location
1752*1208bc7eSAndroid Build Coastguard Worker        $dis .= sprintf("<span class=unimportant>%s:%d</span>",
1753*1208bc7eSAndroid Build Coastguard Worker                        HtmlEscape(CleanFileName($f)), $l);
1754*1208bc7eSAndroid Build Coastguard Worker      }
1755*1208bc7eSAndroid Build Coastguard Worker      $last_dis_filename = $f;
1756*1208bc7eSAndroid Build Coastguard Worker      $last_dis_linenum = $l;
1757*1208bc7eSAndroid Build Coastguard Worker      $running_disasm .= $dis;
1758*1208bc7eSAndroid Build Coastguard Worker      $running_disasm .= "\n";
1759*1208bc7eSAndroid Build Coastguard Worker    }
1760*1208bc7eSAndroid Build Coastguard Worker
1761*1208bc7eSAndroid Build Coastguard Worker    $running1 += $c1;
1762*1208bc7eSAndroid Build Coastguard Worker    $running2 += $c2;
1763*1208bc7eSAndroid Build Coastguard Worker    $total1 += $c1;
1764*1208bc7eSAndroid Build Coastguard Worker    $total2 += $c2;
1765*1208bc7eSAndroid Build Coastguard Worker    my $file = $e->[1];
1766*1208bc7eSAndroid Build Coastguard Worker    my $line = $e->[2];
1767*1208bc7eSAndroid Build Coastguard Worker    if (($file eq $filename) &&
1768*1208bc7eSAndroid Build Coastguard Worker        ($line >= $firstline) &&
1769*1208bc7eSAndroid Build Coastguard Worker        ($line <= $lastline)) {
1770*1208bc7eSAndroid Build Coastguard Worker      # Assign all accumulated samples to this line
1771*1208bc7eSAndroid Build Coastguard Worker      AddEntry($samples1, $line, $running1);
1772*1208bc7eSAndroid Build Coastguard Worker      AddEntry($samples2, $line, $running2);
1773*1208bc7eSAndroid Build Coastguard Worker      $running1 = 0;
1774*1208bc7eSAndroid Build Coastguard Worker      $running2 = 0;
1775*1208bc7eSAndroid Build Coastguard Worker      if ($html) {
1776*1208bc7eSAndroid Build Coastguard Worker        if ($line != $last_touched_line && $disasm{$line} ne '') {
1777*1208bc7eSAndroid Build Coastguard Worker          $disasm{$line} .= "\n";
1778*1208bc7eSAndroid Build Coastguard Worker        }
1779*1208bc7eSAndroid Build Coastguard Worker        $disasm{$line} .= $running_disasm;
1780*1208bc7eSAndroid Build Coastguard Worker        $running_disasm = '';
1781*1208bc7eSAndroid Build Coastguard Worker        $last_touched_line = $line;
1782*1208bc7eSAndroid Build Coastguard Worker      }
1783*1208bc7eSAndroid Build Coastguard Worker    }
1784*1208bc7eSAndroid Build Coastguard Worker  }
1785*1208bc7eSAndroid Build Coastguard Worker
1786*1208bc7eSAndroid Build Coastguard Worker  # Assign any leftover samples to $lastline
1787*1208bc7eSAndroid Build Coastguard Worker  AddEntry($samples1, $lastline, $running1);
1788*1208bc7eSAndroid Build Coastguard Worker  AddEntry($samples2, $lastline, $running2);
1789*1208bc7eSAndroid Build Coastguard Worker  if ($html) {
1790*1208bc7eSAndroid Build Coastguard Worker    if ($lastline != $last_touched_line && $disasm{$lastline} ne '') {
1791*1208bc7eSAndroid Build Coastguard Worker      $disasm{$lastline} .= "\n";
1792*1208bc7eSAndroid Build Coastguard Worker    }
1793*1208bc7eSAndroid Build Coastguard Worker    $disasm{$lastline} .= $running_disasm;
1794*1208bc7eSAndroid Build Coastguard Worker  }
1795*1208bc7eSAndroid Build Coastguard Worker
1796*1208bc7eSAndroid Build Coastguard Worker  if ($html) {
1797*1208bc7eSAndroid Build Coastguard Worker    printf $output (
1798*1208bc7eSAndroid Build Coastguard Worker      "<h1>%s</h1>%s\n<pre onClick=\"jeprof_toggle_asm()\">\n" .
1799*1208bc7eSAndroid Build Coastguard Worker      "Total:%6s %6s (flat / cumulative %s)\n",
1800*1208bc7eSAndroid Build Coastguard Worker      HtmlEscape(ShortFunctionName($routine)),
1801*1208bc7eSAndroid Build Coastguard Worker      HtmlEscape(CleanFileName($filename)),
1802*1208bc7eSAndroid Build Coastguard Worker      Unparse($total1),
1803*1208bc7eSAndroid Build Coastguard Worker      Unparse($total2),
1804*1208bc7eSAndroid Build Coastguard Worker      Units());
1805*1208bc7eSAndroid Build Coastguard Worker  } else {
1806*1208bc7eSAndroid Build Coastguard Worker    printf $output (
1807*1208bc7eSAndroid Build Coastguard Worker      "ROUTINE ====================== %s in %s\n" .
1808*1208bc7eSAndroid Build Coastguard Worker      "%6s %6s Total %s (flat / cumulative)\n",
1809*1208bc7eSAndroid Build Coastguard Worker      ShortFunctionName($routine),
1810*1208bc7eSAndroid Build Coastguard Worker      CleanFileName($filename),
1811*1208bc7eSAndroid Build Coastguard Worker      Unparse($total1),
1812*1208bc7eSAndroid Build Coastguard Worker      Unparse($total2),
1813*1208bc7eSAndroid Build Coastguard Worker      Units());
1814*1208bc7eSAndroid Build Coastguard Worker  }
1815*1208bc7eSAndroid Build Coastguard Worker  if (!open(FILE, "<$filename")) {
1816*1208bc7eSAndroid Build Coastguard Worker    print STDERR "$filename: $!\n";
1817*1208bc7eSAndroid Build Coastguard Worker    return 0;
1818*1208bc7eSAndroid Build Coastguard Worker  }
1819*1208bc7eSAndroid Build Coastguard Worker  my $l = 0;
1820*1208bc7eSAndroid Build Coastguard Worker  while (<FILE>) {
1821*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;         # turn windows-looking lines into unix-looking lines
1822*1208bc7eSAndroid Build Coastguard Worker    $l++;
1823*1208bc7eSAndroid Build Coastguard Worker    if ($l >= $firstline - 5 &&
1824*1208bc7eSAndroid Build Coastguard Worker        (($l <= $oldlastline + 5) || ($l <= $lastline))) {
1825*1208bc7eSAndroid Build Coastguard Worker      chop;
1826*1208bc7eSAndroid Build Coastguard Worker      my $text = $_;
1827*1208bc7eSAndroid Build Coastguard Worker      if ($l == $firstline) { print $output $skip_marker; }
1828*1208bc7eSAndroid Build Coastguard Worker      my $n1 = GetEntry($samples1, $l);
1829*1208bc7eSAndroid Build Coastguard Worker      my $n2 = GetEntry($samples2, $l);
1830*1208bc7eSAndroid Build Coastguard Worker      if ($html) {
1831*1208bc7eSAndroid Build Coastguard Worker        # Emit a span that has one of the following classes:
1832*1208bc7eSAndroid Build Coastguard Worker        #    livesrc -- has samples
1833*1208bc7eSAndroid Build Coastguard Worker        #    deadsrc -- has disassembly, but with no samples
1834*1208bc7eSAndroid Build Coastguard Worker        #    nop     -- has no matching disasembly
1835*1208bc7eSAndroid Build Coastguard Worker        # Also emit an optional span containing disassembly.
1836*1208bc7eSAndroid Build Coastguard Worker        my $dis = $disasm{$l};
1837*1208bc7eSAndroid Build Coastguard Worker        my $asm = "";
1838*1208bc7eSAndroid Build Coastguard Worker        if (defined($dis) && $dis ne '') {
1839*1208bc7eSAndroid Build Coastguard Worker          $asm = "<span class=\"asm\">" . $dis . "</span>";
1840*1208bc7eSAndroid Build Coastguard Worker        }
1841*1208bc7eSAndroid Build Coastguard Worker        my $source_class = (($n1 + $n2 > 0)
1842*1208bc7eSAndroid Build Coastguard Worker                            ? "livesrc"
1843*1208bc7eSAndroid Build Coastguard Worker                            : (($asm ne "") ? "deadsrc" : "nop"));
1844*1208bc7eSAndroid Build Coastguard Worker        printf $output (
1845*1208bc7eSAndroid Build Coastguard Worker          "<span class=\"line\">%5d</span> " .
1846*1208bc7eSAndroid Build Coastguard Worker          "<span class=\"%s\">%6s %6s %s</span>%s\n",
1847*1208bc7eSAndroid Build Coastguard Worker          $l, $source_class,
1848*1208bc7eSAndroid Build Coastguard Worker          HtmlPrintNumber($n1),
1849*1208bc7eSAndroid Build Coastguard Worker          HtmlPrintNumber($n2),
1850*1208bc7eSAndroid Build Coastguard Worker          HtmlEscape($text),
1851*1208bc7eSAndroid Build Coastguard Worker          $asm);
1852*1208bc7eSAndroid Build Coastguard Worker      } else {
1853*1208bc7eSAndroid Build Coastguard Worker        printf $output(
1854*1208bc7eSAndroid Build Coastguard Worker          "%6s %6s %4d: %s\n",
1855*1208bc7eSAndroid Build Coastguard Worker          UnparseAlt($n1),
1856*1208bc7eSAndroid Build Coastguard Worker          UnparseAlt($n2),
1857*1208bc7eSAndroid Build Coastguard Worker          $l,
1858*1208bc7eSAndroid Build Coastguard Worker          $text);
1859*1208bc7eSAndroid Build Coastguard Worker      }
1860*1208bc7eSAndroid Build Coastguard Worker      if ($l == $lastline)  { print $output $skip_marker; }
1861*1208bc7eSAndroid Build Coastguard Worker    };
1862*1208bc7eSAndroid Build Coastguard Worker  }
1863*1208bc7eSAndroid Build Coastguard Worker  close(FILE);
1864*1208bc7eSAndroid Build Coastguard Worker  if ($html) {
1865*1208bc7eSAndroid Build Coastguard Worker    print $output "</pre>\n";
1866*1208bc7eSAndroid Build Coastguard Worker  }
1867*1208bc7eSAndroid Build Coastguard Worker  return 1;
1868*1208bc7eSAndroid Build Coastguard Worker}
1869*1208bc7eSAndroid Build Coastguard Worker
1870*1208bc7eSAndroid Build Coastguard Worker# Return the source line for the specified file/linenumber.
1871*1208bc7eSAndroid Build Coastguard Worker# Returns undef if not found.
1872*1208bc7eSAndroid Build Coastguard Workersub SourceLine {
1873*1208bc7eSAndroid Build Coastguard Worker  my $file = shift;
1874*1208bc7eSAndroid Build Coastguard Worker  my $line = shift;
1875*1208bc7eSAndroid Build Coastguard Worker
1876*1208bc7eSAndroid Build Coastguard Worker  # Look in cache
1877*1208bc7eSAndroid Build Coastguard Worker  if (!defined($main::source_cache{$file})) {
1878*1208bc7eSAndroid Build Coastguard Worker    if (100 < scalar keys(%main::source_cache)) {
1879*1208bc7eSAndroid Build Coastguard Worker      # Clear the cache when it gets too big
1880*1208bc7eSAndroid Build Coastguard Worker      $main::source_cache = ();
1881*1208bc7eSAndroid Build Coastguard Worker    }
1882*1208bc7eSAndroid Build Coastguard Worker
1883*1208bc7eSAndroid Build Coastguard Worker    # Read all lines from the file
1884*1208bc7eSAndroid Build Coastguard Worker    if (!open(FILE, "<$file")) {
1885*1208bc7eSAndroid Build Coastguard Worker      print STDERR "$file: $!\n";
1886*1208bc7eSAndroid Build Coastguard Worker      $main::source_cache{$file} = [];  # Cache the negative result
1887*1208bc7eSAndroid Build Coastguard Worker      return undef;
1888*1208bc7eSAndroid Build Coastguard Worker    }
1889*1208bc7eSAndroid Build Coastguard Worker    my $lines = [];
1890*1208bc7eSAndroid Build Coastguard Worker    push(@{$lines}, "");        # So we can use 1-based line numbers as indices
1891*1208bc7eSAndroid Build Coastguard Worker    while (<FILE>) {
1892*1208bc7eSAndroid Build Coastguard Worker      push(@{$lines}, $_);
1893*1208bc7eSAndroid Build Coastguard Worker    }
1894*1208bc7eSAndroid Build Coastguard Worker    close(FILE);
1895*1208bc7eSAndroid Build Coastguard Worker
1896*1208bc7eSAndroid Build Coastguard Worker    # Save the lines in the cache
1897*1208bc7eSAndroid Build Coastguard Worker    $main::source_cache{$file} = $lines;
1898*1208bc7eSAndroid Build Coastguard Worker  }
1899*1208bc7eSAndroid Build Coastguard Worker
1900*1208bc7eSAndroid Build Coastguard Worker  my $lines = $main::source_cache{$file};
1901*1208bc7eSAndroid Build Coastguard Worker  if (($line < 0) || ($line > $#{$lines})) {
1902*1208bc7eSAndroid Build Coastguard Worker    return undef;
1903*1208bc7eSAndroid Build Coastguard Worker  } else {
1904*1208bc7eSAndroid Build Coastguard Worker    return $lines->[$line];
1905*1208bc7eSAndroid Build Coastguard Worker  }
1906*1208bc7eSAndroid Build Coastguard Worker}
1907*1208bc7eSAndroid Build Coastguard Worker
1908*1208bc7eSAndroid Build Coastguard Worker# Print disassembly for one routine with interspersed source if available
1909*1208bc7eSAndroid Build Coastguard Workersub PrintDisassembledFunction {
1910*1208bc7eSAndroid Build Coastguard Worker  my $prog = shift;
1911*1208bc7eSAndroid Build Coastguard Worker  my $offset = shift;
1912*1208bc7eSAndroid Build Coastguard Worker  my $routine = shift;
1913*1208bc7eSAndroid Build Coastguard Worker  my $flat = shift;
1914*1208bc7eSAndroid Build Coastguard Worker  my $cumulative = shift;
1915*1208bc7eSAndroid Build Coastguard Worker  my $start_addr = shift;
1916*1208bc7eSAndroid Build Coastguard Worker  my $end_addr = shift;
1917*1208bc7eSAndroid Build Coastguard Worker  my $total = shift;
1918*1208bc7eSAndroid Build Coastguard Worker
1919*1208bc7eSAndroid Build Coastguard Worker  # Disassemble all instructions
1920*1208bc7eSAndroid Build Coastguard Worker  my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
1921*1208bc7eSAndroid Build Coastguard Worker
1922*1208bc7eSAndroid Build Coastguard Worker  # Make array of counts per instruction
1923*1208bc7eSAndroid Build Coastguard Worker  my @flat_count = ();
1924*1208bc7eSAndroid Build Coastguard Worker  my @cum_count = ();
1925*1208bc7eSAndroid Build Coastguard Worker  my $flat_total = 0;
1926*1208bc7eSAndroid Build Coastguard Worker  my $cum_total = 0;
1927*1208bc7eSAndroid Build Coastguard Worker  foreach my $e (@instructions) {
1928*1208bc7eSAndroid Build Coastguard Worker    # Add up counts for all address that fall inside this instruction
1929*1208bc7eSAndroid Build Coastguard Worker    my $c1 = 0;
1930*1208bc7eSAndroid Build Coastguard Worker    my $c2 = 0;
1931*1208bc7eSAndroid Build Coastguard Worker    for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
1932*1208bc7eSAndroid Build Coastguard Worker      $c1 += GetEntry($flat, $a);
1933*1208bc7eSAndroid Build Coastguard Worker      $c2 += GetEntry($cumulative, $a);
1934*1208bc7eSAndroid Build Coastguard Worker    }
1935*1208bc7eSAndroid Build Coastguard Worker    push(@flat_count, $c1);
1936*1208bc7eSAndroid Build Coastguard Worker    push(@cum_count, $c2);
1937*1208bc7eSAndroid Build Coastguard Worker    $flat_total += $c1;
1938*1208bc7eSAndroid Build Coastguard Worker    $cum_total += $c2;
1939*1208bc7eSAndroid Build Coastguard Worker  }
1940*1208bc7eSAndroid Build Coastguard Worker
1941*1208bc7eSAndroid Build Coastguard Worker  # Print header with total counts
1942*1208bc7eSAndroid Build Coastguard Worker  printf("ROUTINE ====================== %s\n" .
1943*1208bc7eSAndroid Build Coastguard Worker         "%6s %6s %s (flat, cumulative) %.1f%% of total\n",
1944*1208bc7eSAndroid Build Coastguard Worker         ShortFunctionName($routine),
1945*1208bc7eSAndroid Build Coastguard Worker         Unparse($flat_total),
1946*1208bc7eSAndroid Build Coastguard Worker         Unparse($cum_total),
1947*1208bc7eSAndroid Build Coastguard Worker         Units(),
1948*1208bc7eSAndroid Build Coastguard Worker         ($cum_total * 100.0) / $total);
1949*1208bc7eSAndroid Build Coastguard Worker
1950*1208bc7eSAndroid Build Coastguard Worker  # Process instructions in order
1951*1208bc7eSAndroid Build Coastguard Worker  my $current_file = "";
1952*1208bc7eSAndroid Build Coastguard Worker  for (my $i = 0; $i <= $#instructions; ) {
1953*1208bc7eSAndroid Build Coastguard Worker    my $e = $instructions[$i];
1954*1208bc7eSAndroid Build Coastguard Worker
1955*1208bc7eSAndroid Build Coastguard Worker    # Print the new file name whenever we switch files
1956*1208bc7eSAndroid Build Coastguard Worker    if ($e->[1] ne $current_file) {
1957*1208bc7eSAndroid Build Coastguard Worker      $current_file = $e->[1];
1958*1208bc7eSAndroid Build Coastguard Worker      my $fname = $current_file;
1959*1208bc7eSAndroid Build Coastguard Worker      $fname =~ s|^\./||;   # Trim leading "./"
1960*1208bc7eSAndroid Build Coastguard Worker
1961*1208bc7eSAndroid Build Coastguard Worker      # Shorten long file names
1962*1208bc7eSAndroid Build Coastguard Worker      if (length($fname) >= 58) {
1963*1208bc7eSAndroid Build Coastguard Worker        $fname = "..." . substr($fname, -55);
1964*1208bc7eSAndroid Build Coastguard Worker      }
1965*1208bc7eSAndroid Build Coastguard Worker      printf("-------------------- %s\n", $fname);
1966*1208bc7eSAndroid Build Coastguard Worker    }
1967*1208bc7eSAndroid Build Coastguard Worker
1968*1208bc7eSAndroid Build Coastguard Worker    # TODO: Compute range of lines to print together to deal with
1969*1208bc7eSAndroid Build Coastguard Worker    # small reorderings.
1970*1208bc7eSAndroid Build Coastguard Worker    my $first_line = $e->[2];
1971*1208bc7eSAndroid Build Coastguard Worker    my $last_line = $first_line;
1972*1208bc7eSAndroid Build Coastguard Worker    my %flat_sum = ();
1973*1208bc7eSAndroid Build Coastguard Worker    my %cum_sum = ();
1974*1208bc7eSAndroid Build Coastguard Worker    for (my $l = $first_line; $l <= $last_line; $l++) {
1975*1208bc7eSAndroid Build Coastguard Worker      $flat_sum{$l} = 0;
1976*1208bc7eSAndroid Build Coastguard Worker      $cum_sum{$l} = 0;
1977*1208bc7eSAndroid Build Coastguard Worker    }
1978*1208bc7eSAndroid Build Coastguard Worker
1979*1208bc7eSAndroid Build Coastguard Worker    # Find run of instructions for this range of source lines
1980*1208bc7eSAndroid Build Coastguard Worker    my $first_inst = $i;
1981*1208bc7eSAndroid Build Coastguard Worker    while (($i <= $#instructions) &&
1982*1208bc7eSAndroid Build Coastguard Worker           ($instructions[$i]->[2] >= $first_line) &&
1983*1208bc7eSAndroid Build Coastguard Worker           ($instructions[$i]->[2] <= $last_line)) {
1984*1208bc7eSAndroid Build Coastguard Worker      $e = $instructions[$i];
1985*1208bc7eSAndroid Build Coastguard Worker      $flat_sum{$e->[2]} += $flat_count[$i];
1986*1208bc7eSAndroid Build Coastguard Worker      $cum_sum{$e->[2]} += $cum_count[$i];
1987*1208bc7eSAndroid Build Coastguard Worker      $i++;
1988*1208bc7eSAndroid Build Coastguard Worker    }
1989*1208bc7eSAndroid Build Coastguard Worker    my $last_inst = $i - 1;
1990*1208bc7eSAndroid Build Coastguard Worker
1991*1208bc7eSAndroid Build Coastguard Worker    # Print source lines
1992*1208bc7eSAndroid Build Coastguard Worker    for (my $l = $first_line; $l <= $last_line; $l++) {
1993*1208bc7eSAndroid Build Coastguard Worker      my $line = SourceLine($current_file, $l);
1994*1208bc7eSAndroid Build Coastguard Worker      if (!defined($line)) {
1995*1208bc7eSAndroid Build Coastguard Worker        $line = "?\n";
1996*1208bc7eSAndroid Build Coastguard Worker        next;
1997*1208bc7eSAndroid Build Coastguard Worker      } else {
1998*1208bc7eSAndroid Build Coastguard Worker        $line =~ s/^\s+//;
1999*1208bc7eSAndroid Build Coastguard Worker      }
2000*1208bc7eSAndroid Build Coastguard Worker      printf("%6s %6s %5d: %s",
2001*1208bc7eSAndroid Build Coastguard Worker             UnparseAlt($flat_sum{$l}),
2002*1208bc7eSAndroid Build Coastguard Worker             UnparseAlt($cum_sum{$l}),
2003*1208bc7eSAndroid Build Coastguard Worker             $l,
2004*1208bc7eSAndroid Build Coastguard Worker             $line);
2005*1208bc7eSAndroid Build Coastguard Worker    }
2006*1208bc7eSAndroid Build Coastguard Worker
2007*1208bc7eSAndroid Build Coastguard Worker    # Print disassembly
2008*1208bc7eSAndroid Build Coastguard Worker    for (my $x = $first_inst; $x <= $last_inst; $x++) {
2009*1208bc7eSAndroid Build Coastguard Worker      my $e = $instructions[$x];
2010*1208bc7eSAndroid Build Coastguard Worker      printf("%6s %6s    %8s: %6s\n",
2011*1208bc7eSAndroid Build Coastguard Worker             UnparseAlt($flat_count[$x]),
2012*1208bc7eSAndroid Build Coastguard Worker             UnparseAlt($cum_count[$x]),
2013*1208bc7eSAndroid Build Coastguard Worker             UnparseAddress($offset, $e->[0]),
2014*1208bc7eSAndroid Build Coastguard Worker             CleanDisassembly($e->[3]));
2015*1208bc7eSAndroid Build Coastguard Worker    }
2016*1208bc7eSAndroid Build Coastguard Worker  }
2017*1208bc7eSAndroid Build Coastguard Worker}
2018*1208bc7eSAndroid Build Coastguard Worker
2019*1208bc7eSAndroid Build Coastguard Worker# Print DOT graph
2020*1208bc7eSAndroid Build Coastguard Workersub PrintDot {
2021*1208bc7eSAndroid Build Coastguard Worker  my $prog = shift;
2022*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
2023*1208bc7eSAndroid Build Coastguard Worker  my $raw = shift;
2024*1208bc7eSAndroid Build Coastguard Worker  my $flat = shift;
2025*1208bc7eSAndroid Build Coastguard Worker  my $cumulative = shift;
2026*1208bc7eSAndroid Build Coastguard Worker  my $overall_total = shift;
2027*1208bc7eSAndroid Build Coastguard Worker
2028*1208bc7eSAndroid Build Coastguard Worker  # Get total
2029*1208bc7eSAndroid Build Coastguard Worker  my $local_total = TotalProfile($flat);
2030*1208bc7eSAndroid Build Coastguard Worker  my $nodelimit = int($main::opt_nodefraction * $local_total);
2031*1208bc7eSAndroid Build Coastguard Worker  my $edgelimit = int($main::opt_edgefraction * $local_total);
2032*1208bc7eSAndroid Build Coastguard Worker  my $nodecount = $main::opt_nodecount;
2033*1208bc7eSAndroid Build Coastguard Worker
2034*1208bc7eSAndroid Build Coastguard Worker  # Find nodes to include
2035*1208bc7eSAndroid Build Coastguard Worker  my @list = (sort { abs(GetEntry($cumulative, $b)) <=>
2036*1208bc7eSAndroid Build Coastguard Worker                     abs(GetEntry($cumulative, $a))
2037*1208bc7eSAndroid Build Coastguard Worker                     || $a cmp $b }
2038*1208bc7eSAndroid Build Coastguard Worker              keys(%{$cumulative}));
2039*1208bc7eSAndroid Build Coastguard Worker  my $last = $nodecount - 1;
2040*1208bc7eSAndroid Build Coastguard Worker  if ($last > $#list) {
2041*1208bc7eSAndroid Build Coastguard Worker    $last = $#list;
2042*1208bc7eSAndroid Build Coastguard Worker  }
2043*1208bc7eSAndroid Build Coastguard Worker  while (($last >= 0) &&
2044*1208bc7eSAndroid Build Coastguard Worker         (abs(GetEntry($cumulative, $list[$last])) <= $nodelimit)) {
2045*1208bc7eSAndroid Build Coastguard Worker    $last--;
2046*1208bc7eSAndroid Build Coastguard Worker  }
2047*1208bc7eSAndroid Build Coastguard Worker  if ($last < 0) {
2048*1208bc7eSAndroid Build Coastguard Worker    print STDERR "No nodes to print\n";
2049*1208bc7eSAndroid Build Coastguard Worker    return 0;
2050*1208bc7eSAndroid Build Coastguard Worker  }
2051*1208bc7eSAndroid Build Coastguard Worker
2052*1208bc7eSAndroid Build Coastguard Worker  if ($nodelimit > 0 || $edgelimit > 0) {
2053*1208bc7eSAndroid Build Coastguard Worker    printf STDERR ("Dropping nodes with <= %s %s; edges with <= %s abs(%s)\n",
2054*1208bc7eSAndroid Build Coastguard Worker                   Unparse($nodelimit), Units(),
2055*1208bc7eSAndroid Build Coastguard Worker                   Unparse($edgelimit), Units());
2056*1208bc7eSAndroid Build Coastguard Worker  }
2057*1208bc7eSAndroid Build Coastguard Worker
2058*1208bc7eSAndroid Build Coastguard Worker  # Open DOT output file
2059*1208bc7eSAndroid Build Coastguard Worker  my $output;
2060*1208bc7eSAndroid Build Coastguard Worker  my $escaped_dot = ShellEscape(@DOT);
2061*1208bc7eSAndroid Build Coastguard Worker  my $escaped_ps2pdf = ShellEscape(@PS2PDF);
2062*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_gv) {
2063*1208bc7eSAndroid Build Coastguard Worker    my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "ps"));
2064*1208bc7eSAndroid Build Coastguard Worker    $output = "| $escaped_dot -Tps2 >$escaped_outfile";
2065*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_evince) {
2066*1208bc7eSAndroid Build Coastguard Worker    my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "pdf"));
2067*1208bc7eSAndroid Build Coastguard Worker    $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - $escaped_outfile";
2068*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_ps) {
2069*1208bc7eSAndroid Build Coastguard Worker    $output = "| $escaped_dot -Tps2";
2070*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_pdf) {
2071*1208bc7eSAndroid Build Coastguard Worker    $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - -";
2072*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_web || $main::opt_svg) {
2073*1208bc7eSAndroid Build Coastguard Worker    # We need to post-process the SVG, so write to a temporary file always.
2074*1208bc7eSAndroid Build Coastguard Worker    my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "svg"));
2075*1208bc7eSAndroid Build Coastguard Worker    $output = "| $escaped_dot -Tsvg >$escaped_outfile";
2076*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_gif) {
2077*1208bc7eSAndroid Build Coastguard Worker    $output = "| $escaped_dot -Tgif";
2078*1208bc7eSAndroid Build Coastguard Worker  } else {
2079*1208bc7eSAndroid Build Coastguard Worker    $output = ">&STDOUT";
2080*1208bc7eSAndroid Build Coastguard Worker  }
2081*1208bc7eSAndroid Build Coastguard Worker  open(DOT, $output) || error("$output: $!\n");
2082*1208bc7eSAndroid Build Coastguard Worker
2083*1208bc7eSAndroid Build Coastguard Worker  # Title
2084*1208bc7eSAndroid Build Coastguard Worker  printf DOT ("digraph \"%s; %s %s\" {\n",
2085*1208bc7eSAndroid Build Coastguard Worker              $prog,
2086*1208bc7eSAndroid Build Coastguard Worker              Unparse($overall_total),
2087*1208bc7eSAndroid Build Coastguard Worker              Units());
2088*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_pdf) {
2089*1208bc7eSAndroid Build Coastguard Worker    # The output is more printable if we set the page size for dot.
2090*1208bc7eSAndroid Build Coastguard Worker    printf DOT ("size=\"8,11\"\n");
2091*1208bc7eSAndroid Build Coastguard Worker  }
2092*1208bc7eSAndroid Build Coastguard Worker  printf DOT ("node [width=0.375,height=0.25];\n");
2093*1208bc7eSAndroid Build Coastguard Worker
2094*1208bc7eSAndroid Build Coastguard Worker  # Print legend
2095*1208bc7eSAndroid Build Coastguard Worker  printf DOT ("Legend [shape=box,fontsize=24,shape=plaintext," .
2096*1208bc7eSAndroid Build Coastguard Worker              "label=\"%s\\l%s\\l%s\\l%s\\l%s\\l\"];\n",
2097*1208bc7eSAndroid Build Coastguard Worker              $prog,
2098*1208bc7eSAndroid Build Coastguard Worker              sprintf("Total %s: %s", Units(), Unparse($overall_total)),
2099*1208bc7eSAndroid Build Coastguard Worker              sprintf("Focusing on: %s", Unparse($local_total)),
2100*1208bc7eSAndroid Build Coastguard Worker              sprintf("Dropped nodes with <= %s abs(%s)",
2101*1208bc7eSAndroid Build Coastguard Worker                      Unparse($nodelimit), Units()),
2102*1208bc7eSAndroid Build Coastguard Worker              sprintf("Dropped edges with <= %s %s",
2103*1208bc7eSAndroid Build Coastguard Worker                      Unparse($edgelimit), Units())
2104*1208bc7eSAndroid Build Coastguard Worker              );
2105*1208bc7eSAndroid Build Coastguard Worker
2106*1208bc7eSAndroid Build Coastguard Worker  # Print nodes
2107*1208bc7eSAndroid Build Coastguard Worker  my %node = ();
2108*1208bc7eSAndroid Build Coastguard Worker  my $nextnode = 1;
2109*1208bc7eSAndroid Build Coastguard Worker  foreach my $a (@list[0..$last]) {
2110*1208bc7eSAndroid Build Coastguard Worker    # Pick font size
2111*1208bc7eSAndroid Build Coastguard Worker    my $f = GetEntry($flat, $a);
2112*1208bc7eSAndroid Build Coastguard Worker    my $c = GetEntry($cumulative, $a);
2113*1208bc7eSAndroid Build Coastguard Worker
2114*1208bc7eSAndroid Build Coastguard Worker    my $fs = 8;
2115*1208bc7eSAndroid Build Coastguard Worker    if ($local_total > 0) {
2116*1208bc7eSAndroid Build Coastguard Worker      $fs = 8 + (50.0 * sqrt(abs($f * 1.0 / $local_total)));
2117*1208bc7eSAndroid Build Coastguard Worker    }
2118*1208bc7eSAndroid Build Coastguard Worker
2119*1208bc7eSAndroid Build Coastguard Worker    $node{$a} = $nextnode++;
2120*1208bc7eSAndroid Build Coastguard Worker    my $sym = $a;
2121*1208bc7eSAndroid Build Coastguard Worker    $sym =~ s/\s+/\\n/g;
2122*1208bc7eSAndroid Build Coastguard Worker    $sym =~ s/::/\\n/g;
2123*1208bc7eSAndroid Build Coastguard Worker
2124*1208bc7eSAndroid Build Coastguard Worker    # Extra cumulative info to print for non-leaves
2125*1208bc7eSAndroid Build Coastguard Worker    my $extra = "";
2126*1208bc7eSAndroid Build Coastguard Worker    if ($f != $c) {
2127*1208bc7eSAndroid Build Coastguard Worker      $extra = sprintf("\\rof %s (%s)",
2128*1208bc7eSAndroid Build Coastguard Worker                       Unparse($c),
2129*1208bc7eSAndroid Build Coastguard Worker                       Percent($c, $local_total));
2130*1208bc7eSAndroid Build Coastguard Worker    }
2131*1208bc7eSAndroid Build Coastguard Worker    my $style = "";
2132*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_heapcheck) {
2133*1208bc7eSAndroid Build Coastguard Worker      if ($f > 0) {
2134*1208bc7eSAndroid Build Coastguard Worker        # make leak-causing nodes more visible (add a background)
2135*1208bc7eSAndroid Build Coastguard Worker        $style = ",style=filled,fillcolor=gray"
2136*1208bc7eSAndroid Build Coastguard Worker      } elsif ($f < 0) {
2137*1208bc7eSAndroid Build Coastguard Worker        # make anti-leak-causing nodes (which almost never occur)
2138*1208bc7eSAndroid Build Coastguard Worker        # stand out as well (triple border)
2139*1208bc7eSAndroid Build Coastguard Worker        $style = ",peripheries=3"
2140*1208bc7eSAndroid Build Coastguard Worker      }
2141*1208bc7eSAndroid Build Coastguard Worker    }
2142*1208bc7eSAndroid Build Coastguard Worker
2143*1208bc7eSAndroid Build Coastguard Worker    printf DOT ("N%d [label=\"%s\\n%s (%s)%s\\r" .
2144*1208bc7eSAndroid Build Coastguard Worker                "\",shape=box,fontsize=%.1f%s];\n",
2145*1208bc7eSAndroid Build Coastguard Worker                $node{$a},
2146*1208bc7eSAndroid Build Coastguard Worker                $sym,
2147*1208bc7eSAndroid Build Coastguard Worker                Unparse($f),
2148*1208bc7eSAndroid Build Coastguard Worker                Percent($f, $local_total),
2149*1208bc7eSAndroid Build Coastguard Worker                $extra,
2150*1208bc7eSAndroid Build Coastguard Worker                $fs,
2151*1208bc7eSAndroid Build Coastguard Worker                $style,
2152*1208bc7eSAndroid Build Coastguard Worker               );
2153*1208bc7eSAndroid Build Coastguard Worker  }
2154*1208bc7eSAndroid Build Coastguard Worker
2155*1208bc7eSAndroid Build Coastguard Worker  # Get edges and counts per edge
2156*1208bc7eSAndroid Build Coastguard Worker  my %edge = ();
2157*1208bc7eSAndroid Build Coastguard Worker  my $n;
2158*1208bc7eSAndroid Build Coastguard Worker  my $fullname_to_shortname_map = {};
2159*1208bc7eSAndroid Build Coastguard Worker  FillFullnameToShortnameMap($symbols, $fullname_to_shortname_map);
2160*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$raw})) {
2161*1208bc7eSAndroid Build Coastguard Worker    # TODO: omit low %age edges
2162*1208bc7eSAndroid Build Coastguard Worker    $n = $raw->{$k};
2163*1208bc7eSAndroid Build Coastguard Worker    my @translated = TranslateStack($symbols, $fullname_to_shortname_map, $k);
2164*1208bc7eSAndroid Build Coastguard Worker    for (my $i = 1; $i <= $#translated; $i++) {
2165*1208bc7eSAndroid Build Coastguard Worker      my $src = $translated[$i];
2166*1208bc7eSAndroid Build Coastguard Worker      my $dst = $translated[$i-1];
2167*1208bc7eSAndroid Build Coastguard Worker      #next if ($src eq $dst);  # Avoid self-edges?
2168*1208bc7eSAndroid Build Coastguard Worker      if (exists($node{$src}) && exists($node{$dst})) {
2169*1208bc7eSAndroid Build Coastguard Worker        my $edge_label = "$src\001$dst";
2170*1208bc7eSAndroid Build Coastguard Worker        if (!exists($edge{$edge_label})) {
2171*1208bc7eSAndroid Build Coastguard Worker          $edge{$edge_label} = 0;
2172*1208bc7eSAndroid Build Coastguard Worker        }
2173*1208bc7eSAndroid Build Coastguard Worker        $edge{$edge_label} += $n;
2174*1208bc7eSAndroid Build Coastguard Worker      }
2175*1208bc7eSAndroid Build Coastguard Worker    }
2176*1208bc7eSAndroid Build Coastguard Worker  }
2177*1208bc7eSAndroid Build Coastguard Worker
2178*1208bc7eSAndroid Build Coastguard Worker  # Print edges (process in order of decreasing counts)
2179*1208bc7eSAndroid Build Coastguard Worker  my %indegree = ();   # Number of incoming edges added per node so far
2180*1208bc7eSAndroid Build Coastguard Worker  my %outdegree = ();  # Number of outgoing edges added per node so far
2181*1208bc7eSAndroid Build Coastguard Worker  foreach my $e (sort { $edge{$b} <=> $edge{$a} } keys(%edge)) {
2182*1208bc7eSAndroid Build Coastguard Worker    my @x = split(/\001/, $e);
2183*1208bc7eSAndroid Build Coastguard Worker    $n = $edge{$e};
2184*1208bc7eSAndroid Build Coastguard Worker
2185*1208bc7eSAndroid Build Coastguard Worker    # Initialize degree of kept incoming and outgoing edges if necessary
2186*1208bc7eSAndroid Build Coastguard Worker    my $src = $x[0];
2187*1208bc7eSAndroid Build Coastguard Worker    my $dst = $x[1];
2188*1208bc7eSAndroid Build Coastguard Worker    if (!exists($outdegree{$src})) { $outdegree{$src} = 0; }
2189*1208bc7eSAndroid Build Coastguard Worker    if (!exists($indegree{$dst})) { $indegree{$dst} = 0; }
2190*1208bc7eSAndroid Build Coastguard Worker
2191*1208bc7eSAndroid Build Coastguard Worker    my $keep;
2192*1208bc7eSAndroid Build Coastguard Worker    if ($indegree{$dst} == 0) {
2193*1208bc7eSAndroid Build Coastguard Worker      # Keep edge if needed for reachability
2194*1208bc7eSAndroid Build Coastguard Worker      $keep = 1;
2195*1208bc7eSAndroid Build Coastguard Worker    } elsif (abs($n) <= $edgelimit) {
2196*1208bc7eSAndroid Build Coastguard Worker      # Drop if we are below --edgefraction
2197*1208bc7eSAndroid Build Coastguard Worker      $keep = 0;
2198*1208bc7eSAndroid Build Coastguard Worker    } elsif ($outdegree{$src} >= $main::opt_maxdegree ||
2199*1208bc7eSAndroid Build Coastguard Worker             $indegree{$dst} >= $main::opt_maxdegree) {
2200*1208bc7eSAndroid Build Coastguard Worker      # Keep limited number of in/out edges per node
2201*1208bc7eSAndroid Build Coastguard Worker      $keep = 0;
2202*1208bc7eSAndroid Build Coastguard Worker    } else {
2203*1208bc7eSAndroid Build Coastguard Worker      $keep = 1;
2204*1208bc7eSAndroid Build Coastguard Worker    }
2205*1208bc7eSAndroid Build Coastguard Worker
2206*1208bc7eSAndroid Build Coastguard Worker    if ($keep) {
2207*1208bc7eSAndroid Build Coastguard Worker      $outdegree{$src}++;
2208*1208bc7eSAndroid Build Coastguard Worker      $indegree{$dst}++;
2209*1208bc7eSAndroid Build Coastguard Worker
2210*1208bc7eSAndroid Build Coastguard Worker      # Compute line width based on edge count
2211*1208bc7eSAndroid Build Coastguard Worker      my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0);
2212*1208bc7eSAndroid Build Coastguard Worker      if ($fraction > 1) { $fraction = 1; }
2213*1208bc7eSAndroid Build Coastguard Worker      my $w = $fraction * 2;
2214*1208bc7eSAndroid Build Coastguard Worker      if ($w < 1 && ($main::opt_web || $main::opt_svg)) {
2215*1208bc7eSAndroid Build Coastguard Worker        # SVG output treats line widths < 1 poorly.
2216*1208bc7eSAndroid Build Coastguard Worker        $w = 1;
2217*1208bc7eSAndroid Build Coastguard Worker      }
2218*1208bc7eSAndroid Build Coastguard Worker
2219*1208bc7eSAndroid Build Coastguard Worker      # Dot sometimes segfaults if given edge weights that are too large, so
2220*1208bc7eSAndroid Build Coastguard Worker      # we cap the weights at a large value
2221*1208bc7eSAndroid Build Coastguard Worker      my $edgeweight = abs($n) ** 0.7;
2222*1208bc7eSAndroid Build Coastguard Worker      if ($edgeweight > 100000) { $edgeweight = 100000; }
2223*1208bc7eSAndroid Build Coastguard Worker      $edgeweight = int($edgeweight);
2224*1208bc7eSAndroid Build Coastguard Worker
2225*1208bc7eSAndroid Build Coastguard Worker      my $style = sprintf("setlinewidth(%f)", $w);
2226*1208bc7eSAndroid Build Coastguard Worker      if ($x[1] =~ m/\(inline\)/) {
2227*1208bc7eSAndroid Build Coastguard Worker        $style .= ",dashed";
2228*1208bc7eSAndroid Build Coastguard Worker      }
2229*1208bc7eSAndroid Build Coastguard Worker
2230*1208bc7eSAndroid Build Coastguard Worker      # Use a slightly squashed function of the edge count as the weight
2231*1208bc7eSAndroid Build Coastguard Worker      printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n",
2232*1208bc7eSAndroid Build Coastguard Worker                  $node{$x[0]},
2233*1208bc7eSAndroid Build Coastguard Worker                  $node{$x[1]},
2234*1208bc7eSAndroid Build Coastguard Worker                  Unparse($n),
2235*1208bc7eSAndroid Build Coastguard Worker                  $edgeweight,
2236*1208bc7eSAndroid Build Coastguard Worker                  $style);
2237*1208bc7eSAndroid Build Coastguard Worker    }
2238*1208bc7eSAndroid Build Coastguard Worker  }
2239*1208bc7eSAndroid Build Coastguard Worker
2240*1208bc7eSAndroid Build Coastguard Worker  print DOT ("}\n");
2241*1208bc7eSAndroid Build Coastguard Worker  close(DOT);
2242*1208bc7eSAndroid Build Coastguard Worker
2243*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_web || $main::opt_svg) {
2244*1208bc7eSAndroid Build Coastguard Worker    # Rewrite SVG to be more usable inside web browser.
2245*1208bc7eSAndroid Build Coastguard Worker    RewriteSvg(TempName($main::next_tmpfile, "svg"));
2246*1208bc7eSAndroid Build Coastguard Worker  }
2247*1208bc7eSAndroid Build Coastguard Worker
2248*1208bc7eSAndroid Build Coastguard Worker  return 1;
2249*1208bc7eSAndroid Build Coastguard Worker}
2250*1208bc7eSAndroid Build Coastguard Worker
2251*1208bc7eSAndroid Build Coastguard Workersub RewriteSvg {
2252*1208bc7eSAndroid Build Coastguard Worker  my $svgfile = shift;
2253*1208bc7eSAndroid Build Coastguard Worker
2254*1208bc7eSAndroid Build Coastguard Worker  open(SVG, $svgfile) || die "open temp svg: $!";
2255*1208bc7eSAndroid Build Coastguard Worker  my @svg = <SVG>;
2256*1208bc7eSAndroid Build Coastguard Worker  close(SVG);
2257*1208bc7eSAndroid Build Coastguard Worker  unlink $svgfile;
2258*1208bc7eSAndroid Build Coastguard Worker  my $svg = join('', @svg);
2259*1208bc7eSAndroid Build Coastguard Worker
2260*1208bc7eSAndroid Build Coastguard Worker  # Dot's SVG output is
2261*1208bc7eSAndroid Build Coastguard Worker  #
2262*1208bc7eSAndroid Build Coastguard Worker  #    <svg width="___" height="___"
2263*1208bc7eSAndroid Build Coastguard Worker  #     viewBox="___" xmlns=...>
2264*1208bc7eSAndroid Build Coastguard Worker  #    <g id="graph0" transform="...">
2265*1208bc7eSAndroid Build Coastguard Worker  #    ...
2266*1208bc7eSAndroid Build Coastguard Worker  #    </g>
2267*1208bc7eSAndroid Build Coastguard Worker  #    </svg>
2268*1208bc7eSAndroid Build Coastguard Worker  #
2269*1208bc7eSAndroid Build Coastguard Worker  # Change it to
2270*1208bc7eSAndroid Build Coastguard Worker  #
2271*1208bc7eSAndroid Build Coastguard Worker  #    <svg width="100%" height="100%"
2272*1208bc7eSAndroid Build Coastguard Worker  #     xmlns=...>
2273*1208bc7eSAndroid Build Coastguard Worker  #    $svg_javascript
2274*1208bc7eSAndroid Build Coastguard Worker  #    <g id="viewport" transform="translate(0,0)">
2275*1208bc7eSAndroid Build Coastguard Worker  #    <g id="graph0" transform="...">
2276*1208bc7eSAndroid Build Coastguard Worker  #    ...
2277*1208bc7eSAndroid Build Coastguard Worker  #    </g>
2278*1208bc7eSAndroid Build Coastguard Worker  #    </g>
2279*1208bc7eSAndroid Build Coastguard Worker  #    </svg>
2280*1208bc7eSAndroid Build Coastguard Worker
2281*1208bc7eSAndroid Build Coastguard Worker  # Fix width, height; drop viewBox.
2282*1208bc7eSAndroid Build Coastguard Worker  $svg =~ s/(?s)<svg width="[^"]+" height="[^"]+"(.*?)viewBox="[^"]+"/<svg width="100%" height="100%"$1/;
2283*1208bc7eSAndroid Build Coastguard Worker
2284*1208bc7eSAndroid Build Coastguard Worker  # Insert script, viewport <g> above first <g>
2285*1208bc7eSAndroid Build Coastguard Worker  my $svg_javascript = SvgJavascript();
2286*1208bc7eSAndroid Build Coastguard Worker  my $viewport = "<g id=\"viewport\" transform=\"translate(0,0)\">\n";
2287*1208bc7eSAndroid Build Coastguard Worker  $svg =~ s/<g id="graph\d"/$svg_javascript$viewport$&/;
2288*1208bc7eSAndroid Build Coastguard Worker
2289*1208bc7eSAndroid Build Coastguard Worker  # Insert final </g> above </svg>.
2290*1208bc7eSAndroid Build Coastguard Worker  $svg =~ s/(.*)(<\/svg>)/$1<\/g>$2/;
2291*1208bc7eSAndroid Build Coastguard Worker  $svg =~ s/<g id="graph\d"(.*?)/<g id="viewport"$1/;
2292*1208bc7eSAndroid Build Coastguard Worker
2293*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_svg) {
2294*1208bc7eSAndroid Build Coastguard Worker    # --svg: write to standard output.
2295*1208bc7eSAndroid Build Coastguard Worker    print $svg;
2296*1208bc7eSAndroid Build Coastguard Worker  } else {
2297*1208bc7eSAndroid Build Coastguard Worker    # Write back to temporary file.
2298*1208bc7eSAndroid Build Coastguard Worker    open(SVG, ">$svgfile") || die "open $svgfile: $!";
2299*1208bc7eSAndroid Build Coastguard Worker    print SVG $svg;
2300*1208bc7eSAndroid Build Coastguard Worker    close(SVG);
2301*1208bc7eSAndroid Build Coastguard Worker  }
2302*1208bc7eSAndroid Build Coastguard Worker}
2303*1208bc7eSAndroid Build Coastguard Worker
2304*1208bc7eSAndroid Build Coastguard Workersub SvgJavascript {
2305*1208bc7eSAndroid Build Coastguard Worker  return <<'EOF';
2306*1208bc7eSAndroid Build Coastguard Worker<script type="text/ecmascript"><![CDATA[
2307*1208bc7eSAndroid Build Coastguard Worker// SVGPan
2308*1208bc7eSAndroid Build Coastguard Worker// http://www.cyberz.org/blog/2009/12/08/svgpan-a-javascript-svg-panzoomdrag-library/
2309*1208bc7eSAndroid Build Coastguard Worker// Local modification: if(true || ...) below to force panning, never moving.
2310*1208bc7eSAndroid Build Coastguard Worker
2311*1208bc7eSAndroid Build Coastguard Worker/**
2312*1208bc7eSAndroid Build Coastguard Worker *  SVGPan library 1.2
2313*1208bc7eSAndroid Build Coastguard Worker * ====================
2314*1208bc7eSAndroid Build Coastguard Worker *
2315*1208bc7eSAndroid Build Coastguard Worker * Given an unique existing element with id "viewport", including the
2316*1208bc7eSAndroid Build Coastguard Worker * the library into any SVG adds the following capabilities:
2317*1208bc7eSAndroid Build Coastguard Worker *
2318*1208bc7eSAndroid Build Coastguard Worker *  - Mouse panning
2319*1208bc7eSAndroid Build Coastguard Worker *  - Mouse zooming (using the wheel)
2320*1208bc7eSAndroid Build Coastguard Worker *  - Object dargging
2321*1208bc7eSAndroid Build Coastguard Worker *
2322*1208bc7eSAndroid Build Coastguard Worker * Known issues:
2323*1208bc7eSAndroid Build Coastguard Worker *
2324*1208bc7eSAndroid Build Coastguard Worker *  - Zooming (while panning) on Safari has still some issues
2325*1208bc7eSAndroid Build Coastguard Worker *
2326*1208bc7eSAndroid Build Coastguard Worker * Releases:
2327*1208bc7eSAndroid Build Coastguard Worker *
2328*1208bc7eSAndroid Build Coastguard Worker * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui
2329*1208bc7eSAndroid Build Coastguard Worker *	Fixed a bug with browser mouse handler interaction
2330*1208bc7eSAndroid Build Coastguard Worker *
2331*1208bc7eSAndroid Build Coastguard Worker * 1.1, Wed Feb  3 17:39:33 GMT 2010, Zeng Xiaohui
2332*1208bc7eSAndroid Build Coastguard Worker *	Updated the zoom code to support the mouse wheel on Safari/Chrome
2333*1208bc7eSAndroid Build Coastguard Worker *
2334*1208bc7eSAndroid Build Coastguard Worker * 1.0, Andrea Leofreddi
2335*1208bc7eSAndroid Build Coastguard Worker *	First release
2336*1208bc7eSAndroid Build Coastguard Worker *
2337*1208bc7eSAndroid Build Coastguard Worker * This code is licensed under the following BSD license:
2338*1208bc7eSAndroid Build Coastguard Worker *
2339*1208bc7eSAndroid Build Coastguard Worker * Copyright 2009-2010 Andrea Leofreddi <[email protected]>. All rights reserved.
2340*1208bc7eSAndroid Build Coastguard Worker *
2341*1208bc7eSAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without modification, are
2342*1208bc7eSAndroid Build Coastguard Worker * permitted provided that the following conditions are met:
2343*1208bc7eSAndroid Build Coastguard Worker *
2344*1208bc7eSAndroid Build Coastguard Worker *    1. Redistributions of source code must retain the above copyright notice, this list of
2345*1208bc7eSAndroid Build Coastguard Worker *       conditions and the following disclaimer.
2346*1208bc7eSAndroid Build Coastguard Worker *
2347*1208bc7eSAndroid Build Coastguard Worker *    2. Redistributions in binary form must reproduce the above copyright notice, this list
2348*1208bc7eSAndroid Build Coastguard Worker *       of conditions and the following disclaimer in the documentation and/or other materials
2349*1208bc7eSAndroid Build Coastguard Worker *       provided with the distribution.
2350*1208bc7eSAndroid Build Coastguard Worker *
2351*1208bc7eSAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ``AS IS'' AND ANY EXPRESS OR IMPLIED
2352*1208bc7eSAndroid Build Coastguard Worker * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2353*1208bc7eSAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR
2354*1208bc7eSAndroid Build Coastguard Worker * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2355*1208bc7eSAndroid Build Coastguard Worker * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2356*1208bc7eSAndroid Build Coastguard Worker * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2357*1208bc7eSAndroid Build Coastguard Worker * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2358*1208bc7eSAndroid Build Coastguard Worker * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2359*1208bc7eSAndroid Build Coastguard Worker * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2360*1208bc7eSAndroid Build Coastguard Worker *
2361*1208bc7eSAndroid Build Coastguard Worker * The views and conclusions contained in the software and documentation are those of the
2362*1208bc7eSAndroid Build Coastguard Worker * authors and should not be interpreted as representing official policies, either expressed
2363*1208bc7eSAndroid Build Coastguard Worker * or implied, of Andrea Leofreddi.
2364*1208bc7eSAndroid Build Coastguard Worker */
2365*1208bc7eSAndroid Build Coastguard Worker
2366*1208bc7eSAndroid Build Coastguard Workervar root = document.documentElement;
2367*1208bc7eSAndroid Build Coastguard Worker
2368*1208bc7eSAndroid Build Coastguard Workervar state = 'none', stateTarget, stateOrigin, stateTf;
2369*1208bc7eSAndroid Build Coastguard Worker
2370*1208bc7eSAndroid Build Coastguard WorkersetupHandlers(root);
2371*1208bc7eSAndroid Build Coastguard Worker
2372*1208bc7eSAndroid Build Coastguard Worker/**
2373*1208bc7eSAndroid Build Coastguard Worker * Register handlers
2374*1208bc7eSAndroid Build Coastguard Worker */
2375*1208bc7eSAndroid Build Coastguard Workerfunction setupHandlers(root){
2376*1208bc7eSAndroid Build Coastguard Worker	setAttributes(root, {
2377*1208bc7eSAndroid Build Coastguard Worker		"onmouseup" : "add(evt)",
2378*1208bc7eSAndroid Build Coastguard Worker		"onmousedown" : "handleMouseDown(evt)",
2379*1208bc7eSAndroid Build Coastguard Worker		"onmousemove" : "handleMouseMove(evt)",
2380*1208bc7eSAndroid Build Coastguard Worker		"onmouseup" : "handleMouseUp(evt)",
2381*1208bc7eSAndroid Build Coastguard Worker		//"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element
2382*1208bc7eSAndroid Build Coastguard Worker	});
2383*1208bc7eSAndroid Build Coastguard Worker
2384*1208bc7eSAndroid Build Coastguard Worker	if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0)
2385*1208bc7eSAndroid Build Coastguard Worker		window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari
2386*1208bc7eSAndroid Build Coastguard Worker	else
2387*1208bc7eSAndroid Build Coastguard Worker		window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others
2388*1208bc7eSAndroid Build Coastguard Worker
2389*1208bc7eSAndroid Build Coastguard Worker	var g = svgDoc.getElementById("svg");
2390*1208bc7eSAndroid Build Coastguard Worker	g.width = "100%";
2391*1208bc7eSAndroid Build Coastguard Worker	g.height = "100%";
2392*1208bc7eSAndroid Build Coastguard Worker}
2393*1208bc7eSAndroid Build Coastguard Worker
2394*1208bc7eSAndroid Build Coastguard Worker/**
2395*1208bc7eSAndroid Build Coastguard Worker * Instance an SVGPoint object with given event coordinates.
2396*1208bc7eSAndroid Build Coastguard Worker */
2397*1208bc7eSAndroid Build Coastguard Workerfunction getEventPoint(evt) {
2398*1208bc7eSAndroid Build Coastguard Worker	var p = root.createSVGPoint();
2399*1208bc7eSAndroid Build Coastguard Worker
2400*1208bc7eSAndroid Build Coastguard Worker	p.x = evt.clientX;
2401*1208bc7eSAndroid Build Coastguard Worker	p.y = evt.clientY;
2402*1208bc7eSAndroid Build Coastguard Worker
2403*1208bc7eSAndroid Build Coastguard Worker	return p;
2404*1208bc7eSAndroid Build Coastguard Worker}
2405*1208bc7eSAndroid Build Coastguard Worker
2406*1208bc7eSAndroid Build Coastguard Worker/**
2407*1208bc7eSAndroid Build Coastguard Worker * Sets the current transform matrix of an element.
2408*1208bc7eSAndroid Build Coastguard Worker */
2409*1208bc7eSAndroid Build Coastguard Workerfunction setCTM(element, matrix) {
2410*1208bc7eSAndroid Build Coastguard Worker	var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
2411*1208bc7eSAndroid Build Coastguard Worker
2412*1208bc7eSAndroid Build Coastguard Worker	element.setAttribute("transform", s);
2413*1208bc7eSAndroid Build Coastguard Worker}
2414*1208bc7eSAndroid Build Coastguard Worker
2415*1208bc7eSAndroid Build Coastguard Worker/**
2416*1208bc7eSAndroid Build Coastguard Worker * Dumps a matrix to a string (useful for debug).
2417*1208bc7eSAndroid Build Coastguard Worker */
2418*1208bc7eSAndroid Build Coastguard Workerfunction dumpMatrix(matrix) {
2419*1208bc7eSAndroid Build Coastguard Worker	var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n  " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n  0, 0, 1 ]";
2420*1208bc7eSAndroid Build Coastguard Worker
2421*1208bc7eSAndroid Build Coastguard Worker	return s;
2422*1208bc7eSAndroid Build Coastguard Worker}
2423*1208bc7eSAndroid Build Coastguard Worker
2424*1208bc7eSAndroid Build Coastguard Worker/**
2425*1208bc7eSAndroid Build Coastguard Worker * Sets attributes of an element.
2426*1208bc7eSAndroid Build Coastguard Worker */
2427*1208bc7eSAndroid Build Coastguard Workerfunction setAttributes(element, attributes){
2428*1208bc7eSAndroid Build Coastguard Worker	for (i in attributes)
2429*1208bc7eSAndroid Build Coastguard Worker		element.setAttributeNS(null, i, attributes[i]);
2430*1208bc7eSAndroid Build Coastguard Worker}
2431*1208bc7eSAndroid Build Coastguard Worker
2432*1208bc7eSAndroid Build Coastguard Worker/**
2433*1208bc7eSAndroid Build Coastguard Worker * Handle mouse move event.
2434*1208bc7eSAndroid Build Coastguard Worker */
2435*1208bc7eSAndroid Build Coastguard Workerfunction handleMouseWheel(evt) {
2436*1208bc7eSAndroid Build Coastguard Worker	if(evt.preventDefault)
2437*1208bc7eSAndroid Build Coastguard Worker		evt.preventDefault();
2438*1208bc7eSAndroid Build Coastguard Worker
2439*1208bc7eSAndroid Build Coastguard Worker	evt.returnValue = false;
2440*1208bc7eSAndroid Build Coastguard Worker
2441*1208bc7eSAndroid Build Coastguard Worker	var svgDoc = evt.target.ownerDocument;
2442*1208bc7eSAndroid Build Coastguard Worker
2443*1208bc7eSAndroid Build Coastguard Worker	var delta;
2444*1208bc7eSAndroid Build Coastguard Worker
2445*1208bc7eSAndroid Build Coastguard Worker	if(evt.wheelDelta)
2446*1208bc7eSAndroid Build Coastguard Worker		delta = evt.wheelDelta / 3600; // Chrome/Safari
2447*1208bc7eSAndroid Build Coastguard Worker	else
2448*1208bc7eSAndroid Build Coastguard Worker		delta = evt.detail / -90; // Mozilla
2449*1208bc7eSAndroid Build Coastguard Worker
2450*1208bc7eSAndroid Build Coastguard Worker	var z = 1 + delta; // Zoom factor: 0.9/1.1
2451*1208bc7eSAndroid Build Coastguard Worker
2452*1208bc7eSAndroid Build Coastguard Worker	var g = svgDoc.getElementById("viewport");
2453*1208bc7eSAndroid Build Coastguard Worker
2454*1208bc7eSAndroid Build Coastguard Worker	var p = getEventPoint(evt);
2455*1208bc7eSAndroid Build Coastguard Worker
2456*1208bc7eSAndroid Build Coastguard Worker	p = p.matrixTransform(g.getCTM().inverse());
2457*1208bc7eSAndroid Build Coastguard Worker
2458*1208bc7eSAndroid Build Coastguard Worker	// Compute new scale matrix in current mouse position
2459*1208bc7eSAndroid Build Coastguard Worker	var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
2460*1208bc7eSAndroid Build Coastguard Worker
2461*1208bc7eSAndroid Build Coastguard Worker        setCTM(g, g.getCTM().multiply(k));
2462*1208bc7eSAndroid Build Coastguard Worker
2463*1208bc7eSAndroid Build Coastguard Worker	stateTf = stateTf.multiply(k.inverse());
2464*1208bc7eSAndroid Build Coastguard Worker}
2465*1208bc7eSAndroid Build Coastguard Worker
2466*1208bc7eSAndroid Build Coastguard Worker/**
2467*1208bc7eSAndroid Build Coastguard Worker * Handle mouse move event.
2468*1208bc7eSAndroid Build Coastguard Worker */
2469*1208bc7eSAndroid Build Coastguard Workerfunction handleMouseMove(evt) {
2470*1208bc7eSAndroid Build Coastguard Worker	if(evt.preventDefault)
2471*1208bc7eSAndroid Build Coastguard Worker		evt.preventDefault();
2472*1208bc7eSAndroid Build Coastguard Worker
2473*1208bc7eSAndroid Build Coastguard Worker	evt.returnValue = false;
2474*1208bc7eSAndroid Build Coastguard Worker
2475*1208bc7eSAndroid Build Coastguard Worker	var svgDoc = evt.target.ownerDocument;
2476*1208bc7eSAndroid Build Coastguard Worker
2477*1208bc7eSAndroid Build Coastguard Worker	var g = svgDoc.getElementById("viewport");
2478*1208bc7eSAndroid Build Coastguard Worker
2479*1208bc7eSAndroid Build Coastguard Worker	if(state == 'pan') {
2480*1208bc7eSAndroid Build Coastguard Worker		// Pan mode
2481*1208bc7eSAndroid Build Coastguard Worker		var p = getEventPoint(evt).matrixTransform(stateTf);
2482*1208bc7eSAndroid Build Coastguard Worker
2483*1208bc7eSAndroid Build Coastguard Worker		setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
2484*1208bc7eSAndroid Build Coastguard Worker	} else if(state == 'move') {
2485*1208bc7eSAndroid Build Coastguard Worker		// Move mode
2486*1208bc7eSAndroid Build Coastguard Worker		var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse());
2487*1208bc7eSAndroid Build Coastguard Worker
2488*1208bc7eSAndroid Build Coastguard Worker		setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM()));
2489*1208bc7eSAndroid Build Coastguard Worker
2490*1208bc7eSAndroid Build Coastguard Worker		stateOrigin = p;
2491*1208bc7eSAndroid Build Coastguard Worker	}
2492*1208bc7eSAndroid Build Coastguard Worker}
2493*1208bc7eSAndroid Build Coastguard Worker
2494*1208bc7eSAndroid Build Coastguard Worker/**
2495*1208bc7eSAndroid Build Coastguard Worker * Handle click event.
2496*1208bc7eSAndroid Build Coastguard Worker */
2497*1208bc7eSAndroid Build Coastguard Workerfunction handleMouseDown(evt) {
2498*1208bc7eSAndroid Build Coastguard Worker	if(evt.preventDefault)
2499*1208bc7eSAndroid Build Coastguard Worker		evt.preventDefault();
2500*1208bc7eSAndroid Build Coastguard Worker
2501*1208bc7eSAndroid Build Coastguard Worker	evt.returnValue = false;
2502*1208bc7eSAndroid Build Coastguard Worker
2503*1208bc7eSAndroid Build Coastguard Worker	var svgDoc = evt.target.ownerDocument;
2504*1208bc7eSAndroid Build Coastguard Worker
2505*1208bc7eSAndroid Build Coastguard Worker	var g = svgDoc.getElementById("viewport");
2506*1208bc7eSAndroid Build Coastguard Worker
2507*1208bc7eSAndroid Build Coastguard Worker	if(true || evt.target.tagName == "svg") {
2508*1208bc7eSAndroid Build Coastguard Worker		// Pan mode
2509*1208bc7eSAndroid Build Coastguard Worker		state = 'pan';
2510*1208bc7eSAndroid Build Coastguard Worker
2511*1208bc7eSAndroid Build Coastguard Worker		stateTf = g.getCTM().inverse();
2512*1208bc7eSAndroid Build Coastguard Worker
2513*1208bc7eSAndroid Build Coastguard Worker		stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
2514*1208bc7eSAndroid Build Coastguard Worker	} else {
2515*1208bc7eSAndroid Build Coastguard Worker		// Move mode
2516*1208bc7eSAndroid Build Coastguard Worker		state = 'move';
2517*1208bc7eSAndroid Build Coastguard Worker
2518*1208bc7eSAndroid Build Coastguard Worker		stateTarget = evt.target;
2519*1208bc7eSAndroid Build Coastguard Worker
2520*1208bc7eSAndroid Build Coastguard Worker		stateTf = g.getCTM().inverse();
2521*1208bc7eSAndroid Build Coastguard Worker
2522*1208bc7eSAndroid Build Coastguard Worker		stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
2523*1208bc7eSAndroid Build Coastguard Worker	}
2524*1208bc7eSAndroid Build Coastguard Worker}
2525*1208bc7eSAndroid Build Coastguard Worker
2526*1208bc7eSAndroid Build Coastguard Worker/**
2527*1208bc7eSAndroid Build Coastguard Worker * Handle mouse button release event.
2528*1208bc7eSAndroid Build Coastguard Worker */
2529*1208bc7eSAndroid Build Coastguard Workerfunction handleMouseUp(evt) {
2530*1208bc7eSAndroid Build Coastguard Worker	if(evt.preventDefault)
2531*1208bc7eSAndroid Build Coastguard Worker		evt.preventDefault();
2532*1208bc7eSAndroid Build Coastguard Worker
2533*1208bc7eSAndroid Build Coastguard Worker	evt.returnValue = false;
2534*1208bc7eSAndroid Build Coastguard Worker
2535*1208bc7eSAndroid Build Coastguard Worker	var svgDoc = evt.target.ownerDocument;
2536*1208bc7eSAndroid Build Coastguard Worker
2537*1208bc7eSAndroid Build Coastguard Worker	if(state == 'pan' || state == 'move') {
2538*1208bc7eSAndroid Build Coastguard Worker		// Quit pan mode
2539*1208bc7eSAndroid Build Coastguard Worker		state = '';
2540*1208bc7eSAndroid Build Coastguard Worker	}
2541*1208bc7eSAndroid Build Coastguard Worker}
2542*1208bc7eSAndroid Build Coastguard Worker
2543*1208bc7eSAndroid Build Coastguard Worker]]></script>
2544*1208bc7eSAndroid Build Coastguard WorkerEOF
2545*1208bc7eSAndroid Build Coastguard Worker}
2546*1208bc7eSAndroid Build Coastguard Worker
2547*1208bc7eSAndroid Build Coastguard Worker# Provides a map from fullname to shortname for cases where the
2548*1208bc7eSAndroid Build Coastguard Worker# shortname is ambiguous.  The symlist has both the fullname and
2549*1208bc7eSAndroid Build Coastguard Worker# shortname for all symbols, which is usually fine, but sometimes --
2550*1208bc7eSAndroid Build Coastguard Worker# such as overloaded functions -- two different fullnames can map to
2551*1208bc7eSAndroid Build Coastguard Worker# the same shortname.  In that case, we use the address of the
2552*1208bc7eSAndroid Build Coastguard Worker# function to disambiguate the two.  This function fills in a map that
2553*1208bc7eSAndroid Build Coastguard Worker# maps fullnames to modified shortnames in such cases.  If a fullname
2554*1208bc7eSAndroid Build Coastguard Worker# is not present in the map, the 'normal' shortname provided by the
2555*1208bc7eSAndroid Build Coastguard Worker# symlist is the appropriate one to use.
2556*1208bc7eSAndroid Build Coastguard Workersub FillFullnameToShortnameMap {
2557*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
2558*1208bc7eSAndroid Build Coastguard Worker  my $fullname_to_shortname_map = shift;
2559*1208bc7eSAndroid Build Coastguard Worker  my $shortnames_seen_once = {};
2560*1208bc7eSAndroid Build Coastguard Worker  my $shortnames_seen_more_than_once = {};
2561*1208bc7eSAndroid Build Coastguard Worker
2562*1208bc7eSAndroid Build Coastguard Worker  foreach my $symlist (values(%{$symbols})) {
2563*1208bc7eSAndroid Build Coastguard Worker    # TODO(csilvers): deal with inlined symbols too.
2564*1208bc7eSAndroid Build Coastguard Worker    my $shortname = $symlist->[0];
2565*1208bc7eSAndroid Build Coastguard Worker    my $fullname = $symlist->[2];
2566*1208bc7eSAndroid Build Coastguard Worker    if ($fullname !~ /<[0-9a-fA-F]+>$/) {  # fullname doesn't end in an address
2567*1208bc7eSAndroid Build Coastguard Worker      next;       # the only collisions we care about are when addresses differ
2568*1208bc7eSAndroid Build Coastguard Worker    }
2569*1208bc7eSAndroid Build Coastguard Worker    if (defined($shortnames_seen_once->{$shortname}) &&
2570*1208bc7eSAndroid Build Coastguard Worker        $shortnames_seen_once->{$shortname} ne $fullname) {
2571*1208bc7eSAndroid Build Coastguard Worker      $shortnames_seen_more_than_once->{$shortname} = 1;
2572*1208bc7eSAndroid Build Coastguard Worker    } else {
2573*1208bc7eSAndroid Build Coastguard Worker      $shortnames_seen_once->{$shortname} = $fullname;
2574*1208bc7eSAndroid Build Coastguard Worker    }
2575*1208bc7eSAndroid Build Coastguard Worker  }
2576*1208bc7eSAndroid Build Coastguard Worker
2577*1208bc7eSAndroid Build Coastguard Worker  foreach my $symlist (values(%{$symbols})) {
2578*1208bc7eSAndroid Build Coastguard Worker    my $shortname = $symlist->[0];
2579*1208bc7eSAndroid Build Coastguard Worker    my $fullname = $symlist->[2];
2580*1208bc7eSAndroid Build Coastguard Worker    # TODO(csilvers): take in a list of addresses we care about, and only
2581*1208bc7eSAndroid Build Coastguard Worker    # store in the map if $symlist->[1] is in that list.  Saves space.
2582*1208bc7eSAndroid Build Coastguard Worker    next if defined($fullname_to_shortname_map->{$fullname});
2583*1208bc7eSAndroid Build Coastguard Worker    if (defined($shortnames_seen_more_than_once->{$shortname})) {
2584*1208bc7eSAndroid Build Coastguard Worker      if ($fullname =~ /<0*([^>]*)>$/) {   # fullname has address at end of it
2585*1208bc7eSAndroid Build Coastguard Worker        $fullname_to_shortname_map->{$fullname} = "$shortname\@$1";
2586*1208bc7eSAndroid Build Coastguard Worker      }
2587*1208bc7eSAndroid Build Coastguard Worker    }
2588*1208bc7eSAndroid Build Coastguard Worker  }
2589*1208bc7eSAndroid Build Coastguard Worker}
2590*1208bc7eSAndroid Build Coastguard Worker
2591*1208bc7eSAndroid Build Coastguard Worker# Return a small number that identifies the argument.
2592*1208bc7eSAndroid Build Coastguard Worker# Multiple calls with the same argument will return the same number.
2593*1208bc7eSAndroid Build Coastguard Worker# Calls with different arguments will return different numbers.
2594*1208bc7eSAndroid Build Coastguard Workersub ShortIdFor {
2595*1208bc7eSAndroid Build Coastguard Worker  my $key = shift;
2596*1208bc7eSAndroid Build Coastguard Worker  my $id = $main::uniqueid{$key};
2597*1208bc7eSAndroid Build Coastguard Worker  if (!defined($id)) {
2598*1208bc7eSAndroid Build Coastguard Worker    $id = keys(%main::uniqueid) + 1;
2599*1208bc7eSAndroid Build Coastguard Worker    $main::uniqueid{$key} = $id;
2600*1208bc7eSAndroid Build Coastguard Worker  }
2601*1208bc7eSAndroid Build Coastguard Worker  return $id;
2602*1208bc7eSAndroid Build Coastguard Worker}
2603*1208bc7eSAndroid Build Coastguard Worker
2604*1208bc7eSAndroid Build Coastguard Worker# Translate a stack of addresses into a stack of symbols
2605*1208bc7eSAndroid Build Coastguard Workersub TranslateStack {
2606*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
2607*1208bc7eSAndroid Build Coastguard Worker  my $fullname_to_shortname_map = shift;
2608*1208bc7eSAndroid Build Coastguard Worker  my $k = shift;
2609*1208bc7eSAndroid Build Coastguard Worker
2610*1208bc7eSAndroid Build Coastguard Worker  my @addrs = split(/\n/, $k);
2611*1208bc7eSAndroid Build Coastguard Worker  my @result = ();
2612*1208bc7eSAndroid Build Coastguard Worker  for (my $i = 0; $i <= $#addrs; $i++) {
2613*1208bc7eSAndroid Build Coastguard Worker    my $a = $addrs[$i];
2614*1208bc7eSAndroid Build Coastguard Worker
2615*1208bc7eSAndroid Build Coastguard Worker    # Skip large addresses since they sometimes show up as fake entries on RH9
2616*1208bc7eSAndroid Build Coastguard Worker    if (length($a) > 8 && $a gt "7fffffffffffffff") {
2617*1208bc7eSAndroid Build Coastguard Worker      next;
2618*1208bc7eSAndroid Build Coastguard Worker    }
2619*1208bc7eSAndroid Build Coastguard Worker
2620*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_disasm || $main::opt_list) {
2621*1208bc7eSAndroid Build Coastguard Worker      # We want just the address for the key
2622*1208bc7eSAndroid Build Coastguard Worker      push(@result, $a);
2623*1208bc7eSAndroid Build Coastguard Worker      next;
2624*1208bc7eSAndroid Build Coastguard Worker    }
2625*1208bc7eSAndroid Build Coastguard Worker
2626*1208bc7eSAndroid Build Coastguard Worker    my $symlist = $symbols->{$a};
2627*1208bc7eSAndroid Build Coastguard Worker    if (!defined($symlist)) {
2628*1208bc7eSAndroid Build Coastguard Worker      $symlist = [$a, "", $a];
2629*1208bc7eSAndroid Build Coastguard Worker    }
2630*1208bc7eSAndroid Build Coastguard Worker
2631*1208bc7eSAndroid Build Coastguard Worker    # We can have a sequence of symbols for a particular entry
2632*1208bc7eSAndroid Build Coastguard Worker    # (more than one symbol in the case of inlining).  Callers
2633*1208bc7eSAndroid Build Coastguard Worker    # come before callees in symlist, so walk backwards since
2634*1208bc7eSAndroid Build Coastguard Worker    # the translated stack should contain callees before callers.
2635*1208bc7eSAndroid Build Coastguard Worker    for (my $j = $#{$symlist}; $j >= 2; $j -= 3) {
2636*1208bc7eSAndroid Build Coastguard Worker      my $func = $symlist->[$j-2];
2637*1208bc7eSAndroid Build Coastguard Worker      my $fileline = $symlist->[$j-1];
2638*1208bc7eSAndroid Build Coastguard Worker      my $fullfunc = $symlist->[$j];
2639*1208bc7eSAndroid Build Coastguard Worker      if (defined($fullname_to_shortname_map->{$fullfunc})) {
2640*1208bc7eSAndroid Build Coastguard Worker        $func = $fullname_to_shortname_map->{$fullfunc};
2641*1208bc7eSAndroid Build Coastguard Worker      }
2642*1208bc7eSAndroid Build Coastguard Worker      if ($j > 2) {
2643*1208bc7eSAndroid Build Coastguard Worker        $func = "$func (inline)";
2644*1208bc7eSAndroid Build Coastguard Worker      }
2645*1208bc7eSAndroid Build Coastguard Worker
2646*1208bc7eSAndroid Build Coastguard Worker      # Do not merge nodes corresponding to Callback::Run since that
2647*1208bc7eSAndroid Build Coastguard Worker      # causes confusing cycles in dot display.  Instead, we synthesize
2648*1208bc7eSAndroid Build Coastguard Worker      # a unique name for this frame per caller.
2649*1208bc7eSAndroid Build Coastguard Worker      if ($func =~ m/Callback.*::Run$/) {
2650*1208bc7eSAndroid Build Coastguard Worker        my $caller = ($i > 0) ? $addrs[$i-1] : 0;
2651*1208bc7eSAndroid Build Coastguard Worker        $func = "Run#" . ShortIdFor($caller);
2652*1208bc7eSAndroid Build Coastguard Worker      }
2653*1208bc7eSAndroid Build Coastguard Worker
2654*1208bc7eSAndroid Build Coastguard Worker      if ($main::opt_addresses) {
2655*1208bc7eSAndroid Build Coastguard Worker        push(@result, "$a $func $fileline");
2656*1208bc7eSAndroid Build Coastguard Worker      } elsif ($main::opt_lines) {
2657*1208bc7eSAndroid Build Coastguard Worker        if ($func eq '??' && $fileline eq '??:0') {
2658*1208bc7eSAndroid Build Coastguard Worker          push(@result, "$a");
2659*1208bc7eSAndroid Build Coastguard Worker        } else {
2660*1208bc7eSAndroid Build Coastguard Worker          push(@result, "$func $fileline");
2661*1208bc7eSAndroid Build Coastguard Worker        }
2662*1208bc7eSAndroid Build Coastguard Worker      } elsif ($main::opt_functions) {
2663*1208bc7eSAndroid Build Coastguard Worker        if ($func eq '??') {
2664*1208bc7eSAndroid Build Coastguard Worker          push(@result, "$a");
2665*1208bc7eSAndroid Build Coastguard Worker        } else {
2666*1208bc7eSAndroid Build Coastguard Worker          push(@result, $func);
2667*1208bc7eSAndroid Build Coastguard Worker        }
2668*1208bc7eSAndroid Build Coastguard Worker      } elsif ($main::opt_files) {
2669*1208bc7eSAndroid Build Coastguard Worker        if ($fileline eq '??:0' || $fileline eq '') {
2670*1208bc7eSAndroid Build Coastguard Worker          push(@result, "$a");
2671*1208bc7eSAndroid Build Coastguard Worker        } else {
2672*1208bc7eSAndroid Build Coastguard Worker          my $f = $fileline;
2673*1208bc7eSAndroid Build Coastguard Worker          $f =~ s/:\d+$//;
2674*1208bc7eSAndroid Build Coastguard Worker          push(@result, $f);
2675*1208bc7eSAndroid Build Coastguard Worker        }
2676*1208bc7eSAndroid Build Coastguard Worker      } else {
2677*1208bc7eSAndroid Build Coastguard Worker        push(@result, $a);
2678*1208bc7eSAndroid Build Coastguard Worker        last;  # Do not print inlined info
2679*1208bc7eSAndroid Build Coastguard Worker      }
2680*1208bc7eSAndroid Build Coastguard Worker    }
2681*1208bc7eSAndroid Build Coastguard Worker  }
2682*1208bc7eSAndroid Build Coastguard Worker
2683*1208bc7eSAndroid Build Coastguard Worker  # print join(",", @addrs), " => ", join(",", @result), "\n";
2684*1208bc7eSAndroid Build Coastguard Worker  return @result;
2685*1208bc7eSAndroid Build Coastguard Worker}
2686*1208bc7eSAndroid Build Coastguard Worker
2687*1208bc7eSAndroid Build Coastguard Worker# Generate percent string for a number and a total
2688*1208bc7eSAndroid Build Coastguard Workersub Percent {
2689*1208bc7eSAndroid Build Coastguard Worker  my $num = shift;
2690*1208bc7eSAndroid Build Coastguard Worker  my $tot = shift;
2691*1208bc7eSAndroid Build Coastguard Worker  if ($tot != 0) {
2692*1208bc7eSAndroid Build Coastguard Worker    return sprintf("%.1f%%", $num * 100.0 / $tot);
2693*1208bc7eSAndroid Build Coastguard Worker  } else {
2694*1208bc7eSAndroid Build Coastguard Worker    return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf");
2695*1208bc7eSAndroid Build Coastguard Worker  }
2696*1208bc7eSAndroid Build Coastguard Worker}
2697*1208bc7eSAndroid Build Coastguard Worker
2698*1208bc7eSAndroid Build Coastguard Worker# Generate pretty-printed form of number
2699*1208bc7eSAndroid Build Coastguard Workersub Unparse {
2700*1208bc7eSAndroid Build Coastguard Worker  my $num = shift;
2701*1208bc7eSAndroid Build Coastguard Worker  if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
2702*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
2703*1208bc7eSAndroid Build Coastguard Worker      return sprintf("%d", $num);
2704*1208bc7eSAndroid Build Coastguard Worker    } else {
2705*1208bc7eSAndroid Build Coastguard Worker      if ($main::opt_show_bytes) {
2706*1208bc7eSAndroid Build Coastguard Worker        return sprintf("%d", $num);
2707*1208bc7eSAndroid Build Coastguard Worker      } else {
2708*1208bc7eSAndroid Build Coastguard Worker        return sprintf("%.1f", $num / 1048576.0);
2709*1208bc7eSAndroid Build Coastguard Worker      }
2710*1208bc7eSAndroid Build Coastguard Worker    }
2711*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
2712*1208bc7eSAndroid Build Coastguard Worker    return sprintf("%.3f", $num / 1e9); # Convert nanoseconds to seconds
2713*1208bc7eSAndroid Build Coastguard Worker  } else {
2714*1208bc7eSAndroid Build Coastguard Worker    return sprintf("%d", $num);
2715*1208bc7eSAndroid Build Coastguard Worker  }
2716*1208bc7eSAndroid Build Coastguard Worker}
2717*1208bc7eSAndroid Build Coastguard Worker
2718*1208bc7eSAndroid Build Coastguard Worker# Alternate pretty-printed form: 0 maps to "."
2719*1208bc7eSAndroid Build Coastguard Workersub UnparseAlt {
2720*1208bc7eSAndroid Build Coastguard Worker  my $num = shift;
2721*1208bc7eSAndroid Build Coastguard Worker  if ($num == 0) {
2722*1208bc7eSAndroid Build Coastguard Worker    return ".";
2723*1208bc7eSAndroid Build Coastguard Worker  } else {
2724*1208bc7eSAndroid Build Coastguard Worker    return Unparse($num);
2725*1208bc7eSAndroid Build Coastguard Worker  }
2726*1208bc7eSAndroid Build Coastguard Worker}
2727*1208bc7eSAndroid Build Coastguard Worker
2728*1208bc7eSAndroid Build Coastguard Worker# Alternate pretty-printed form: 0 maps to ""
2729*1208bc7eSAndroid Build Coastguard Workersub HtmlPrintNumber {
2730*1208bc7eSAndroid Build Coastguard Worker  my $num = shift;
2731*1208bc7eSAndroid Build Coastguard Worker  if ($num == 0) {
2732*1208bc7eSAndroid Build Coastguard Worker    return "";
2733*1208bc7eSAndroid Build Coastguard Worker  } else {
2734*1208bc7eSAndroid Build Coastguard Worker    return Unparse($num);
2735*1208bc7eSAndroid Build Coastguard Worker  }
2736*1208bc7eSAndroid Build Coastguard Worker}
2737*1208bc7eSAndroid Build Coastguard Worker
2738*1208bc7eSAndroid Build Coastguard Worker# Return output units
2739*1208bc7eSAndroid Build Coastguard Workersub Units {
2740*1208bc7eSAndroid Build Coastguard Worker  if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
2741*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
2742*1208bc7eSAndroid Build Coastguard Worker      return "objects";
2743*1208bc7eSAndroid Build Coastguard Worker    } else {
2744*1208bc7eSAndroid Build Coastguard Worker      if ($main::opt_show_bytes) {
2745*1208bc7eSAndroid Build Coastguard Worker        return "B";
2746*1208bc7eSAndroid Build Coastguard Worker      } else {
2747*1208bc7eSAndroid Build Coastguard Worker        return "MB";
2748*1208bc7eSAndroid Build Coastguard Worker      }
2749*1208bc7eSAndroid Build Coastguard Worker    }
2750*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
2751*1208bc7eSAndroid Build Coastguard Worker    return "seconds";
2752*1208bc7eSAndroid Build Coastguard Worker  } else {
2753*1208bc7eSAndroid Build Coastguard Worker    return "samples";
2754*1208bc7eSAndroid Build Coastguard Worker  }
2755*1208bc7eSAndroid Build Coastguard Worker}
2756*1208bc7eSAndroid Build Coastguard Worker
2757*1208bc7eSAndroid Build Coastguard Worker##### Profile manipulation code #####
2758*1208bc7eSAndroid Build Coastguard Worker
2759*1208bc7eSAndroid Build Coastguard Worker# Generate flattened profile:
2760*1208bc7eSAndroid Build Coastguard Worker# If count is charged to stack [a,b,c,d], in generated profile,
2761*1208bc7eSAndroid Build Coastguard Worker# it will be charged to [a]
2762*1208bc7eSAndroid Build Coastguard Workersub FlatProfile {
2763*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
2764*1208bc7eSAndroid Build Coastguard Worker  my $result = {};
2765*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
2766*1208bc7eSAndroid Build Coastguard Worker    my $count = $profile->{$k};
2767*1208bc7eSAndroid Build Coastguard Worker    my @addrs = split(/\n/, $k);
2768*1208bc7eSAndroid Build Coastguard Worker    if ($#addrs >= 0) {
2769*1208bc7eSAndroid Build Coastguard Worker      AddEntry($result, $addrs[0], $count);
2770*1208bc7eSAndroid Build Coastguard Worker    }
2771*1208bc7eSAndroid Build Coastguard Worker  }
2772*1208bc7eSAndroid Build Coastguard Worker  return $result;
2773*1208bc7eSAndroid Build Coastguard Worker}
2774*1208bc7eSAndroid Build Coastguard Worker
2775*1208bc7eSAndroid Build Coastguard Worker# Generate cumulative profile:
2776*1208bc7eSAndroid Build Coastguard Worker# If count is charged to stack [a,b,c,d], in generated profile,
2777*1208bc7eSAndroid Build Coastguard Worker# it will be charged to [a], [b], [c], [d]
2778*1208bc7eSAndroid Build Coastguard Workersub CumulativeProfile {
2779*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
2780*1208bc7eSAndroid Build Coastguard Worker  my $result = {};
2781*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
2782*1208bc7eSAndroid Build Coastguard Worker    my $count = $profile->{$k};
2783*1208bc7eSAndroid Build Coastguard Worker    my @addrs = split(/\n/, $k);
2784*1208bc7eSAndroid Build Coastguard Worker    foreach my $a (@addrs) {
2785*1208bc7eSAndroid Build Coastguard Worker      AddEntry($result, $a, $count);
2786*1208bc7eSAndroid Build Coastguard Worker    }
2787*1208bc7eSAndroid Build Coastguard Worker  }
2788*1208bc7eSAndroid Build Coastguard Worker  return $result;
2789*1208bc7eSAndroid Build Coastguard Worker}
2790*1208bc7eSAndroid Build Coastguard Worker
2791*1208bc7eSAndroid Build Coastguard Worker# If the second-youngest PC on the stack is always the same, returns
2792*1208bc7eSAndroid Build Coastguard Worker# that pc.  Otherwise, returns undef.
2793*1208bc7eSAndroid Build Coastguard Workersub IsSecondPcAlwaysTheSame {
2794*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
2795*1208bc7eSAndroid Build Coastguard Worker
2796*1208bc7eSAndroid Build Coastguard Worker  my $second_pc = undef;
2797*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
2798*1208bc7eSAndroid Build Coastguard Worker    my @addrs = split(/\n/, $k);
2799*1208bc7eSAndroid Build Coastguard Worker    if ($#addrs < 1) {
2800*1208bc7eSAndroid Build Coastguard Worker      return undef;
2801*1208bc7eSAndroid Build Coastguard Worker    }
2802*1208bc7eSAndroid Build Coastguard Worker    if (not defined $second_pc) {
2803*1208bc7eSAndroid Build Coastguard Worker      $second_pc = $addrs[1];
2804*1208bc7eSAndroid Build Coastguard Worker    } else {
2805*1208bc7eSAndroid Build Coastguard Worker      if ($second_pc ne $addrs[1]) {
2806*1208bc7eSAndroid Build Coastguard Worker        return undef;
2807*1208bc7eSAndroid Build Coastguard Worker      }
2808*1208bc7eSAndroid Build Coastguard Worker    }
2809*1208bc7eSAndroid Build Coastguard Worker  }
2810*1208bc7eSAndroid Build Coastguard Worker  return $second_pc;
2811*1208bc7eSAndroid Build Coastguard Worker}
2812*1208bc7eSAndroid Build Coastguard Worker
2813*1208bc7eSAndroid Build Coastguard Workersub ExtractSymbolLocation {
2814*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
2815*1208bc7eSAndroid Build Coastguard Worker  my $address = shift;
2816*1208bc7eSAndroid Build Coastguard Worker  # 'addr2line' outputs "??:0" for unknown locations; we do the
2817*1208bc7eSAndroid Build Coastguard Worker  # same to be consistent.
2818*1208bc7eSAndroid Build Coastguard Worker  my $location = "??:0:unknown";
2819*1208bc7eSAndroid Build Coastguard Worker  if (exists $symbols->{$address}) {
2820*1208bc7eSAndroid Build Coastguard Worker    my $file = $symbols->{$address}->[1];
2821*1208bc7eSAndroid Build Coastguard Worker    if ($file eq "?") {
2822*1208bc7eSAndroid Build Coastguard Worker      $file = "??:0"
2823*1208bc7eSAndroid Build Coastguard Worker    }
2824*1208bc7eSAndroid Build Coastguard Worker    $location = $file . ":" . $symbols->{$address}->[0];
2825*1208bc7eSAndroid Build Coastguard Worker  }
2826*1208bc7eSAndroid Build Coastguard Worker  return $location;
2827*1208bc7eSAndroid Build Coastguard Worker}
2828*1208bc7eSAndroid Build Coastguard Worker
2829*1208bc7eSAndroid Build Coastguard Worker# Extracts a graph of calls.
2830*1208bc7eSAndroid Build Coastguard Workersub ExtractCalls {
2831*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
2832*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
2833*1208bc7eSAndroid Build Coastguard Worker
2834*1208bc7eSAndroid Build Coastguard Worker  my $calls = {};
2835*1208bc7eSAndroid Build Coastguard Worker  while( my ($stack_trace, $count) = each %$profile ) {
2836*1208bc7eSAndroid Build Coastguard Worker    my @address = split(/\n/, $stack_trace);
2837*1208bc7eSAndroid Build Coastguard Worker    my $destination = ExtractSymbolLocation($symbols, $address[0]);
2838*1208bc7eSAndroid Build Coastguard Worker    AddEntry($calls, $destination, $count);
2839*1208bc7eSAndroid Build Coastguard Worker    for (my $i = 1; $i <= $#address; $i++) {
2840*1208bc7eSAndroid Build Coastguard Worker      my $source = ExtractSymbolLocation($symbols, $address[$i]);
2841*1208bc7eSAndroid Build Coastguard Worker      my $call = "$source -> $destination";
2842*1208bc7eSAndroid Build Coastguard Worker      AddEntry($calls, $call, $count);
2843*1208bc7eSAndroid Build Coastguard Worker      $destination = $source;
2844*1208bc7eSAndroid Build Coastguard Worker    }
2845*1208bc7eSAndroid Build Coastguard Worker  }
2846*1208bc7eSAndroid Build Coastguard Worker
2847*1208bc7eSAndroid Build Coastguard Worker  return $calls;
2848*1208bc7eSAndroid Build Coastguard Worker}
2849*1208bc7eSAndroid Build Coastguard Worker
2850*1208bc7eSAndroid Build Coastguard Workersub FilterFrames {
2851*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
2852*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
2853*1208bc7eSAndroid Build Coastguard Worker
2854*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_retain eq '' && $main::opt_exclude eq '') {
2855*1208bc7eSAndroid Build Coastguard Worker    return $profile;
2856*1208bc7eSAndroid Build Coastguard Worker  }
2857*1208bc7eSAndroid Build Coastguard Worker
2858*1208bc7eSAndroid Build Coastguard Worker  my $result = {};
2859*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
2860*1208bc7eSAndroid Build Coastguard Worker    my $count = $profile->{$k};
2861*1208bc7eSAndroid Build Coastguard Worker    my @addrs = split(/\n/, $k);
2862*1208bc7eSAndroid Build Coastguard Worker    my @path = ();
2863*1208bc7eSAndroid Build Coastguard Worker    foreach my $a (@addrs) {
2864*1208bc7eSAndroid Build Coastguard Worker      my $sym;
2865*1208bc7eSAndroid Build Coastguard Worker      if (exists($symbols->{$a})) {
2866*1208bc7eSAndroid Build Coastguard Worker        $sym = $symbols->{$a}->[0];
2867*1208bc7eSAndroid Build Coastguard Worker      } else {
2868*1208bc7eSAndroid Build Coastguard Worker        $sym = $a;
2869*1208bc7eSAndroid Build Coastguard Worker      }
2870*1208bc7eSAndroid Build Coastguard Worker      if ($main::opt_retain ne '' && $sym !~ m/$main::opt_retain/) {
2871*1208bc7eSAndroid Build Coastguard Worker        next;
2872*1208bc7eSAndroid Build Coastguard Worker      }
2873*1208bc7eSAndroid Build Coastguard Worker      if ($main::opt_exclude ne '' && $sym =~ m/$main::opt_exclude/) {
2874*1208bc7eSAndroid Build Coastguard Worker        next;
2875*1208bc7eSAndroid Build Coastguard Worker      }
2876*1208bc7eSAndroid Build Coastguard Worker      push(@path, $a);
2877*1208bc7eSAndroid Build Coastguard Worker    }
2878*1208bc7eSAndroid Build Coastguard Worker    if (scalar(@path) > 0) {
2879*1208bc7eSAndroid Build Coastguard Worker      my $reduced_path = join("\n", @path);
2880*1208bc7eSAndroid Build Coastguard Worker      AddEntry($result, $reduced_path, $count);
2881*1208bc7eSAndroid Build Coastguard Worker    }
2882*1208bc7eSAndroid Build Coastguard Worker  }
2883*1208bc7eSAndroid Build Coastguard Worker
2884*1208bc7eSAndroid Build Coastguard Worker  return $result;
2885*1208bc7eSAndroid Build Coastguard Worker}
2886*1208bc7eSAndroid Build Coastguard Worker
2887*1208bc7eSAndroid Build Coastguard Workersub RemoveUninterestingFrames {
2888*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
2889*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
2890*1208bc7eSAndroid Build Coastguard Worker
2891*1208bc7eSAndroid Build Coastguard Worker  # List of function names to skip
2892*1208bc7eSAndroid Build Coastguard Worker  my %skip = ();
2893*1208bc7eSAndroid Build Coastguard Worker  my $skip_regexp = 'NOMATCH';
2894*1208bc7eSAndroid Build Coastguard Worker  if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
2895*1208bc7eSAndroid Build Coastguard Worker    foreach my $name ('@JEMALLOC_PREFIX@calloc',
2896*1208bc7eSAndroid Build Coastguard Worker                      'cfree',
2897*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@malloc',
2898*1208bc7eSAndroid Build Coastguard Worker                      'newImpl',
2899*1208bc7eSAndroid Build Coastguard Worker                      'void* newImpl',
2900*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@free',
2901*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@memalign',
2902*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@posix_memalign',
2903*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@aligned_alloc',
2904*1208bc7eSAndroid Build Coastguard Worker                      'pvalloc',
2905*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@valloc',
2906*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@realloc',
2907*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@mallocx',
2908*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@rallocx',
2909*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@xallocx',
2910*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@dallocx',
2911*1208bc7eSAndroid Build Coastguard Worker                      '@JEMALLOC_PREFIX@sdallocx',
2912*1208bc7eSAndroid Build Coastguard Worker                      'tc_calloc',
2913*1208bc7eSAndroid Build Coastguard Worker                      'tc_cfree',
2914*1208bc7eSAndroid Build Coastguard Worker                      'tc_malloc',
2915*1208bc7eSAndroid Build Coastguard Worker                      'tc_free',
2916*1208bc7eSAndroid Build Coastguard Worker                      'tc_memalign',
2917*1208bc7eSAndroid Build Coastguard Worker                      'tc_posix_memalign',
2918*1208bc7eSAndroid Build Coastguard Worker                      'tc_pvalloc',
2919*1208bc7eSAndroid Build Coastguard Worker                      'tc_valloc',
2920*1208bc7eSAndroid Build Coastguard Worker                      'tc_realloc',
2921*1208bc7eSAndroid Build Coastguard Worker                      'tc_new',
2922*1208bc7eSAndroid Build Coastguard Worker                      'tc_delete',
2923*1208bc7eSAndroid Build Coastguard Worker                      'tc_newarray',
2924*1208bc7eSAndroid Build Coastguard Worker                      'tc_deletearray',
2925*1208bc7eSAndroid Build Coastguard Worker                      'tc_new_nothrow',
2926*1208bc7eSAndroid Build Coastguard Worker                      'tc_newarray_nothrow',
2927*1208bc7eSAndroid Build Coastguard Worker                      'do_malloc',
2928*1208bc7eSAndroid Build Coastguard Worker                      '::do_malloc',   # new name -- got moved to an unnamed ns
2929*1208bc7eSAndroid Build Coastguard Worker                      '::do_malloc_or_cpp_alloc',
2930*1208bc7eSAndroid Build Coastguard Worker                      'DoSampledAllocation',
2931*1208bc7eSAndroid Build Coastguard Worker                      'simple_alloc::allocate',
2932*1208bc7eSAndroid Build Coastguard Worker                      '__malloc_alloc_template::allocate',
2933*1208bc7eSAndroid Build Coastguard Worker                      '__builtin_delete',
2934*1208bc7eSAndroid Build Coastguard Worker                      '__builtin_new',
2935*1208bc7eSAndroid Build Coastguard Worker                      '__builtin_vec_delete',
2936*1208bc7eSAndroid Build Coastguard Worker                      '__builtin_vec_new',
2937*1208bc7eSAndroid Build Coastguard Worker                      'operator new',
2938*1208bc7eSAndroid Build Coastguard Worker                      'operator new[]',
2939*1208bc7eSAndroid Build Coastguard Worker                      # The entry to our memory-allocation routines on OS X
2940*1208bc7eSAndroid Build Coastguard Worker                      'malloc_zone_malloc',
2941*1208bc7eSAndroid Build Coastguard Worker                      'malloc_zone_calloc',
2942*1208bc7eSAndroid Build Coastguard Worker                      'malloc_zone_valloc',
2943*1208bc7eSAndroid Build Coastguard Worker                      'malloc_zone_realloc',
2944*1208bc7eSAndroid Build Coastguard Worker                      'malloc_zone_memalign',
2945*1208bc7eSAndroid Build Coastguard Worker                      'malloc_zone_free',
2946*1208bc7eSAndroid Build Coastguard Worker                      # These mark the beginning/end of our custom sections
2947*1208bc7eSAndroid Build Coastguard Worker                      '__start_google_malloc',
2948*1208bc7eSAndroid Build Coastguard Worker                      '__stop_google_malloc',
2949*1208bc7eSAndroid Build Coastguard Worker                      '__start_malloc_hook',
2950*1208bc7eSAndroid Build Coastguard Worker                      '__stop_malloc_hook') {
2951*1208bc7eSAndroid Build Coastguard Worker      $skip{$name} = 1;
2952*1208bc7eSAndroid Build Coastguard Worker      $skip{"_" . $name} = 1;   # Mach (OS X) adds a _ prefix to everything
2953*1208bc7eSAndroid Build Coastguard Worker    }
2954*1208bc7eSAndroid Build Coastguard Worker    # TODO: Remove TCMalloc once everything has been
2955*1208bc7eSAndroid Build Coastguard Worker    # moved into the tcmalloc:: namespace and we have flushed
2956*1208bc7eSAndroid Build Coastguard Worker    # old code out of the system.
2957*1208bc7eSAndroid Build Coastguard Worker    $skip_regexp = "TCMalloc|^tcmalloc::";
2958*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::profile_type eq 'contention') {
2959*1208bc7eSAndroid Build Coastguard Worker    foreach my $vname ('base::RecordLockProfileData',
2960*1208bc7eSAndroid Build Coastguard Worker                       'base::SubmitMutexProfileData',
2961*1208bc7eSAndroid Build Coastguard Worker                       'base::SubmitSpinLockProfileData',
2962*1208bc7eSAndroid Build Coastguard Worker                       'Mutex::Unlock',
2963*1208bc7eSAndroid Build Coastguard Worker                       'Mutex::UnlockSlow',
2964*1208bc7eSAndroid Build Coastguard Worker                       'Mutex::ReaderUnlock',
2965*1208bc7eSAndroid Build Coastguard Worker                       'MutexLock::~MutexLock',
2966*1208bc7eSAndroid Build Coastguard Worker                       'SpinLock::Unlock',
2967*1208bc7eSAndroid Build Coastguard Worker                       'SpinLock::SlowUnlock',
2968*1208bc7eSAndroid Build Coastguard Worker                       'SpinLockHolder::~SpinLockHolder') {
2969*1208bc7eSAndroid Build Coastguard Worker      $skip{$vname} = 1;
2970*1208bc7eSAndroid Build Coastguard Worker    }
2971*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::profile_type eq 'cpu') {
2972*1208bc7eSAndroid Build Coastguard Worker    # Drop signal handlers used for CPU profile collection
2973*1208bc7eSAndroid Build Coastguard Worker    # TODO(dpeng): this should not be necessary; it's taken
2974*1208bc7eSAndroid Build Coastguard Worker    # care of by the general 2nd-pc mechanism below.
2975*1208bc7eSAndroid Build Coastguard Worker    foreach my $name ('ProfileData::Add',           # historical
2976*1208bc7eSAndroid Build Coastguard Worker                      'ProfileData::prof_handler',  # historical
2977*1208bc7eSAndroid Build Coastguard Worker                      'CpuProfiler::prof_handler',
2978*1208bc7eSAndroid Build Coastguard Worker                      '__FRAME_END__',
2979*1208bc7eSAndroid Build Coastguard Worker                      '__pthread_sighandler',
2980*1208bc7eSAndroid Build Coastguard Worker                      '__restore') {
2981*1208bc7eSAndroid Build Coastguard Worker      $skip{$name} = 1;
2982*1208bc7eSAndroid Build Coastguard Worker    }
2983*1208bc7eSAndroid Build Coastguard Worker  } else {
2984*1208bc7eSAndroid Build Coastguard Worker    # Nothing skipped for unknown types
2985*1208bc7eSAndroid Build Coastguard Worker  }
2986*1208bc7eSAndroid Build Coastguard Worker
2987*1208bc7eSAndroid Build Coastguard Worker  if ($main::profile_type eq 'cpu') {
2988*1208bc7eSAndroid Build Coastguard Worker    # If all the second-youngest program counters are the same,
2989*1208bc7eSAndroid Build Coastguard Worker    # this STRONGLY suggests that it is an artifact of measurement,
2990*1208bc7eSAndroid Build Coastguard Worker    # i.e., stack frames pushed by the CPU profiler signal handler.
2991*1208bc7eSAndroid Build Coastguard Worker    # Hence, we delete them.
2992*1208bc7eSAndroid Build Coastguard Worker    # (The topmost PC is read from the signal structure, not from
2993*1208bc7eSAndroid Build Coastguard Worker    # the stack, so it does not get involved.)
2994*1208bc7eSAndroid Build Coastguard Worker    while (my $second_pc = IsSecondPcAlwaysTheSame($profile)) {
2995*1208bc7eSAndroid Build Coastguard Worker      my $result = {};
2996*1208bc7eSAndroid Build Coastguard Worker      my $func = '';
2997*1208bc7eSAndroid Build Coastguard Worker      if (exists($symbols->{$second_pc})) {
2998*1208bc7eSAndroid Build Coastguard Worker        $second_pc = $symbols->{$second_pc}->[0];
2999*1208bc7eSAndroid Build Coastguard Worker      }
3000*1208bc7eSAndroid Build Coastguard Worker      print STDERR "Removing $second_pc from all stack traces.\n";
3001*1208bc7eSAndroid Build Coastguard Worker      foreach my $k (keys(%{$profile})) {
3002*1208bc7eSAndroid Build Coastguard Worker        my $count = $profile->{$k};
3003*1208bc7eSAndroid Build Coastguard Worker        my @addrs = split(/\n/, $k);
3004*1208bc7eSAndroid Build Coastguard Worker        splice @addrs, 1, 1;
3005*1208bc7eSAndroid Build Coastguard Worker        my $reduced_path = join("\n", @addrs);
3006*1208bc7eSAndroid Build Coastguard Worker        AddEntry($result, $reduced_path, $count);
3007*1208bc7eSAndroid Build Coastguard Worker      }
3008*1208bc7eSAndroid Build Coastguard Worker      $profile = $result;
3009*1208bc7eSAndroid Build Coastguard Worker    }
3010*1208bc7eSAndroid Build Coastguard Worker  }
3011*1208bc7eSAndroid Build Coastguard Worker
3012*1208bc7eSAndroid Build Coastguard Worker  my $result = {};
3013*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
3014*1208bc7eSAndroid Build Coastguard Worker    my $count = $profile->{$k};
3015*1208bc7eSAndroid Build Coastguard Worker    my @addrs = split(/\n/, $k);
3016*1208bc7eSAndroid Build Coastguard Worker    my @path = ();
3017*1208bc7eSAndroid Build Coastguard Worker    foreach my $a (@addrs) {
3018*1208bc7eSAndroid Build Coastguard Worker      if (exists($symbols->{$a})) {
3019*1208bc7eSAndroid Build Coastguard Worker        my $func = $symbols->{$a}->[0];
3020*1208bc7eSAndroid Build Coastguard Worker        if ($skip{$func} || ($func =~ m/$skip_regexp/)) {
3021*1208bc7eSAndroid Build Coastguard Worker          # Throw away the portion of the backtrace seen so far, under the
3022*1208bc7eSAndroid Build Coastguard Worker          # assumption that previous frames were for functions internal to the
3023*1208bc7eSAndroid Build Coastguard Worker          # allocator.
3024*1208bc7eSAndroid Build Coastguard Worker          @path = ();
3025*1208bc7eSAndroid Build Coastguard Worker          next;
3026*1208bc7eSAndroid Build Coastguard Worker        }
3027*1208bc7eSAndroid Build Coastguard Worker      }
3028*1208bc7eSAndroid Build Coastguard Worker      push(@path, $a);
3029*1208bc7eSAndroid Build Coastguard Worker    }
3030*1208bc7eSAndroid Build Coastguard Worker    my $reduced_path = join("\n", @path);
3031*1208bc7eSAndroid Build Coastguard Worker    AddEntry($result, $reduced_path, $count);
3032*1208bc7eSAndroid Build Coastguard Worker  }
3033*1208bc7eSAndroid Build Coastguard Worker
3034*1208bc7eSAndroid Build Coastguard Worker  $result = FilterFrames($symbols, $result);
3035*1208bc7eSAndroid Build Coastguard Worker
3036*1208bc7eSAndroid Build Coastguard Worker  return $result;
3037*1208bc7eSAndroid Build Coastguard Worker}
3038*1208bc7eSAndroid Build Coastguard Worker
3039*1208bc7eSAndroid Build Coastguard Worker# Reduce profile to granularity given by user
3040*1208bc7eSAndroid Build Coastguard Workersub ReduceProfile {
3041*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
3042*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
3043*1208bc7eSAndroid Build Coastguard Worker  my $result = {};
3044*1208bc7eSAndroid Build Coastguard Worker  my $fullname_to_shortname_map = {};
3045*1208bc7eSAndroid Build Coastguard Worker  FillFullnameToShortnameMap($symbols, $fullname_to_shortname_map);
3046*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
3047*1208bc7eSAndroid Build Coastguard Worker    my $count = $profile->{$k};
3048*1208bc7eSAndroid Build Coastguard Worker    my @translated = TranslateStack($symbols, $fullname_to_shortname_map, $k);
3049*1208bc7eSAndroid Build Coastguard Worker    my @path = ();
3050*1208bc7eSAndroid Build Coastguard Worker    my %seen = ();
3051*1208bc7eSAndroid Build Coastguard Worker    $seen{''} = 1;      # So that empty keys are skipped
3052*1208bc7eSAndroid Build Coastguard Worker    foreach my $e (@translated) {
3053*1208bc7eSAndroid Build Coastguard Worker      # To avoid double-counting due to recursion, skip a stack-trace
3054*1208bc7eSAndroid Build Coastguard Worker      # entry if it has already been seen
3055*1208bc7eSAndroid Build Coastguard Worker      if (!$seen{$e}) {
3056*1208bc7eSAndroid Build Coastguard Worker        $seen{$e} = 1;
3057*1208bc7eSAndroid Build Coastguard Worker        push(@path, $e);
3058*1208bc7eSAndroid Build Coastguard Worker      }
3059*1208bc7eSAndroid Build Coastguard Worker    }
3060*1208bc7eSAndroid Build Coastguard Worker    my $reduced_path = join("\n", @path);
3061*1208bc7eSAndroid Build Coastguard Worker    AddEntry($result, $reduced_path, $count);
3062*1208bc7eSAndroid Build Coastguard Worker  }
3063*1208bc7eSAndroid Build Coastguard Worker  return $result;
3064*1208bc7eSAndroid Build Coastguard Worker}
3065*1208bc7eSAndroid Build Coastguard Worker
3066*1208bc7eSAndroid Build Coastguard Worker# Does the specified symbol array match the regexp?
3067*1208bc7eSAndroid Build Coastguard Workersub SymbolMatches {
3068*1208bc7eSAndroid Build Coastguard Worker  my $sym = shift;
3069*1208bc7eSAndroid Build Coastguard Worker  my $re = shift;
3070*1208bc7eSAndroid Build Coastguard Worker  if (defined($sym)) {
3071*1208bc7eSAndroid Build Coastguard Worker    for (my $i = 0; $i < $#{$sym}; $i += 3) {
3072*1208bc7eSAndroid Build Coastguard Worker      if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) {
3073*1208bc7eSAndroid Build Coastguard Worker        return 1;
3074*1208bc7eSAndroid Build Coastguard Worker      }
3075*1208bc7eSAndroid Build Coastguard Worker    }
3076*1208bc7eSAndroid Build Coastguard Worker  }
3077*1208bc7eSAndroid Build Coastguard Worker  return 0;
3078*1208bc7eSAndroid Build Coastguard Worker}
3079*1208bc7eSAndroid Build Coastguard Worker
3080*1208bc7eSAndroid Build Coastguard Worker# Focus only on paths involving specified regexps
3081*1208bc7eSAndroid Build Coastguard Workersub FocusProfile {
3082*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
3083*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
3084*1208bc7eSAndroid Build Coastguard Worker  my $focus = shift;
3085*1208bc7eSAndroid Build Coastguard Worker  my $result = {};
3086*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
3087*1208bc7eSAndroid Build Coastguard Worker    my $count = $profile->{$k};
3088*1208bc7eSAndroid Build Coastguard Worker    my @addrs = split(/\n/, $k);
3089*1208bc7eSAndroid Build Coastguard Worker    foreach my $a (@addrs) {
3090*1208bc7eSAndroid Build Coastguard Worker      # Reply if it matches either the address/shortname/fileline
3091*1208bc7eSAndroid Build Coastguard Worker      if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) {
3092*1208bc7eSAndroid Build Coastguard Worker        AddEntry($result, $k, $count);
3093*1208bc7eSAndroid Build Coastguard Worker        last;
3094*1208bc7eSAndroid Build Coastguard Worker      }
3095*1208bc7eSAndroid Build Coastguard Worker    }
3096*1208bc7eSAndroid Build Coastguard Worker  }
3097*1208bc7eSAndroid Build Coastguard Worker  return $result;
3098*1208bc7eSAndroid Build Coastguard Worker}
3099*1208bc7eSAndroid Build Coastguard Worker
3100*1208bc7eSAndroid Build Coastguard Worker# Focus only on paths not involving specified regexps
3101*1208bc7eSAndroid Build Coastguard Workersub IgnoreProfile {
3102*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
3103*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
3104*1208bc7eSAndroid Build Coastguard Worker  my $ignore = shift;
3105*1208bc7eSAndroid Build Coastguard Worker  my $result = {};
3106*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
3107*1208bc7eSAndroid Build Coastguard Worker    my $count = $profile->{$k};
3108*1208bc7eSAndroid Build Coastguard Worker    my @addrs = split(/\n/, $k);
3109*1208bc7eSAndroid Build Coastguard Worker    my $matched = 0;
3110*1208bc7eSAndroid Build Coastguard Worker    foreach my $a (@addrs) {
3111*1208bc7eSAndroid Build Coastguard Worker      # Reply if it matches either the address/shortname/fileline
3112*1208bc7eSAndroid Build Coastguard Worker      if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) {
3113*1208bc7eSAndroid Build Coastguard Worker        $matched = 1;
3114*1208bc7eSAndroid Build Coastguard Worker        last;
3115*1208bc7eSAndroid Build Coastguard Worker      }
3116*1208bc7eSAndroid Build Coastguard Worker    }
3117*1208bc7eSAndroid Build Coastguard Worker    if (!$matched) {
3118*1208bc7eSAndroid Build Coastguard Worker      AddEntry($result, $k, $count);
3119*1208bc7eSAndroid Build Coastguard Worker    }
3120*1208bc7eSAndroid Build Coastguard Worker  }
3121*1208bc7eSAndroid Build Coastguard Worker  return $result;
3122*1208bc7eSAndroid Build Coastguard Worker}
3123*1208bc7eSAndroid Build Coastguard Worker
3124*1208bc7eSAndroid Build Coastguard Worker# Get total count in profile
3125*1208bc7eSAndroid Build Coastguard Workersub TotalProfile {
3126*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
3127*1208bc7eSAndroid Build Coastguard Worker  my $result = 0;
3128*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$profile})) {
3129*1208bc7eSAndroid Build Coastguard Worker    $result += $profile->{$k};
3130*1208bc7eSAndroid Build Coastguard Worker  }
3131*1208bc7eSAndroid Build Coastguard Worker  return $result;
3132*1208bc7eSAndroid Build Coastguard Worker}
3133*1208bc7eSAndroid Build Coastguard Worker
3134*1208bc7eSAndroid Build Coastguard Worker# Add A to B
3135*1208bc7eSAndroid Build Coastguard Workersub AddProfile {
3136*1208bc7eSAndroid Build Coastguard Worker  my $A = shift;
3137*1208bc7eSAndroid Build Coastguard Worker  my $B = shift;
3138*1208bc7eSAndroid Build Coastguard Worker
3139*1208bc7eSAndroid Build Coastguard Worker  my $R = {};
3140*1208bc7eSAndroid Build Coastguard Worker  # add all keys in A
3141*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$A})) {
3142*1208bc7eSAndroid Build Coastguard Worker    my $v = $A->{$k};
3143*1208bc7eSAndroid Build Coastguard Worker    AddEntry($R, $k, $v);
3144*1208bc7eSAndroid Build Coastguard Worker  }
3145*1208bc7eSAndroid Build Coastguard Worker  # add all keys in B
3146*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$B})) {
3147*1208bc7eSAndroid Build Coastguard Worker    my $v = $B->{$k};
3148*1208bc7eSAndroid Build Coastguard Worker    AddEntry($R, $k, $v);
3149*1208bc7eSAndroid Build Coastguard Worker  }
3150*1208bc7eSAndroid Build Coastguard Worker  return $R;
3151*1208bc7eSAndroid Build Coastguard Worker}
3152*1208bc7eSAndroid Build Coastguard Worker
3153*1208bc7eSAndroid Build Coastguard Worker# Merges symbol maps
3154*1208bc7eSAndroid Build Coastguard Workersub MergeSymbols {
3155*1208bc7eSAndroid Build Coastguard Worker  my $A = shift;
3156*1208bc7eSAndroid Build Coastguard Worker  my $B = shift;
3157*1208bc7eSAndroid Build Coastguard Worker
3158*1208bc7eSAndroid Build Coastguard Worker  my $R = {};
3159*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$A})) {
3160*1208bc7eSAndroid Build Coastguard Worker    $R->{$k} = $A->{$k};
3161*1208bc7eSAndroid Build Coastguard Worker  }
3162*1208bc7eSAndroid Build Coastguard Worker  if (defined($B)) {
3163*1208bc7eSAndroid Build Coastguard Worker    foreach my $k (keys(%{$B})) {
3164*1208bc7eSAndroid Build Coastguard Worker      $R->{$k} = $B->{$k};
3165*1208bc7eSAndroid Build Coastguard Worker    }
3166*1208bc7eSAndroid Build Coastguard Worker  }
3167*1208bc7eSAndroid Build Coastguard Worker  return $R;
3168*1208bc7eSAndroid Build Coastguard Worker}
3169*1208bc7eSAndroid Build Coastguard Worker
3170*1208bc7eSAndroid Build Coastguard Worker
3171*1208bc7eSAndroid Build Coastguard Worker# Add A to B
3172*1208bc7eSAndroid Build Coastguard Workersub AddPcs {
3173*1208bc7eSAndroid Build Coastguard Worker  my $A = shift;
3174*1208bc7eSAndroid Build Coastguard Worker  my $B = shift;
3175*1208bc7eSAndroid Build Coastguard Worker
3176*1208bc7eSAndroid Build Coastguard Worker  my $R = {};
3177*1208bc7eSAndroid Build Coastguard Worker  # add all keys in A
3178*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$A})) {
3179*1208bc7eSAndroid Build Coastguard Worker    $R->{$k} = 1
3180*1208bc7eSAndroid Build Coastguard Worker  }
3181*1208bc7eSAndroid Build Coastguard Worker  # add all keys in B
3182*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$B})) {
3183*1208bc7eSAndroid Build Coastguard Worker    $R->{$k} = 1
3184*1208bc7eSAndroid Build Coastguard Worker  }
3185*1208bc7eSAndroid Build Coastguard Worker  return $R;
3186*1208bc7eSAndroid Build Coastguard Worker}
3187*1208bc7eSAndroid Build Coastguard Worker
3188*1208bc7eSAndroid Build Coastguard Worker# Subtract B from A
3189*1208bc7eSAndroid Build Coastguard Workersub SubtractProfile {
3190*1208bc7eSAndroid Build Coastguard Worker  my $A = shift;
3191*1208bc7eSAndroid Build Coastguard Worker  my $B = shift;
3192*1208bc7eSAndroid Build Coastguard Worker
3193*1208bc7eSAndroid Build Coastguard Worker  my $R = {};
3194*1208bc7eSAndroid Build Coastguard Worker  foreach my $k (keys(%{$A})) {
3195*1208bc7eSAndroid Build Coastguard Worker    my $v = $A->{$k} - GetEntry($B, $k);
3196*1208bc7eSAndroid Build Coastguard Worker    if ($v < 0 && $main::opt_drop_negative) {
3197*1208bc7eSAndroid Build Coastguard Worker      $v = 0;
3198*1208bc7eSAndroid Build Coastguard Worker    }
3199*1208bc7eSAndroid Build Coastguard Worker    AddEntry($R, $k, $v);
3200*1208bc7eSAndroid Build Coastguard Worker  }
3201*1208bc7eSAndroid Build Coastguard Worker  if (!$main::opt_drop_negative) {
3202*1208bc7eSAndroid Build Coastguard Worker    # Take care of when subtracted profile has more entries
3203*1208bc7eSAndroid Build Coastguard Worker    foreach my $k (keys(%{$B})) {
3204*1208bc7eSAndroid Build Coastguard Worker      if (!exists($A->{$k})) {
3205*1208bc7eSAndroid Build Coastguard Worker        AddEntry($R, $k, 0 - $B->{$k});
3206*1208bc7eSAndroid Build Coastguard Worker      }
3207*1208bc7eSAndroid Build Coastguard Worker    }
3208*1208bc7eSAndroid Build Coastguard Worker  }
3209*1208bc7eSAndroid Build Coastguard Worker  return $R;
3210*1208bc7eSAndroid Build Coastguard Worker}
3211*1208bc7eSAndroid Build Coastguard Worker
3212*1208bc7eSAndroid Build Coastguard Worker# Get entry from profile; zero if not present
3213*1208bc7eSAndroid Build Coastguard Workersub GetEntry {
3214*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
3215*1208bc7eSAndroid Build Coastguard Worker  my $k = shift;
3216*1208bc7eSAndroid Build Coastguard Worker  if (exists($profile->{$k})) {
3217*1208bc7eSAndroid Build Coastguard Worker    return $profile->{$k};
3218*1208bc7eSAndroid Build Coastguard Worker  } else {
3219*1208bc7eSAndroid Build Coastguard Worker    return 0;
3220*1208bc7eSAndroid Build Coastguard Worker  }
3221*1208bc7eSAndroid Build Coastguard Worker}
3222*1208bc7eSAndroid Build Coastguard Worker
3223*1208bc7eSAndroid Build Coastguard Worker# Add entry to specified profile
3224*1208bc7eSAndroid Build Coastguard Workersub AddEntry {
3225*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
3226*1208bc7eSAndroid Build Coastguard Worker  my $k = shift;
3227*1208bc7eSAndroid Build Coastguard Worker  my $n = shift;
3228*1208bc7eSAndroid Build Coastguard Worker  if (!exists($profile->{$k})) {
3229*1208bc7eSAndroid Build Coastguard Worker    $profile->{$k} = 0;
3230*1208bc7eSAndroid Build Coastguard Worker  }
3231*1208bc7eSAndroid Build Coastguard Worker  $profile->{$k} += $n;
3232*1208bc7eSAndroid Build Coastguard Worker}
3233*1208bc7eSAndroid Build Coastguard Worker
3234*1208bc7eSAndroid Build Coastguard Worker# Add a stack of entries to specified profile, and add them to the $pcs
3235*1208bc7eSAndroid Build Coastguard Worker# list.
3236*1208bc7eSAndroid Build Coastguard Workersub AddEntries {
3237*1208bc7eSAndroid Build Coastguard Worker  my $profile = shift;
3238*1208bc7eSAndroid Build Coastguard Worker  my $pcs = shift;
3239*1208bc7eSAndroid Build Coastguard Worker  my $stack = shift;
3240*1208bc7eSAndroid Build Coastguard Worker  my $count = shift;
3241*1208bc7eSAndroid Build Coastguard Worker  my @k = ();
3242*1208bc7eSAndroid Build Coastguard Worker
3243*1208bc7eSAndroid Build Coastguard Worker  foreach my $e (split(/\s+/, $stack)) {
3244*1208bc7eSAndroid Build Coastguard Worker    my $pc = HexExtend($e);
3245*1208bc7eSAndroid Build Coastguard Worker    $pcs->{$pc} = 1;
3246*1208bc7eSAndroid Build Coastguard Worker    push @k, $pc;
3247*1208bc7eSAndroid Build Coastguard Worker  }
3248*1208bc7eSAndroid Build Coastguard Worker  AddEntry($profile, (join "\n", @k), $count);
3249*1208bc7eSAndroid Build Coastguard Worker}
3250*1208bc7eSAndroid Build Coastguard Worker
3251*1208bc7eSAndroid Build Coastguard Worker##### Code to profile a server dynamically #####
3252*1208bc7eSAndroid Build Coastguard Worker
3253*1208bc7eSAndroid Build Coastguard Workersub CheckSymbolPage {
3254*1208bc7eSAndroid Build Coastguard Worker  my $url = SymbolPageURL();
3255*1208bc7eSAndroid Build Coastguard Worker  my $command = ShellEscape(@URL_FETCHER, $url);
3256*1208bc7eSAndroid Build Coastguard Worker  open(SYMBOL, "$command |") or error($command);
3257*1208bc7eSAndroid Build Coastguard Worker  my $line = <SYMBOL>;
3258*1208bc7eSAndroid Build Coastguard Worker  $line =~ s/\r//g;         # turn windows-looking lines into unix-looking lines
3259*1208bc7eSAndroid Build Coastguard Worker  close(SYMBOL);
3260*1208bc7eSAndroid Build Coastguard Worker  unless (defined($line)) {
3261*1208bc7eSAndroid Build Coastguard Worker    error("$url doesn't exist\n");
3262*1208bc7eSAndroid Build Coastguard Worker  }
3263*1208bc7eSAndroid Build Coastguard Worker
3264*1208bc7eSAndroid Build Coastguard Worker  if ($line =~ /^num_symbols:\s+(\d+)$/) {
3265*1208bc7eSAndroid Build Coastguard Worker    if ($1 == 0) {
3266*1208bc7eSAndroid Build Coastguard Worker      error("Stripped binary. No symbols available.\n");
3267*1208bc7eSAndroid Build Coastguard Worker    }
3268*1208bc7eSAndroid Build Coastguard Worker  } else {
3269*1208bc7eSAndroid Build Coastguard Worker    error("Failed to get the number of symbols from $url\n");
3270*1208bc7eSAndroid Build Coastguard Worker  }
3271*1208bc7eSAndroid Build Coastguard Worker}
3272*1208bc7eSAndroid Build Coastguard Worker
3273*1208bc7eSAndroid Build Coastguard Workersub IsProfileURL {
3274*1208bc7eSAndroid Build Coastguard Worker  my $profile_name = shift;
3275*1208bc7eSAndroid Build Coastguard Worker  if (-f $profile_name) {
3276*1208bc7eSAndroid Build Coastguard Worker    printf STDERR "Using local file $profile_name.\n";
3277*1208bc7eSAndroid Build Coastguard Worker    return 0;
3278*1208bc7eSAndroid Build Coastguard Worker  }
3279*1208bc7eSAndroid Build Coastguard Worker  return 1;
3280*1208bc7eSAndroid Build Coastguard Worker}
3281*1208bc7eSAndroid Build Coastguard Worker
3282*1208bc7eSAndroid Build Coastguard Workersub ParseProfileURL {
3283*1208bc7eSAndroid Build Coastguard Worker  my $profile_name = shift;
3284*1208bc7eSAndroid Build Coastguard Worker
3285*1208bc7eSAndroid Build Coastguard Worker  if (!defined($profile_name) || $profile_name eq "") {
3286*1208bc7eSAndroid Build Coastguard Worker    return ();
3287*1208bc7eSAndroid Build Coastguard Worker  }
3288*1208bc7eSAndroid Build Coastguard Worker
3289*1208bc7eSAndroid Build Coastguard Worker  # Split profile URL - matches all non-empty strings, so no test.
3290*1208bc7eSAndroid Build Coastguard Worker  $profile_name =~ m,^(https?://)?([^/]+)(.*?)(/|$PROFILES)?$,;
3291*1208bc7eSAndroid Build Coastguard Worker
3292*1208bc7eSAndroid Build Coastguard Worker  my $proto = $1 || "http://";
3293*1208bc7eSAndroid Build Coastguard Worker  my $hostport = $2;
3294*1208bc7eSAndroid Build Coastguard Worker  my $prefix = $3;
3295*1208bc7eSAndroid Build Coastguard Worker  my $profile = $4 || "/";
3296*1208bc7eSAndroid Build Coastguard Worker
3297*1208bc7eSAndroid Build Coastguard Worker  my $host = $hostport;
3298*1208bc7eSAndroid Build Coastguard Worker  $host =~ s/:.*//;
3299*1208bc7eSAndroid Build Coastguard Worker
3300*1208bc7eSAndroid Build Coastguard Worker  my $baseurl = "$proto$hostport$prefix";
3301*1208bc7eSAndroid Build Coastguard Worker  return ($host, $baseurl, $profile);
3302*1208bc7eSAndroid Build Coastguard Worker}
3303*1208bc7eSAndroid Build Coastguard Worker
3304*1208bc7eSAndroid Build Coastguard Worker# We fetch symbols from the first profile argument.
3305*1208bc7eSAndroid Build Coastguard Workersub SymbolPageURL {
3306*1208bc7eSAndroid Build Coastguard Worker  my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]);
3307*1208bc7eSAndroid Build Coastguard Worker  return "$baseURL$SYMBOL_PAGE";
3308*1208bc7eSAndroid Build Coastguard Worker}
3309*1208bc7eSAndroid Build Coastguard Worker
3310*1208bc7eSAndroid Build Coastguard Workersub FetchProgramName() {
3311*1208bc7eSAndroid Build Coastguard Worker  my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]);
3312*1208bc7eSAndroid Build Coastguard Worker  my $url = "$baseURL$PROGRAM_NAME_PAGE";
3313*1208bc7eSAndroid Build Coastguard Worker  my $command_line = ShellEscape(@URL_FETCHER, $url);
3314*1208bc7eSAndroid Build Coastguard Worker  open(CMDLINE, "$command_line |") or error($command_line);
3315*1208bc7eSAndroid Build Coastguard Worker  my $cmdline = <CMDLINE>;
3316*1208bc7eSAndroid Build Coastguard Worker  $cmdline =~ s/\r//g;   # turn windows-looking lines into unix-looking lines
3317*1208bc7eSAndroid Build Coastguard Worker  close(CMDLINE);
3318*1208bc7eSAndroid Build Coastguard Worker  error("Failed to get program name from $url\n") unless defined($cmdline);
3319*1208bc7eSAndroid Build Coastguard Worker  $cmdline =~ s/\x00.+//;  # Remove argv[1] and latters.
3320*1208bc7eSAndroid Build Coastguard Worker  $cmdline =~ s!\n!!g;  # Remove LFs.
3321*1208bc7eSAndroid Build Coastguard Worker  return $cmdline;
3322*1208bc7eSAndroid Build Coastguard Worker}
3323*1208bc7eSAndroid Build Coastguard Worker
3324*1208bc7eSAndroid Build Coastguard Worker# Gee, curl's -L (--location) option isn't reliable at least
3325*1208bc7eSAndroid Build Coastguard Worker# with its 7.12.3 version.  Curl will forget to post data if
3326*1208bc7eSAndroid Build Coastguard Worker# there is a redirection.  This function is a workaround for
3327*1208bc7eSAndroid Build Coastguard Worker# curl.  Redirection happens on borg hosts.
3328*1208bc7eSAndroid Build Coastguard Workersub ResolveRedirectionForCurl {
3329*1208bc7eSAndroid Build Coastguard Worker  my $url = shift;
3330*1208bc7eSAndroid Build Coastguard Worker  my $command_line = ShellEscape(@URL_FETCHER, "--head", $url);
3331*1208bc7eSAndroid Build Coastguard Worker  open(CMDLINE, "$command_line |") or error($command_line);
3332*1208bc7eSAndroid Build Coastguard Worker  while (<CMDLINE>) {
3333*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;         # turn windows-looking lines into unix-looking lines
3334*1208bc7eSAndroid Build Coastguard Worker    if (/^Location: (.*)/) {
3335*1208bc7eSAndroid Build Coastguard Worker      $url = $1;
3336*1208bc7eSAndroid Build Coastguard Worker    }
3337*1208bc7eSAndroid Build Coastguard Worker  }
3338*1208bc7eSAndroid Build Coastguard Worker  close(CMDLINE);
3339*1208bc7eSAndroid Build Coastguard Worker  return $url;
3340*1208bc7eSAndroid Build Coastguard Worker}
3341*1208bc7eSAndroid Build Coastguard Worker
3342*1208bc7eSAndroid Build Coastguard Worker# Add a timeout flat to URL_FETCHER.  Returns a new list.
3343*1208bc7eSAndroid Build Coastguard Workersub AddFetchTimeout {
3344*1208bc7eSAndroid Build Coastguard Worker  my $timeout = shift;
3345*1208bc7eSAndroid Build Coastguard Worker  my @fetcher = @_;
3346*1208bc7eSAndroid Build Coastguard Worker  if (defined($timeout)) {
3347*1208bc7eSAndroid Build Coastguard Worker    if (join(" ", @fetcher) =~ m/\bcurl -s/) {
3348*1208bc7eSAndroid Build Coastguard Worker      push(@fetcher, "--max-time", sprintf("%d", $timeout));
3349*1208bc7eSAndroid Build Coastguard Worker    } elsif (join(" ", @fetcher) =~ m/\brpcget\b/) {
3350*1208bc7eSAndroid Build Coastguard Worker      push(@fetcher, sprintf("--deadline=%d", $timeout));
3351*1208bc7eSAndroid Build Coastguard Worker    }
3352*1208bc7eSAndroid Build Coastguard Worker  }
3353*1208bc7eSAndroid Build Coastguard Worker  return @fetcher;
3354*1208bc7eSAndroid Build Coastguard Worker}
3355*1208bc7eSAndroid Build Coastguard Worker
3356*1208bc7eSAndroid Build Coastguard Worker# Reads a symbol map from the file handle name given as $1, returning
3357*1208bc7eSAndroid Build Coastguard Worker# the resulting symbol map.  Also processes variables relating to symbols.
3358*1208bc7eSAndroid Build Coastguard Worker# Currently, the only variable processed is 'binary=<value>' which updates
3359*1208bc7eSAndroid Build Coastguard Worker# $main::prog to have the correct program name.
3360*1208bc7eSAndroid Build Coastguard Workersub ReadSymbols {
3361*1208bc7eSAndroid Build Coastguard Worker  my $in = shift;
3362*1208bc7eSAndroid Build Coastguard Worker  my $map = {};
3363*1208bc7eSAndroid Build Coastguard Worker  while (<$in>) {
3364*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;         # turn windows-looking lines into unix-looking lines
3365*1208bc7eSAndroid Build Coastguard Worker    # Removes all the leading zeroes from the symbols, see comment below.
3366*1208bc7eSAndroid Build Coastguard Worker    if (m/^0x0*([0-9a-f]+)\s+(.+)/) {
3367*1208bc7eSAndroid Build Coastguard Worker      $map->{$1} = $2;
3368*1208bc7eSAndroid Build Coastguard Worker    } elsif (m/^---/) {
3369*1208bc7eSAndroid Build Coastguard Worker      last;
3370*1208bc7eSAndroid Build Coastguard Worker    } elsif (m/^([a-z][^=]*)=(.*)$/ ) {
3371*1208bc7eSAndroid Build Coastguard Worker      my ($variable, $value) = ($1, $2);
3372*1208bc7eSAndroid Build Coastguard Worker      for ($variable, $value) {
3373*1208bc7eSAndroid Build Coastguard Worker        s/^\s+//;
3374*1208bc7eSAndroid Build Coastguard Worker        s/\s+$//;
3375*1208bc7eSAndroid Build Coastguard Worker      }
3376*1208bc7eSAndroid Build Coastguard Worker      if ($variable eq "binary") {
3377*1208bc7eSAndroid Build Coastguard Worker        if ($main::prog ne $UNKNOWN_BINARY && $main::prog ne $value) {
3378*1208bc7eSAndroid Build Coastguard Worker          printf STDERR ("Warning: Mismatched binary name '%s', using '%s'.\n",
3379*1208bc7eSAndroid Build Coastguard Worker                         $main::prog, $value);
3380*1208bc7eSAndroid Build Coastguard Worker        }
3381*1208bc7eSAndroid Build Coastguard Worker        $main::prog = $value;
3382*1208bc7eSAndroid Build Coastguard Worker      } else {
3383*1208bc7eSAndroid Build Coastguard Worker        printf STDERR ("Ignoring unknown variable in symbols list: " .
3384*1208bc7eSAndroid Build Coastguard Worker            "'%s' = '%s'\n", $variable, $value);
3385*1208bc7eSAndroid Build Coastguard Worker      }
3386*1208bc7eSAndroid Build Coastguard Worker    }
3387*1208bc7eSAndroid Build Coastguard Worker  }
3388*1208bc7eSAndroid Build Coastguard Worker  return $map;
3389*1208bc7eSAndroid Build Coastguard Worker}
3390*1208bc7eSAndroid Build Coastguard Worker
3391*1208bc7eSAndroid Build Coastguard Workersub URLEncode {
3392*1208bc7eSAndroid Build Coastguard Worker  my $str = shift;
3393*1208bc7eSAndroid Build Coastguard Worker  $str =~ s/([^A-Za-z0-9\-_.!~*'()])/ sprintf "%%%02x", ord $1 /eg;
3394*1208bc7eSAndroid Build Coastguard Worker  return $str;
3395*1208bc7eSAndroid Build Coastguard Worker}
3396*1208bc7eSAndroid Build Coastguard Worker
3397*1208bc7eSAndroid Build Coastguard Workersub AppendSymbolFilterParams {
3398*1208bc7eSAndroid Build Coastguard Worker  my $url = shift;
3399*1208bc7eSAndroid Build Coastguard Worker  my @params = ();
3400*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_retain ne '') {
3401*1208bc7eSAndroid Build Coastguard Worker    push(@params, sprintf("retain=%s", URLEncode($main::opt_retain)));
3402*1208bc7eSAndroid Build Coastguard Worker  }
3403*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_exclude ne '') {
3404*1208bc7eSAndroid Build Coastguard Worker    push(@params, sprintf("exclude=%s", URLEncode($main::opt_exclude)));
3405*1208bc7eSAndroid Build Coastguard Worker  }
3406*1208bc7eSAndroid Build Coastguard Worker  if (scalar @params > 0) {
3407*1208bc7eSAndroid Build Coastguard Worker    $url = sprintf("%s?%s", $url, join("&", @params));
3408*1208bc7eSAndroid Build Coastguard Worker  }
3409*1208bc7eSAndroid Build Coastguard Worker  return $url;
3410*1208bc7eSAndroid Build Coastguard Worker}
3411*1208bc7eSAndroid Build Coastguard Worker
3412*1208bc7eSAndroid Build Coastguard Worker# Fetches and processes symbols to prepare them for use in the profile output
3413*1208bc7eSAndroid Build Coastguard Worker# code.  If the optional 'symbol_map' arg is not given, fetches symbols from
3414*1208bc7eSAndroid Build Coastguard Worker# $SYMBOL_PAGE for all PC values found in profile.  Otherwise, the raw symbols
3415*1208bc7eSAndroid Build Coastguard Worker# are assumed to have already been fetched into 'symbol_map' and are simply
3416*1208bc7eSAndroid Build Coastguard Worker# extracted and processed.
3417*1208bc7eSAndroid Build Coastguard Workersub FetchSymbols {
3418*1208bc7eSAndroid Build Coastguard Worker  my $pcset = shift;
3419*1208bc7eSAndroid Build Coastguard Worker  my $symbol_map = shift;
3420*1208bc7eSAndroid Build Coastguard Worker
3421*1208bc7eSAndroid Build Coastguard Worker  my %seen = ();
3422*1208bc7eSAndroid Build Coastguard Worker  my @pcs = grep { !$seen{$_}++ } keys(%$pcset);  # uniq
3423*1208bc7eSAndroid Build Coastguard Worker
3424*1208bc7eSAndroid Build Coastguard Worker  if (!defined($symbol_map)) {
3425*1208bc7eSAndroid Build Coastguard Worker    my $post_data = join("+", sort((map {"0x" . "$_"} @pcs)));
3426*1208bc7eSAndroid Build Coastguard Worker
3427*1208bc7eSAndroid Build Coastguard Worker    open(POSTFILE, ">$main::tmpfile_sym");
3428*1208bc7eSAndroid Build Coastguard Worker    print POSTFILE $post_data;
3429*1208bc7eSAndroid Build Coastguard Worker    close(POSTFILE);
3430*1208bc7eSAndroid Build Coastguard Worker
3431*1208bc7eSAndroid Build Coastguard Worker    my $url = SymbolPageURL();
3432*1208bc7eSAndroid Build Coastguard Worker
3433*1208bc7eSAndroid Build Coastguard Worker    my $command_line;
3434*1208bc7eSAndroid Build Coastguard Worker    if (join(" ", @URL_FETCHER) =~ m/\bcurl -s/) {
3435*1208bc7eSAndroid Build Coastguard Worker      $url = ResolveRedirectionForCurl($url);
3436*1208bc7eSAndroid Build Coastguard Worker      $url = AppendSymbolFilterParams($url);
3437*1208bc7eSAndroid Build Coastguard Worker      $command_line = ShellEscape(@URL_FETCHER, "-d", "\@$main::tmpfile_sym",
3438*1208bc7eSAndroid Build Coastguard Worker                                  $url);
3439*1208bc7eSAndroid Build Coastguard Worker    } else {
3440*1208bc7eSAndroid Build Coastguard Worker      $url = AppendSymbolFilterParams($url);
3441*1208bc7eSAndroid Build Coastguard Worker      $command_line = (ShellEscape(@URL_FETCHER, "--post", $url)
3442*1208bc7eSAndroid Build Coastguard Worker                       . " < " . ShellEscape($main::tmpfile_sym));
3443*1208bc7eSAndroid Build Coastguard Worker    }
3444*1208bc7eSAndroid Build Coastguard Worker    # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols.
3445*1208bc7eSAndroid Build Coastguard Worker    my $escaped_cppfilt = ShellEscape($obj_tool_map{"c++filt"});
3446*1208bc7eSAndroid Build Coastguard Worker    open(SYMBOL, "$command_line | $escaped_cppfilt |") or error($command_line);
3447*1208bc7eSAndroid Build Coastguard Worker    $symbol_map = ReadSymbols(*SYMBOL{IO});
3448*1208bc7eSAndroid Build Coastguard Worker    close(SYMBOL);
3449*1208bc7eSAndroid Build Coastguard Worker  }
3450*1208bc7eSAndroid Build Coastguard Worker
3451*1208bc7eSAndroid Build Coastguard Worker  my $symbols = {};
3452*1208bc7eSAndroid Build Coastguard Worker  foreach my $pc (@pcs) {
3453*1208bc7eSAndroid Build Coastguard Worker    my $fullname;
3454*1208bc7eSAndroid Build Coastguard Worker    # For 64 bits binaries, symbols are extracted with 8 leading zeroes.
3455*1208bc7eSAndroid Build Coastguard Worker    # Then /symbol reads the long symbols in as uint64, and outputs
3456*1208bc7eSAndroid Build Coastguard Worker    # the result with a "0x%08llx" format which get rid of the zeroes.
3457*1208bc7eSAndroid Build Coastguard Worker    # By removing all the leading zeroes in both $pc and the symbols from
3458*1208bc7eSAndroid Build Coastguard Worker    # /symbol, the symbols match and are retrievable from the map.
3459*1208bc7eSAndroid Build Coastguard Worker    my $shortpc = $pc;
3460*1208bc7eSAndroid Build Coastguard Worker    $shortpc =~ s/^0*//;
3461*1208bc7eSAndroid Build Coastguard Worker    # Each line may have a list of names, which includes the function
3462*1208bc7eSAndroid Build Coastguard Worker    # and also other functions it has inlined.  They are separated (in
3463*1208bc7eSAndroid Build Coastguard Worker    # PrintSymbolizedProfile), by --, which is illegal in function names.
3464*1208bc7eSAndroid Build Coastguard Worker    my $fullnames;
3465*1208bc7eSAndroid Build Coastguard Worker    if (defined($symbol_map->{$shortpc})) {
3466*1208bc7eSAndroid Build Coastguard Worker      $fullnames = $symbol_map->{$shortpc};
3467*1208bc7eSAndroid Build Coastguard Worker    } else {
3468*1208bc7eSAndroid Build Coastguard Worker      $fullnames = "0x" . $pc;  # Just use addresses
3469*1208bc7eSAndroid Build Coastguard Worker    }
3470*1208bc7eSAndroid Build Coastguard Worker    my $sym = [];
3471*1208bc7eSAndroid Build Coastguard Worker    $symbols->{$pc} = $sym;
3472*1208bc7eSAndroid Build Coastguard Worker    foreach my $fullname (split("--", $fullnames)) {
3473*1208bc7eSAndroid Build Coastguard Worker      my $name = ShortFunctionName($fullname);
3474*1208bc7eSAndroid Build Coastguard Worker      push(@{$sym}, $name, "?", $fullname);
3475*1208bc7eSAndroid Build Coastguard Worker    }
3476*1208bc7eSAndroid Build Coastguard Worker  }
3477*1208bc7eSAndroid Build Coastguard Worker  return $symbols;
3478*1208bc7eSAndroid Build Coastguard Worker}
3479*1208bc7eSAndroid Build Coastguard Worker
3480*1208bc7eSAndroid Build Coastguard Workersub BaseName {
3481*1208bc7eSAndroid Build Coastguard Worker  my $file_name = shift;
3482*1208bc7eSAndroid Build Coastguard Worker  $file_name =~ s!^.*/!!;  # Remove directory name
3483*1208bc7eSAndroid Build Coastguard Worker  return $file_name;
3484*1208bc7eSAndroid Build Coastguard Worker}
3485*1208bc7eSAndroid Build Coastguard Worker
3486*1208bc7eSAndroid Build Coastguard Workersub MakeProfileBaseName {
3487*1208bc7eSAndroid Build Coastguard Worker  my ($binary_name, $profile_name) = @_;
3488*1208bc7eSAndroid Build Coastguard Worker  my ($host, $baseURL, $path) = ParseProfileURL($profile_name);
3489*1208bc7eSAndroid Build Coastguard Worker  my $binary_shortname = BaseName($binary_name);
3490*1208bc7eSAndroid Build Coastguard Worker  return sprintf("%s.%s.%s",
3491*1208bc7eSAndroid Build Coastguard Worker                 $binary_shortname, $main::op_time, $host);
3492*1208bc7eSAndroid Build Coastguard Worker}
3493*1208bc7eSAndroid Build Coastguard Worker
3494*1208bc7eSAndroid Build Coastguard Workersub FetchDynamicProfile {
3495*1208bc7eSAndroid Build Coastguard Worker  my $binary_name = shift;
3496*1208bc7eSAndroid Build Coastguard Worker  my $profile_name = shift;
3497*1208bc7eSAndroid Build Coastguard Worker  my $fetch_name_only = shift;
3498*1208bc7eSAndroid Build Coastguard Worker  my $encourage_patience = shift;
3499*1208bc7eSAndroid Build Coastguard Worker
3500*1208bc7eSAndroid Build Coastguard Worker  if (!IsProfileURL($profile_name)) {
3501*1208bc7eSAndroid Build Coastguard Worker    return $profile_name;
3502*1208bc7eSAndroid Build Coastguard Worker  } else {
3503*1208bc7eSAndroid Build Coastguard Worker    my ($host, $baseURL, $path) = ParseProfileURL($profile_name);
3504*1208bc7eSAndroid Build Coastguard Worker    if ($path eq "" || $path eq "/") {
3505*1208bc7eSAndroid Build Coastguard Worker      # Missing type specifier defaults to cpu-profile
3506*1208bc7eSAndroid Build Coastguard Worker      $path = $PROFILE_PAGE;
3507*1208bc7eSAndroid Build Coastguard Worker    }
3508*1208bc7eSAndroid Build Coastguard Worker
3509*1208bc7eSAndroid Build Coastguard Worker    my $profile_file = MakeProfileBaseName($binary_name, $profile_name);
3510*1208bc7eSAndroid Build Coastguard Worker
3511*1208bc7eSAndroid Build Coastguard Worker    my $url = "$baseURL$path";
3512*1208bc7eSAndroid Build Coastguard Worker    my $fetch_timeout = undef;
3513*1208bc7eSAndroid Build Coastguard Worker    if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE/) {
3514*1208bc7eSAndroid Build Coastguard Worker      if ($path =~ m/[?]/) {
3515*1208bc7eSAndroid Build Coastguard Worker        $url .= "&";
3516*1208bc7eSAndroid Build Coastguard Worker      } else {
3517*1208bc7eSAndroid Build Coastguard Worker        $url .= "?";
3518*1208bc7eSAndroid Build Coastguard Worker      }
3519*1208bc7eSAndroid Build Coastguard Worker      $url .= sprintf("seconds=%d", $main::opt_seconds);
3520*1208bc7eSAndroid Build Coastguard Worker      $fetch_timeout = $main::opt_seconds * 1.01 + 60;
3521*1208bc7eSAndroid Build Coastguard Worker      # Set $profile_type for consumption by PrintSymbolizedProfile.
3522*1208bc7eSAndroid Build Coastguard Worker      $main::profile_type = 'cpu';
3523*1208bc7eSAndroid Build Coastguard Worker    } else {
3524*1208bc7eSAndroid Build Coastguard Worker      # For non-CPU profiles, we add a type-extension to
3525*1208bc7eSAndroid Build Coastguard Worker      # the target profile file name.
3526*1208bc7eSAndroid Build Coastguard Worker      my $suffix = $path;
3527*1208bc7eSAndroid Build Coastguard Worker      $suffix =~ s,/,.,g;
3528*1208bc7eSAndroid Build Coastguard Worker      $profile_file .= $suffix;
3529*1208bc7eSAndroid Build Coastguard Worker      # Set $profile_type for consumption by PrintSymbolizedProfile.
3530*1208bc7eSAndroid Build Coastguard Worker      if ($path =~ m/$HEAP_PAGE/) {
3531*1208bc7eSAndroid Build Coastguard Worker        $main::profile_type = 'heap';
3532*1208bc7eSAndroid Build Coastguard Worker      } elsif ($path =~ m/$GROWTH_PAGE/) {
3533*1208bc7eSAndroid Build Coastguard Worker        $main::profile_type = 'growth';
3534*1208bc7eSAndroid Build Coastguard Worker      } elsif ($path =~ m/$CONTENTION_PAGE/) {
3535*1208bc7eSAndroid Build Coastguard Worker        $main::profile_type = 'contention';
3536*1208bc7eSAndroid Build Coastguard Worker      }
3537*1208bc7eSAndroid Build Coastguard Worker    }
3538*1208bc7eSAndroid Build Coastguard Worker
3539*1208bc7eSAndroid Build Coastguard Worker    my $profile_dir = $ENV{"JEPROF_TMPDIR"} || ($ENV{HOME} . "/jeprof");
3540*1208bc7eSAndroid Build Coastguard Worker    if (! -d $profile_dir) {
3541*1208bc7eSAndroid Build Coastguard Worker      mkdir($profile_dir)
3542*1208bc7eSAndroid Build Coastguard Worker          || die("Unable to create profile directory $profile_dir: $!\n");
3543*1208bc7eSAndroid Build Coastguard Worker    }
3544*1208bc7eSAndroid Build Coastguard Worker    my $tmp_profile = "$profile_dir/.tmp.$profile_file";
3545*1208bc7eSAndroid Build Coastguard Worker    my $real_profile = "$profile_dir/$profile_file";
3546*1208bc7eSAndroid Build Coastguard Worker
3547*1208bc7eSAndroid Build Coastguard Worker    if ($fetch_name_only > 0) {
3548*1208bc7eSAndroid Build Coastguard Worker      return $real_profile;
3549*1208bc7eSAndroid Build Coastguard Worker    }
3550*1208bc7eSAndroid Build Coastguard Worker
3551*1208bc7eSAndroid Build Coastguard Worker    my @fetcher = AddFetchTimeout($fetch_timeout, @URL_FETCHER);
3552*1208bc7eSAndroid Build Coastguard Worker    my $cmd = ShellEscape(@fetcher, $url) . " > " . ShellEscape($tmp_profile);
3553*1208bc7eSAndroid Build Coastguard Worker    if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE|$CENSUSPROFILE_PAGE/){
3554*1208bc7eSAndroid Build Coastguard Worker      print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n  ${real_profile}\n";
3555*1208bc7eSAndroid Build Coastguard Worker      if ($encourage_patience) {
3556*1208bc7eSAndroid Build Coastguard Worker        print STDERR "Be patient...\n";
3557*1208bc7eSAndroid Build Coastguard Worker      }
3558*1208bc7eSAndroid Build Coastguard Worker    } else {
3559*1208bc7eSAndroid Build Coastguard Worker      print STDERR "Fetching $path profile from $url to\n  ${real_profile}\n";
3560*1208bc7eSAndroid Build Coastguard Worker    }
3561*1208bc7eSAndroid Build Coastguard Worker
3562*1208bc7eSAndroid Build Coastguard Worker    (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n");
3563*1208bc7eSAndroid Build Coastguard Worker    (system("mv", $tmp_profile, $real_profile) == 0) || error("Unable to rename profile\n");
3564*1208bc7eSAndroid Build Coastguard Worker    print STDERR "Wrote profile to $real_profile\n";
3565*1208bc7eSAndroid Build Coastguard Worker    $main::collected_profile = $real_profile;
3566*1208bc7eSAndroid Build Coastguard Worker    return $main::collected_profile;
3567*1208bc7eSAndroid Build Coastguard Worker  }
3568*1208bc7eSAndroid Build Coastguard Worker}
3569*1208bc7eSAndroid Build Coastguard Worker
3570*1208bc7eSAndroid Build Coastguard Worker# Collect profiles in parallel
3571*1208bc7eSAndroid Build Coastguard Workersub FetchDynamicProfiles {
3572*1208bc7eSAndroid Build Coastguard Worker  my $items = scalar(@main::pfile_args);
3573*1208bc7eSAndroid Build Coastguard Worker  my $levels = log($items) / log(2);
3574*1208bc7eSAndroid Build Coastguard Worker
3575*1208bc7eSAndroid Build Coastguard Worker  if ($items == 1) {
3576*1208bc7eSAndroid Build Coastguard Worker    $main::profile_files[0] = FetchDynamicProfile($main::prog, $main::pfile_args[0], 0, 1);
3577*1208bc7eSAndroid Build Coastguard Worker  } else {
3578*1208bc7eSAndroid Build Coastguard Worker    # math rounding issues
3579*1208bc7eSAndroid Build Coastguard Worker    if ((2 ** $levels) < $items) {
3580*1208bc7eSAndroid Build Coastguard Worker     $levels++;
3581*1208bc7eSAndroid Build Coastguard Worker    }
3582*1208bc7eSAndroid Build Coastguard Worker    my $count = scalar(@main::pfile_args);
3583*1208bc7eSAndroid Build Coastguard Worker    for (my $i = 0; $i < $count; $i++) {
3584*1208bc7eSAndroid Build Coastguard Worker      $main::profile_files[$i] = FetchDynamicProfile($main::prog, $main::pfile_args[$i], 1, 0);
3585*1208bc7eSAndroid Build Coastguard Worker    }
3586*1208bc7eSAndroid Build Coastguard Worker    print STDERR "Fetching $count profiles, Be patient...\n";
3587*1208bc7eSAndroid Build Coastguard Worker    FetchDynamicProfilesRecurse($levels, 0, 0);
3588*1208bc7eSAndroid Build Coastguard Worker    $main::collected_profile = join(" \\\n    ", @main::profile_files);
3589*1208bc7eSAndroid Build Coastguard Worker  }
3590*1208bc7eSAndroid Build Coastguard Worker}
3591*1208bc7eSAndroid Build Coastguard Worker
3592*1208bc7eSAndroid Build Coastguard Worker# Recursively fork a process to get enough processes
3593*1208bc7eSAndroid Build Coastguard Worker# collecting profiles
3594*1208bc7eSAndroid Build Coastguard Workersub FetchDynamicProfilesRecurse {
3595*1208bc7eSAndroid Build Coastguard Worker  my $maxlevel = shift;
3596*1208bc7eSAndroid Build Coastguard Worker  my $level = shift;
3597*1208bc7eSAndroid Build Coastguard Worker  my $position = shift;
3598*1208bc7eSAndroid Build Coastguard Worker
3599*1208bc7eSAndroid Build Coastguard Worker  if (my $pid = fork()) {
3600*1208bc7eSAndroid Build Coastguard Worker    $position = 0 | ($position << 1);
3601*1208bc7eSAndroid Build Coastguard Worker    TryCollectProfile($maxlevel, $level, $position);
3602*1208bc7eSAndroid Build Coastguard Worker    wait;
3603*1208bc7eSAndroid Build Coastguard Worker  } else {
3604*1208bc7eSAndroid Build Coastguard Worker    $position = 1 | ($position << 1);
3605*1208bc7eSAndroid Build Coastguard Worker    TryCollectProfile($maxlevel, $level, $position);
3606*1208bc7eSAndroid Build Coastguard Worker    cleanup();
3607*1208bc7eSAndroid Build Coastguard Worker    exit(0);
3608*1208bc7eSAndroid Build Coastguard Worker  }
3609*1208bc7eSAndroid Build Coastguard Worker}
3610*1208bc7eSAndroid Build Coastguard Worker
3611*1208bc7eSAndroid Build Coastguard Worker# Collect a single profile
3612*1208bc7eSAndroid Build Coastguard Workersub TryCollectProfile {
3613*1208bc7eSAndroid Build Coastguard Worker  my $maxlevel = shift;
3614*1208bc7eSAndroid Build Coastguard Worker  my $level = shift;
3615*1208bc7eSAndroid Build Coastguard Worker  my $position = shift;
3616*1208bc7eSAndroid Build Coastguard Worker
3617*1208bc7eSAndroid Build Coastguard Worker  if ($level >= ($maxlevel - 1)) {
3618*1208bc7eSAndroid Build Coastguard Worker    if ($position < scalar(@main::pfile_args)) {
3619*1208bc7eSAndroid Build Coastguard Worker      FetchDynamicProfile($main::prog, $main::pfile_args[$position], 0, 0);
3620*1208bc7eSAndroid Build Coastguard Worker    }
3621*1208bc7eSAndroid Build Coastguard Worker  } else {
3622*1208bc7eSAndroid Build Coastguard Worker    FetchDynamicProfilesRecurse($maxlevel, $level+1, $position);
3623*1208bc7eSAndroid Build Coastguard Worker  }
3624*1208bc7eSAndroid Build Coastguard Worker}
3625*1208bc7eSAndroid Build Coastguard Worker
3626*1208bc7eSAndroid Build Coastguard Worker##### Parsing code #####
3627*1208bc7eSAndroid Build Coastguard Worker
3628*1208bc7eSAndroid Build Coastguard Worker# Provide a small streaming-read module to handle very large
3629*1208bc7eSAndroid Build Coastguard Worker# cpu-profile files.  Stream in chunks along a sliding window.
3630*1208bc7eSAndroid Build Coastguard Worker# Provides an interface to get one 'slot', correctly handling
3631*1208bc7eSAndroid Build Coastguard Worker# endian-ness differences.  A slot is one 32-bit or 64-bit word
3632*1208bc7eSAndroid Build Coastguard Worker# (depending on the input profile).  We tell endianness and bit-size
3633*1208bc7eSAndroid Build Coastguard Worker# for the profile by looking at the first 8 bytes: in cpu profiles,
3634*1208bc7eSAndroid Build Coastguard Worker# the second slot is always 3 (we'll accept anything that's not 0).
3635*1208bc7eSAndroid Build Coastguard WorkerBEGIN {
3636*1208bc7eSAndroid Build Coastguard Worker  package CpuProfileStream;
3637*1208bc7eSAndroid Build Coastguard Worker
3638*1208bc7eSAndroid Build Coastguard Worker  sub new {
3639*1208bc7eSAndroid Build Coastguard Worker    my ($class, $file, $fname) = @_;
3640*1208bc7eSAndroid Build Coastguard Worker    my $self = { file        => $file,
3641*1208bc7eSAndroid Build Coastguard Worker                 base        => 0,
3642*1208bc7eSAndroid Build Coastguard Worker                 stride      => 512 * 1024,   # must be a multiple of bitsize/8
3643*1208bc7eSAndroid Build Coastguard Worker                 slots       => [],
3644*1208bc7eSAndroid Build Coastguard Worker                 unpack_code => "",           # N for big-endian, V for little
3645*1208bc7eSAndroid Build Coastguard Worker                 perl_is_64bit => 1,          # matters if profile is 64-bit
3646*1208bc7eSAndroid Build Coastguard Worker    };
3647*1208bc7eSAndroid Build Coastguard Worker    bless $self, $class;
3648*1208bc7eSAndroid Build Coastguard Worker    # Let unittests adjust the stride
3649*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_test_stride > 0) {
3650*1208bc7eSAndroid Build Coastguard Worker      $self->{stride} = $main::opt_test_stride;
3651*1208bc7eSAndroid Build Coastguard Worker    }
3652*1208bc7eSAndroid Build Coastguard Worker    # Read the first two slots to figure out bitsize and endianness.
3653*1208bc7eSAndroid Build Coastguard Worker    my $slots = $self->{slots};
3654*1208bc7eSAndroid Build Coastguard Worker    my $str;
3655*1208bc7eSAndroid Build Coastguard Worker    read($self->{file}, $str, 8);
3656*1208bc7eSAndroid Build Coastguard Worker    # Set the global $address_length based on what we see here.
3657*1208bc7eSAndroid Build Coastguard Worker    # 8 is 32-bit (8 hexadecimal chars); 16 is 64-bit (16 hexadecimal chars).
3658*1208bc7eSAndroid Build Coastguard Worker    $address_length = ($str eq (chr(0)x8)) ? 16 : 8;
3659*1208bc7eSAndroid Build Coastguard Worker    if ($address_length == 8) {
3660*1208bc7eSAndroid Build Coastguard Worker      if (substr($str, 6, 2) eq chr(0)x2) {
3661*1208bc7eSAndroid Build Coastguard Worker        $self->{unpack_code} = 'V';  # Little-endian.
3662*1208bc7eSAndroid Build Coastguard Worker      } elsif (substr($str, 4, 2) eq chr(0)x2) {
3663*1208bc7eSAndroid Build Coastguard Worker        $self->{unpack_code} = 'N';  # Big-endian
3664*1208bc7eSAndroid Build Coastguard Worker      } else {
3665*1208bc7eSAndroid Build Coastguard Worker        ::error("$fname: header size >= 2**16\n");
3666*1208bc7eSAndroid Build Coastguard Worker      }
3667*1208bc7eSAndroid Build Coastguard Worker      @$slots = unpack($self->{unpack_code} . "*", $str);
3668*1208bc7eSAndroid Build Coastguard Worker    } else {
3669*1208bc7eSAndroid Build Coastguard Worker      # If we're a 64-bit profile, check if we're a 64-bit-capable
3670*1208bc7eSAndroid Build Coastguard Worker      # perl.  Otherwise, each slot will be represented as a float
3671*1208bc7eSAndroid Build Coastguard Worker      # instead of an int64, losing precision and making all the
3672*1208bc7eSAndroid Build Coastguard Worker      # 64-bit addresses wrong.  We won't complain yet, but will
3673*1208bc7eSAndroid Build Coastguard Worker      # later if we ever see a value that doesn't fit in 32 bits.
3674*1208bc7eSAndroid Build Coastguard Worker      my $has_q = 0;
3675*1208bc7eSAndroid Build Coastguard Worker      eval { $has_q = pack("Q", "1") ? 1 : 1; };
3676*1208bc7eSAndroid Build Coastguard Worker      if (!$has_q) {
3677*1208bc7eSAndroid Build Coastguard Worker        $self->{perl_is_64bit} = 0;
3678*1208bc7eSAndroid Build Coastguard Worker      }
3679*1208bc7eSAndroid Build Coastguard Worker      read($self->{file}, $str, 8);
3680*1208bc7eSAndroid Build Coastguard Worker      if (substr($str, 4, 4) eq chr(0)x4) {
3681*1208bc7eSAndroid Build Coastguard Worker        # We'd love to use 'Q', but it's a) not universal, b) not endian-proof.
3682*1208bc7eSAndroid Build Coastguard Worker        $self->{unpack_code} = 'V';  # Little-endian.
3683*1208bc7eSAndroid Build Coastguard Worker      } elsif (substr($str, 0, 4) eq chr(0)x4) {
3684*1208bc7eSAndroid Build Coastguard Worker        $self->{unpack_code} = 'N';  # Big-endian
3685*1208bc7eSAndroid Build Coastguard Worker      } else {
3686*1208bc7eSAndroid Build Coastguard Worker        ::error("$fname: header size >= 2**32\n");
3687*1208bc7eSAndroid Build Coastguard Worker      }
3688*1208bc7eSAndroid Build Coastguard Worker      my @pair = unpack($self->{unpack_code} . "*", $str);
3689*1208bc7eSAndroid Build Coastguard Worker      # Since we know one of the pair is 0, it's fine to just add them.
3690*1208bc7eSAndroid Build Coastguard Worker      @$slots = (0, $pair[0] + $pair[1]);
3691*1208bc7eSAndroid Build Coastguard Worker    }
3692*1208bc7eSAndroid Build Coastguard Worker    return $self;
3693*1208bc7eSAndroid Build Coastguard Worker  }
3694*1208bc7eSAndroid Build Coastguard Worker
3695*1208bc7eSAndroid Build Coastguard Worker  # Load more data when we access slots->get(X) which is not yet in memory.
3696*1208bc7eSAndroid Build Coastguard Worker  sub overflow {
3697*1208bc7eSAndroid Build Coastguard Worker    my ($self) = @_;
3698*1208bc7eSAndroid Build Coastguard Worker    my $slots = $self->{slots};
3699*1208bc7eSAndroid Build Coastguard Worker    $self->{base} += $#$slots + 1;   # skip over data we're replacing
3700*1208bc7eSAndroid Build Coastguard Worker    my $str;
3701*1208bc7eSAndroid Build Coastguard Worker    read($self->{file}, $str, $self->{stride});
3702*1208bc7eSAndroid Build Coastguard Worker    if ($address_length == 8) {      # the 32-bit case
3703*1208bc7eSAndroid Build Coastguard Worker      # This is the easy case: unpack provides 32-bit unpacking primitives.
3704*1208bc7eSAndroid Build Coastguard Worker      @$slots = unpack($self->{unpack_code} . "*", $str);
3705*1208bc7eSAndroid Build Coastguard Worker    } else {
3706*1208bc7eSAndroid Build Coastguard Worker      # We need to unpack 32 bits at a time and combine.
3707*1208bc7eSAndroid Build Coastguard Worker      my @b32_values = unpack($self->{unpack_code} . "*", $str);
3708*1208bc7eSAndroid Build Coastguard Worker      my @b64_values = ();
3709*1208bc7eSAndroid Build Coastguard Worker      for (my $i = 0; $i < $#b32_values; $i += 2) {
3710*1208bc7eSAndroid Build Coastguard Worker        # TODO(csilvers): if this is a 32-bit perl, the math below
3711*1208bc7eSAndroid Build Coastguard Worker        #    could end up in a too-large int, which perl will promote
3712*1208bc7eSAndroid Build Coastguard Worker        #    to a double, losing necessary precision.  Deal with that.
3713*1208bc7eSAndroid Build Coastguard Worker        #    Right now, we just die.
3714*1208bc7eSAndroid Build Coastguard Worker        my ($lo, $hi) = ($b32_values[$i], $b32_values[$i+1]);
3715*1208bc7eSAndroid Build Coastguard Worker        if ($self->{unpack_code} eq 'N') {    # big-endian
3716*1208bc7eSAndroid Build Coastguard Worker          ($lo, $hi) = ($hi, $lo);
3717*1208bc7eSAndroid Build Coastguard Worker        }
3718*1208bc7eSAndroid Build Coastguard Worker        my $value = $lo + $hi * (2**32);
3719*1208bc7eSAndroid Build Coastguard Worker        if (!$self->{perl_is_64bit} &&   # check value is exactly represented
3720*1208bc7eSAndroid Build Coastguard Worker            (($value % (2**32)) != $lo || int($value / (2**32)) != $hi)) {
3721*1208bc7eSAndroid Build Coastguard Worker          ::error("Need a 64-bit perl to process this 64-bit profile.\n");
3722*1208bc7eSAndroid Build Coastguard Worker        }
3723*1208bc7eSAndroid Build Coastguard Worker        push(@b64_values, $value);
3724*1208bc7eSAndroid Build Coastguard Worker      }
3725*1208bc7eSAndroid Build Coastguard Worker      @$slots = @b64_values;
3726*1208bc7eSAndroid Build Coastguard Worker    }
3727*1208bc7eSAndroid Build Coastguard Worker  }
3728*1208bc7eSAndroid Build Coastguard Worker
3729*1208bc7eSAndroid Build Coastguard Worker  # Access the i-th long in the file (logically), or -1 at EOF.
3730*1208bc7eSAndroid Build Coastguard Worker  sub get {
3731*1208bc7eSAndroid Build Coastguard Worker    my ($self, $idx) = @_;
3732*1208bc7eSAndroid Build Coastguard Worker    my $slots = $self->{slots};
3733*1208bc7eSAndroid Build Coastguard Worker    while ($#$slots >= 0) {
3734*1208bc7eSAndroid Build Coastguard Worker      if ($idx < $self->{base}) {
3735*1208bc7eSAndroid Build Coastguard Worker        # The only time we expect a reference to $slots[$i - something]
3736*1208bc7eSAndroid Build Coastguard Worker        # after referencing $slots[$i] is reading the very first header.
3737*1208bc7eSAndroid Build Coastguard Worker        # Since $stride > |header|, that shouldn't cause any lookback
3738*1208bc7eSAndroid Build Coastguard Worker        # errors.  And everything after the header is sequential.
3739*1208bc7eSAndroid Build Coastguard Worker        print STDERR "Unexpected look-back reading CPU profile";
3740*1208bc7eSAndroid Build Coastguard Worker        return -1;   # shrug, don't know what better to return
3741*1208bc7eSAndroid Build Coastguard Worker      } elsif ($idx > $self->{base} + $#$slots) {
3742*1208bc7eSAndroid Build Coastguard Worker        $self->overflow();
3743*1208bc7eSAndroid Build Coastguard Worker      } else {
3744*1208bc7eSAndroid Build Coastguard Worker        return $slots->[$idx - $self->{base}];
3745*1208bc7eSAndroid Build Coastguard Worker      }
3746*1208bc7eSAndroid Build Coastguard Worker    }
3747*1208bc7eSAndroid Build Coastguard Worker    # If we get here, $slots is [], which means we've reached EOF
3748*1208bc7eSAndroid Build Coastguard Worker    return -1;  # unique since slots is supposed to hold unsigned numbers
3749*1208bc7eSAndroid Build Coastguard Worker  }
3750*1208bc7eSAndroid Build Coastguard Worker}
3751*1208bc7eSAndroid Build Coastguard Worker
3752*1208bc7eSAndroid Build Coastguard Worker# Reads the top, 'header' section of a profile, and returns the last
3753*1208bc7eSAndroid Build Coastguard Worker# line of the header, commonly called a 'header line'.  The header
3754*1208bc7eSAndroid Build Coastguard Worker# section of a profile consists of zero or more 'command' lines that
3755*1208bc7eSAndroid Build Coastguard Worker# are instructions to jeprof, which jeprof executes when reading the
3756*1208bc7eSAndroid Build Coastguard Worker# header.  All 'command' lines start with a %.  After the command
3757*1208bc7eSAndroid Build Coastguard Worker# lines is the 'header line', which is a profile-specific line that
3758*1208bc7eSAndroid Build Coastguard Worker# indicates what type of profile it is, and perhaps other global
3759*1208bc7eSAndroid Build Coastguard Worker# information about the profile.  For instance, here's a header line
3760*1208bc7eSAndroid Build Coastguard Worker# for a heap profile:
3761*1208bc7eSAndroid Build Coastguard Worker#   heap profile:     53:    38236 [  5525:  1284029] @ heapprofile
3762*1208bc7eSAndroid Build Coastguard Worker# For historical reasons, the CPU profile does not contain a text-
3763*1208bc7eSAndroid Build Coastguard Worker# readable header line.  If the profile looks like a CPU profile,
3764*1208bc7eSAndroid Build Coastguard Worker# this function returns "".  If no header line could be found, this
3765*1208bc7eSAndroid Build Coastguard Worker# function returns undef.
3766*1208bc7eSAndroid Build Coastguard Worker#
3767*1208bc7eSAndroid Build Coastguard Worker# The following commands are recognized:
3768*1208bc7eSAndroid Build Coastguard Worker#   %warn -- emit the rest of this line to stderr, prefixed by 'WARNING:'
3769*1208bc7eSAndroid Build Coastguard Worker#
3770*1208bc7eSAndroid Build Coastguard Worker# The input file should be in binmode.
3771*1208bc7eSAndroid Build Coastguard Workersub ReadProfileHeader {
3772*1208bc7eSAndroid Build Coastguard Worker  local *PROFILE = shift;
3773*1208bc7eSAndroid Build Coastguard Worker  my $firstchar = "";
3774*1208bc7eSAndroid Build Coastguard Worker  my $line = "";
3775*1208bc7eSAndroid Build Coastguard Worker  read(PROFILE, $firstchar, 1);
3776*1208bc7eSAndroid Build Coastguard Worker  seek(PROFILE, -1, 1);                    # unread the firstchar
3777*1208bc7eSAndroid Build Coastguard Worker  if ($firstchar !~ /[[:print:]]/) {       # is not a text character
3778*1208bc7eSAndroid Build Coastguard Worker    return "";
3779*1208bc7eSAndroid Build Coastguard Worker  }
3780*1208bc7eSAndroid Build Coastguard Worker  while (defined($line = <PROFILE>)) {
3781*1208bc7eSAndroid Build Coastguard Worker    $line =~ s/\r//g;   # turn windows-looking lines into unix-looking lines
3782*1208bc7eSAndroid Build Coastguard Worker    if ($line =~ /^%warn\s+(.*)/) {        # 'warn' command
3783*1208bc7eSAndroid Build Coastguard Worker      # Note this matches both '%warn blah\n' and '%warn\n'.
3784*1208bc7eSAndroid Build Coastguard Worker      print STDERR "WARNING: $1\n";        # print the rest of the line
3785*1208bc7eSAndroid Build Coastguard Worker    } elsif ($line =~ /^%/) {
3786*1208bc7eSAndroid Build Coastguard Worker      print STDERR "Ignoring unknown command from profile header: $line";
3787*1208bc7eSAndroid Build Coastguard Worker    } else {
3788*1208bc7eSAndroid Build Coastguard Worker      # End of commands, must be the header line.
3789*1208bc7eSAndroid Build Coastguard Worker      return $line;
3790*1208bc7eSAndroid Build Coastguard Worker    }
3791*1208bc7eSAndroid Build Coastguard Worker  }
3792*1208bc7eSAndroid Build Coastguard Worker  return undef;     # got to EOF without seeing a header line
3793*1208bc7eSAndroid Build Coastguard Worker}
3794*1208bc7eSAndroid Build Coastguard Worker
3795*1208bc7eSAndroid Build Coastguard Workersub IsSymbolizedProfileFile {
3796*1208bc7eSAndroid Build Coastguard Worker  my $file_name = shift;
3797*1208bc7eSAndroid Build Coastguard Worker  if (!(-e $file_name) || !(-r $file_name)) {
3798*1208bc7eSAndroid Build Coastguard Worker    return 0;
3799*1208bc7eSAndroid Build Coastguard Worker  }
3800*1208bc7eSAndroid Build Coastguard Worker  # Check if the file contains a symbol-section marker.
3801*1208bc7eSAndroid Build Coastguard Worker  open(TFILE, "<$file_name");
3802*1208bc7eSAndroid Build Coastguard Worker  binmode TFILE;
3803*1208bc7eSAndroid Build Coastguard Worker  my $firstline = ReadProfileHeader(*TFILE);
3804*1208bc7eSAndroid Build Coastguard Worker  close(TFILE);
3805*1208bc7eSAndroid Build Coastguard Worker  if (!$firstline) {
3806*1208bc7eSAndroid Build Coastguard Worker    return 0;
3807*1208bc7eSAndroid Build Coastguard Worker  }
3808*1208bc7eSAndroid Build Coastguard Worker  $SYMBOL_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
3809*1208bc7eSAndroid Build Coastguard Worker  my $symbol_marker = $&;
3810*1208bc7eSAndroid Build Coastguard Worker  return $firstline =~ /^--- *$symbol_marker/;
3811*1208bc7eSAndroid Build Coastguard Worker}
3812*1208bc7eSAndroid Build Coastguard Worker
3813*1208bc7eSAndroid Build Coastguard Worker# Parse profile generated by common/profiler.cc and return a reference
3814*1208bc7eSAndroid Build Coastguard Worker# to a map:
3815*1208bc7eSAndroid Build Coastguard Worker#      $result->{version}     Version number of profile file
3816*1208bc7eSAndroid Build Coastguard Worker#      $result->{period}      Sampling period (in microseconds)
3817*1208bc7eSAndroid Build Coastguard Worker#      $result->{profile}     Profile object
3818*1208bc7eSAndroid Build Coastguard Worker#      $result->{threads}     Map of thread IDs to profile objects
3819*1208bc7eSAndroid Build Coastguard Worker#      $result->{map}         Memory map info from profile
3820*1208bc7eSAndroid Build Coastguard Worker#      $result->{pcs}         Hash of all PC values seen, key is hex address
3821*1208bc7eSAndroid Build Coastguard Workersub ReadProfile {
3822*1208bc7eSAndroid Build Coastguard Worker  my $prog = shift;
3823*1208bc7eSAndroid Build Coastguard Worker  my $fname = shift;
3824*1208bc7eSAndroid Build Coastguard Worker  my $result;            # return value
3825*1208bc7eSAndroid Build Coastguard Worker
3826*1208bc7eSAndroid Build Coastguard Worker  $CONTENTION_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
3827*1208bc7eSAndroid Build Coastguard Worker  my $contention_marker = $&;
3828*1208bc7eSAndroid Build Coastguard Worker  $GROWTH_PAGE  =~ m,[^/]+$,;    # matches everything after the last slash
3829*1208bc7eSAndroid Build Coastguard Worker  my $growth_marker = $&;
3830*1208bc7eSAndroid Build Coastguard Worker  $SYMBOL_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
3831*1208bc7eSAndroid Build Coastguard Worker  my $symbol_marker = $&;
3832*1208bc7eSAndroid Build Coastguard Worker  $PROFILE_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
3833*1208bc7eSAndroid Build Coastguard Worker  my $profile_marker = $&;
3834*1208bc7eSAndroid Build Coastguard Worker  $HEAP_PAGE =~ m,[^/]+$,;    # matches everything after the last slash
3835*1208bc7eSAndroid Build Coastguard Worker  my $heap_marker = $&;
3836*1208bc7eSAndroid Build Coastguard Worker
3837*1208bc7eSAndroid Build Coastguard Worker  # Look at first line to see if it is a heap or a CPU profile.
3838*1208bc7eSAndroid Build Coastguard Worker  # CPU profile may start with no header at all, and just binary data
3839*1208bc7eSAndroid Build Coastguard Worker  # (starting with \0\0\0\0) -- in that case, don't try to read the
3840*1208bc7eSAndroid Build Coastguard Worker  # whole firstline, since it may be gigabytes(!) of data.
3841*1208bc7eSAndroid Build Coastguard Worker  open(PROFILE, "<$fname") || error("$fname: $!\n");
3842*1208bc7eSAndroid Build Coastguard Worker  binmode PROFILE;      # New perls do UTF-8 processing
3843*1208bc7eSAndroid Build Coastguard Worker  my $header = ReadProfileHeader(*PROFILE);
3844*1208bc7eSAndroid Build Coastguard Worker  if (!defined($header)) {   # means "at EOF"
3845*1208bc7eSAndroid Build Coastguard Worker    error("Profile is empty.\n");
3846*1208bc7eSAndroid Build Coastguard Worker  }
3847*1208bc7eSAndroid Build Coastguard Worker
3848*1208bc7eSAndroid Build Coastguard Worker  my $symbols;
3849*1208bc7eSAndroid Build Coastguard Worker  if ($header =~ m/^--- *$symbol_marker/o) {
3850*1208bc7eSAndroid Build Coastguard Worker    # Verify that the user asked for a symbolized profile
3851*1208bc7eSAndroid Build Coastguard Worker    if (!$main::use_symbolized_profile) {
3852*1208bc7eSAndroid Build Coastguard Worker      # we have both a binary and symbolized profiles, abort
3853*1208bc7eSAndroid Build Coastguard Worker      error("FATAL ERROR: Symbolized profile\n   $fname\ncannot be used with " .
3854*1208bc7eSAndroid Build Coastguard Worker            "a binary arg. Try again without passing\n   $prog\n");
3855*1208bc7eSAndroid Build Coastguard Worker    }
3856*1208bc7eSAndroid Build Coastguard Worker    # Read the symbol section of the symbolized profile file.
3857*1208bc7eSAndroid Build Coastguard Worker    $symbols = ReadSymbols(*PROFILE{IO});
3858*1208bc7eSAndroid Build Coastguard Worker    # Read the next line to get the header for the remaining profile.
3859*1208bc7eSAndroid Build Coastguard Worker    $header = ReadProfileHeader(*PROFILE) || "";
3860*1208bc7eSAndroid Build Coastguard Worker  }
3861*1208bc7eSAndroid Build Coastguard Worker
3862*1208bc7eSAndroid Build Coastguard Worker  if ($header =~ m/^--- *($heap_marker|$growth_marker)/o) {
3863*1208bc7eSAndroid Build Coastguard Worker    # Skip "--- ..." line for profile types that have their own headers.
3864*1208bc7eSAndroid Build Coastguard Worker    $header = ReadProfileHeader(*PROFILE) || "";
3865*1208bc7eSAndroid Build Coastguard Worker  }
3866*1208bc7eSAndroid Build Coastguard Worker
3867*1208bc7eSAndroid Build Coastguard Worker  $main::profile_type = '';
3868*1208bc7eSAndroid Build Coastguard Worker
3869*1208bc7eSAndroid Build Coastguard Worker  if ($header =~ m/^heap profile:.*$growth_marker/o) {
3870*1208bc7eSAndroid Build Coastguard Worker    $main::profile_type = 'growth';
3871*1208bc7eSAndroid Build Coastguard Worker    $result =  ReadHeapProfile($prog, *PROFILE, $header);
3872*1208bc7eSAndroid Build Coastguard Worker  } elsif ($header =~ m/^heap profile:/) {
3873*1208bc7eSAndroid Build Coastguard Worker    $main::profile_type = 'heap';
3874*1208bc7eSAndroid Build Coastguard Worker    $result =  ReadHeapProfile($prog, *PROFILE, $header);
3875*1208bc7eSAndroid Build Coastguard Worker  } elsif ($header =~ m/^heap/) {
3876*1208bc7eSAndroid Build Coastguard Worker    $main::profile_type = 'heap';
3877*1208bc7eSAndroid Build Coastguard Worker    $result = ReadThreadedHeapProfile($prog, $fname, $header);
3878*1208bc7eSAndroid Build Coastguard Worker  } elsif ($header =~ m/^--- *$contention_marker/o) {
3879*1208bc7eSAndroid Build Coastguard Worker    $main::profile_type = 'contention';
3880*1208bc7eSAndroid Build Coastguard Worker    $result = ReadSynchProfile($prog, *PROFILE);
3881*1208bc7eSAndroid Build Coastguard Worker  } elsif ($header =~ m/^--- *Stacks:/) {
3882*1208bc7eSAndroid Build Coastguard Worker    print STDERR
3883*1208bc7eSAndroid Build Coastguard Worker      "Old format contention profile: mistakenly reports " .
3884*1208bc7eSAndroid Build Coastguard Worker      "condition variable signals as lock contentions.\n";
3885*1208bc7eSAndroid Build Coastguard Worker    $main::profile_type = 'contention';
3886*1208bc7eSAndroid Build Coastguard Worker    $result = ReadSynchProfile($prog, *PROFILE);
3887*1208bc7eSAndroid Build Coastguard Worker  } elsif ($header =~ m/^--- *$profile_marker/) {
3888*1208bc7eSAndroid Build Coastguard Worker    # the binary cpu profile data starts immediately after this line
3889*1208bc7eSAndroid Build Coastguard Worker    $main::profile_type = 'cpu';
3890*1208bc7eSAndroid Build Coastguard Worker    $result = ReadCPUProfile($prog, $fname, *PROFILE);
3891*1208bc7eSAndroid Build Coastguard Worker  } else {
3892*1208bc7eSAndroid Build Coastguard Worker    if (defined($symbols)) {
3893*1208bc7eSAndroid Build Coastguard Worker      # a symbolized profile contains a format we don't recognize, bail out
3894*1208bc7eSAndroid Build Coastguard Worker      error("$fname: Cannot recognize profile section after symbols.\n");
3895*1208bc7eSAndroid Build Coastguard Worker    }
3896*1208bc7eSAndroid Build Coastguard Worker    # no ascii header present -- must be a CPU profile
3897*1208bc7eSAndroid Build Coastguard Worker    $main::profile_type = 'cpu';
3898*1208bc7eSAndroid Build Coastguard Worker    $result = ReadCPUProfile($prog, $fname, *PROFILE);
3899*1208bc7eSAndroid Build Coastguard Worker  }
3900*1208bc7eSAndroid Build Coastguard Worker
3901*1208bc7eSAndroid Build Coastguard Worker  close(PROFILE);
3902*1208bc7eSAndroid Build Coastguard Worker
3903*1208bc7eSAndroid Build Coastguard Worker  # if we got symbols along with the profile, return those as well
3904*1208bc7eSAndroid Build Coastguard Worker  if (defined($symbols)) {
3905*1208bc7eSAndroid Build Coastguard Worker    $result->{symbols} = $symbols;
3906*1208bc7eSAndroid Build Coastguard Worker  }
3907*1208bc7eSAndroid Build Coastguard Worker
3908*1208bc7eSAndroid Build Coastguard Worker  return $result;
3909*1208bc7eSAndroid Build Coastguard Worker}
3910*1208bc7eSAndroid Build Coastguard Worker
3911*1208bc7eSAndroid Build Coastguard Worker# Subtract one from caller pc so we map back to call instr.
3912*1208bc7eSAndroid Build Coastguard Worker# However, don't do this if we're reading a symbolized profile
3913*1208bc7eSAndroid Build Coastguard Worker# file, in which case the subtract-one was done when the file
3914*1208bc7eSAndroid Build Coastguard Worker# was written.
3915*1208bc7eSAndroid Build Coastguard Worker#
3916*1208bc7eSAndroid Build Coastguard Worker# We apply the same logic to all readers, though ReadCPUProfile uses an
3917*1208bc7eSAndroid Build Coastguard Worker# independent implementation.
3918*1208bc7eSAndroid Build Coastguard Workersub FixCallerAddresses {
3919*1208bc7eSAndroid Build Coastguard Worker  my $stack = shift;
3920*1208bc7eSAndroid Build Coastguard Worker  # --raw/http: Always subtract one from pc's, because PrintSymbolizedProfile()
3921*1208bc7eSAndroid Build Coastguard Worker  # dumps unadjusted profiles.
3922*1208bc7eSAndroid Build Coastguard Worker  {
3923*1208bc7eSAndroid Build Coastguard Worker    $stack =~ /(\s)/;
3924*1208bc7eSAndroid Build Coastguard Worker    my $delimiter = $1;
3925*1208bc7eSAndroid Build Coastguard Worker    my @addrs = split(' ', $stack);
3926*1208bc7eSAndroid Build Coastguard Worker    my @fixedaddrs;
3927*1208bc7eSAndroid Build Coastguard Worker    $#fixedaddrs = $#addrs;
3928*1208bc7eSAndroid Build Coastguard Worker    if ($#addrs >= 0) {
3929*1208bc7eSAndroid Build Coastguard Worker      $fixedaddrs[0] = $addrs[0];
3930*1208bc7eSAndroid Build Coastguard Worker    }
3931*1208bc7eSAndroid Build Coastguard Worker    for (my $i = 1; $i <= $#addrs; $i++) {
3932*1208bc7eSAndroid Build Coastguard Worker      $fixedaddrs[$i] = AddressSub($addrs[$i], "0x1");
3933*1208bc7eSAndroid Build Coastguard Worker    }
3934*1208bc7eSAndroid Build Coastguard Worker    return join $delimiter, @fixedaddrs;
3935*1208bc7eSAndroid Build Coastguard Worker  }
3936*1208bc7eSAndroid Build Coastguard Worker}
3937*1208bc7eSAndroid Build Coastguard Worker
3938*1208bc7eSAndroid Build Coastguard Worker# CPU profile reader
3939*1208bc7eSAndroid Build Coastguard Workersub ReadCPUProfile {
3940*1208bc7eSAndroid Build Coastguard Worker  my $prog = shift;
3941*1208bc7eSAndroid Build Coastguard Worker  my $fname = shift;       # just used for logging
3942*1208bc7eSAndroid Build Coastguard Worker  local *PROFILE = shift;
3943*1208bc7eSAndroid Build Coastguard Worker  my $version;
3944*1208bc7eSAndroid Build Coastguard Worker  my $period;
3945*1208bc7eSAndroid Build Coastguard Worker  my $i;
3946*1208bc7eSAndroid Build Coastguard Worker  my $profile = {};
3947*1208bc7eSAndroid Build Coastguard Worker  my $pcs = {};
3948*1208bc7eSAndroid Build Coastguard Worker
3949*1208bc7eSAndroid Build Coastguard Worker  # Parse string into array of slots.
3950*1208bc7eSAndroid Build Coastguard Worker  my $slots = CpuProfileStream->new(*PROFILE, $fname);
3951*1208bc7eSAndroid Build Coastguard Worker
3952*1208bc7eSAndroid Build Coastguard Worker  # Read header.  The current header version is a 5-element structure
3953*1208bc7eSAndroid Build Coastguard Worker  # containing:
3954*1208bc7eSAndroid Build Coastguard Worker  #   0: header count (always 0)
3955*1208bc7eSAndroid Build Coastguard Worker  #   1: header "words" (after this one: 3)
3956*1208bc7eSAndroid Build Coastguard Worker  #   2: format version (0)
3957*1208bc7eSAndroid Build Coastguard Worker  #   3: sampling period (usec)
3958*1208bc7eSAndroid Build Coastguard Worker  #   4: unused padding (always 0)
3959*1208bc7eSAndroid Build Coastguard Worker  if ($slots->get(0) != 0 ) {
3960*1208bc7eSAndroid Build Coastguard Worker    error("$fname: not a profile file, or old format profile file\n");
3961*1208bc7eSAndroid Build Coastguard Worker  }
3962*1208bc7eSAndroid Build Coastguard Worker  $i = 2 + $slots->get(1);
3963*1208bc7eSAndroid Build Coastguard Worker  $version = $slots->get(2);
3964*1208bc7eSAndroid Build Coastguard Worker  $period = $slots->get(3);
3965*1208bc7eSAndroid Build Coastguard Worker  # Do some sanity checking on these header values.
3966*1208bc7eSAndroid Build Coastguard Worker  if ($version > (2**32) || $period > (2**32) || $i > (2**32) || $i < 5) {
3967*1208bc7eSAndroid Build Coastguard Worker    error("$fname: not a profile file, or corrupted profile file\n");
3968*1208bc7eSAndroid Build Coastguard Worker  }
3969*1208bc7eSAndroid Build Coastguard Worker
3970*1208bc7eSAndroid Build Coastguard Worker  # Parse profile
3971*1208bc7eSAndroid Build Coastguard Worker  while ($slots->get($i) != -1) {
3972*1208bc7eSAndroid Build Coastguard Worker    my $n = $slots->get($i++);
3973*1208bc7eSAndroid Build Coastguard Worker    my $d = $slots->get($i++);
3974*1208bc7eSAndroid Build Coastguard Worker    if ($d > (2**16)) {  # TODO(csilvers): what's a reasonable max-stack-depth?
3975*1208bc7eSAndroid Build Coastguard Worker      my $addr = sprintf("0%o", $i * ($address_length == 8 ? 4 : 8));
3976*1208bc7eSAndroid Build Coastguard Worker      print STDERR "At index $i (address $addr):\n";
3977*1208bc7eSAndroid Build Coastguard Worker      error("$fname: stack trace depth >= 2**32\n");
3978*1208bc7eSAndroid Build Coastguard Worker    }
3979*1208bc7eSAndroid Build Coastguard Worker    if ($slots->get($i) == 0) {
3980*1208bc7eSAndroid Build Coastguard Worker      # End of profile data marker
3981*1208bc7eSAndroid Build Coastguard Worker      $i += $d;
3982*1208bc7eSAndroid Build Coastguard Worker      last;
3983*1208bc7eSAndroid Build Coastguard Worker    }
3984*1208bc7eSAndroid Build Coastguard Worker
3985*1208bc7eSAndroid Build Coastguard Worker    # Make key out of the stack entries
3986*1208bc7eSAndroid Build Coastguard Worker    my @k = ();
3987*1208bc7eSAndroid Build Coastguard Worker    for (my $j = 0; $j < $d; $j++) {
3988*1208bc7eSAndroid Build Coastguard Worker      my $pc = $slots->get($i+$j);
3989*1208bc7eSAndroid Build Coastguard Worker      # Subtract one from caller pc so we map back to call instr.
3990*1208bc7eSAndroid Build Coastguard Worker      $pc--;
3991*1208bc7eSAndroid Build Coastguard Worker      $pc = sprintf("%0*x", $address_length, $pc);
3992*1208bc7eSAndroid Build Coastguard Worker      $pcs->{$pc} = 1;
3993*1208bc7eSAndroid Build Coastguard Worker      push @k, $pc;
3994*1208bc7eSAndroid Build Coastguard Worker    }
3995*1208bc7eSAndroid Build Coastguard Worker
3996*1208bc7eSAndroid Build Coastguard Worker    AddEntry($profile, (join "\n", @k), $n);
3997*1208bc7eSAndroid Build Coastguard Worker    $i += $d;
3998*1208bc7eSAndroid Build Coastguard Worker  }
3999*1208bc7eSAndroid Build Coastguard Worker
4000*1208bc7eSAndroid Build Coastguard Worker  # Parse map
4001*1208bc7eSAndroid Build Coastguard Worker  my $map = '';
4002*1208bc7eSAndroid Build Coastguard Worker  seek(PROFILE, $i * 4, 0);
4003*1208bc7eSAndroid Build Coastguard Worker  read(PROFILE, $map, (stat PROFILE)[7]);
4004*1208bc7eSAndroid Build Coastguard Worker
4005*1208bc7eSAndroid Build Coastguard Worker  my $r = {};
4006*1208bc7eSAndroid Build Coastguard Worker  $r->{version} = $version;
4007*1208bc7eSAndroid Build Coastguard Worker  $r->{period} = $period;
4008*1208bc7eSAndroid Build Coastguard Worker  $r->{profile} = $profile;
4009*1208bc7eSAndroid Build Coastguard Worker  $r->{libs} = ParseLibraries($prog, $map, $pcs);
4010*1208bc7eSAndroid Build Coastguard Worker  $r->{pcs} = $pcs;
4011*1208bc7eSAndroid Build Coastguard Worker
4012*1208bc7eSAndroid Build Coastguard Worker  return $r;
4013*1208bc7eSAndroid Build Coastguard Worker}
4014*1208bc7eSAndroid Build Coastguard Worker
4015*1208bc7eSAndroid Build Coastguard Workersub HeapProfileIndex {
4016*1208bc7eSAndroid Build Coastguard Worker  my $index = 1;
4017*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_inuse_space) {
4018*1208bc7eSAndroid Build Coastguard Worker    $index = 1;
4019*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_inuse_objects) {
4020*1208bc7eSAndroid Build Coastguard Worker    $index = 0;
4021*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_alloc_space) {
4022*1208bc7eSAndroid Build Coastguard Worker    $index = 3;
4023*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_alloc_objects) {
4024*1208bc7eSAndroid Build Coastguard Worker    $index = 2;
4025*1208bc7eSAndroid Build Coastguard Worker  }
4026*1208bc7eSAndroid Build Coastguard Worker  return $index;
4027*1208bc7eSAndroid Build Coastguard Worker}
4028*1208bc7eSAndroid Build Coastguard Worker
4029*1208bc7eSAndroid Build Coastguard Workersub ReadMappedLibraries {
4030*1208bc7eSAndroid Build Coastguard Worker  my $fh = shift;
4031*1208bc7eSAndroid Build Coastguard Worker  my $map = "";
4032*1208bc7eSAndroid Build Coastguard Worker  # Read the /proc/self/maps data
4033*1208bc7eSAndroid Build Coastguard Worker  while (<$fh>) {
4034*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;         # turn windows-looking lines into unix-looking lines
4035*1208bc7eSAndroid Build Coastguard Worker    $map .= $_;
4036*1208bc7eSAndroid Build Coastguard Worker  }
4037*1208bc7eSAndroid Build Coastguard Worker  return $map;
4038*1208bc7eSAndroid Build Coastguard Worker}
4039*1208bc7eSAndroid Build Coastguard Worker
4040*1208bc7eSAndroid Build Coastguard Workersub ReadMemoryMap {
4041*1208bc7eSAndroid Build Coastguard Worker  my $fh = shift;
4042*1208bc7eSAndroid Build Coastguard Worker  my $map = "";
4043*1208bc7eSAndroid Build Coastguard Worker  # Read /proc/self/maps data as formatted by DumpAddressMap()
4044*1208bc7eSAndroid Build Coastguard Worker  my $buildvar = "";
4045*1208bc7eSAndroid Build Coastguard Worker  while (<PROFILE>) {
4046*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;         # turn windows-looking lines into unix-looking lines
4047*1208bc7eSAndroid Build Coastguard Worker    # Parse "build=<dir>" specification if supplied
4048*1208bc7eSAndroid Build Coastguard Worker    if (m/^\s*build=(.*)\n/) {
4049*1208bc7eSAndroid Build Coastguard Worker      $buildvar = $1;
4050*1208bc7eSAndroid Build Coastguard Worker    }
4051*1208bc7eSAndroid Build Coastguard Worker
4052*1208bc7eSAndroid Build Coastguard Worker    # Expand "$build" variable if available
4053*1208bc7eSAndroid Build Coastguard Worker    $_ =~ s/\$build\b/$buildvar/g;
4054*1208bc7eSAndroid Build Coastguard Worker
4055*1208bc7eSAndroid Build Coastguard Worker    $map .= $_;
4056*1208bc7eSAndroid Build Coastguard Worker  }
4057*1208bc7eSAndroid Build Coastguard Worker  return $map;
4058*1208bc7eSAndroid Build Coastguard Worker}
4059*1208bc7eSAndroid Build Coastguard Worker
4060*1208bc7eSAndroid Build Coastguard Workersub AdjustSamples {
4061*1208bc7eSAndroid Build Coastguard Worker  my ($sample_adjustment, $sampling_algorithm, $n1, $s1, $n2, $s2) = @_;
4062*1208bc7eSAndroid Build Coastguard Worker  if ($sample_adjustment) {
4063*1208bc7eSAndroid Build Coastguard Worker    if ($sampling_algorithm == 2) {
4064*1208bc7eSAndroid Build Coastguard Worker      # Remote-heap version 2
4065*1208bc7eSAndroid Build Coastguard Worker      # The sampling frequency is the rate of a Poisson process.
4066*1208bc7eSAndroid Build Coastguard Worker      # This means that the probability of sampling an allocation of
4067*1208bc7eSAndroid Build Coastguard Worker      # size X with sampling rate Y is 1 - exp(-X/Y)
4068*1208bc7eSAndroid Build Coastguard Worker      if ($n1 != 0) {
4069*1208bc7eSAndroid Build Coastguard Worker        my $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
4070*1208bc7eSAndroid Build Coastguard Worker        my $scale_factor = 1/(1 - exp(-$ratio));
4071*1208bc7eSAndroid Build Coastguard Worker        $n1 *= $scale_factor;
4072*1208bc7eSAndroid Build Coastguard Worker        $s1 *= $scale_factor;
4073*1208bc7eSAndroid Build Coastguard Worker      }
4074*1208bc7eSAndroid Build Coastguard Worker      if ($n2 != 0) {
4075*1208bc7eSAndroid Build Coastguard Worker        my $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
4076*1208bc7eSAndroid Build Coastguard Worker        my $scale_factor = 1/(1 - exp(-$ratio));
4077*1208bc7eSAndroid Build Coastguard Worker        $n2 *= $scale_factor;
4078*1208bc7eSAndroid Build Coastguard Worker        $s2 *= $scale_factor;
4079*1208bc7eSAndroid Build Coastguard Worker      }
4080*1208bc7eSAndroid Build Coastguard Worker    } else {
4081*1208bc7eSAndroid Build Coastguard Worker      # Remote-heap version 1
4082*1208bc7eSAndroid Build Coastguard Worker      my $ratio;
4083*1208bc7eSAndroid Build Coastguard Worker      $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
4084*1208bc7eSAndroid Build Coastguard Worker      if ($ratio < 1) {
4085*1208bc7eSAndroid Build Coastguard Worker        $n1 /= $ratio;
4086*1208bc7eSAndroid Build Coastguard Worker        $s1 /= $ratio;
4087*1208bc7eSAndroid Build Coastguard Worker      }
4088*1208bc7eSAndroid Build Coastguard Worker      $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
4089*1208bc7eSAndroid Build Coastguard Worker      if ($ratio < 1) {
4090*1208bc7eSAndroid Build Coastguard Worker        $n2 /= $ratio;
4091*1208bc7eSAndroid Build Coastguard Worker        $s2 /= $ratio;
4092*1208bc7eSAndroid Build Coastguard Worker      }
4093*1208bc7eSAndroid Build Coastguard Worker    }
4094*1208bc7eSAndroid Build Coastguard Worker  }
4095*1208bc7eSAndroid Build Coastguard Worker  return ($n1, $s1, $n2, $s2);
4096*1208bc7eSAndroid Build Coastguard Worker}
4097*1208bc7eSAndroid Build Coastguard Worker
4098*1208bc7eSAndroid Build Coastguard Workersub ReadHeapProfile {
4099*1208bc7eSAndroid Build Coastguard Worker  my $prog = shift;
4100*1208bc7eSAndroid Build Coastguard Worker  local *PROFILE = shift;
4101*1208bc7eSAndroid Build Coastguard Worker  my $header = shift;
4102*1208bc7eSAndroid Build Coastguard Worker
4103*1208bc7eSAndroid Build Coastguard Worker  my $index = HeapProfileIndex();
4104*1208bc7eSAndroid Build Coastguard Worker
4105*1208bc7eSAndroid Build Coastguard Worker  # Find the type of this profile.  The header line looks like:
4106*1208bc7eSAndroid Build Coastguard Worker  #    heap profile:   1246:  8800744 [  1246:  8800744] @ <heap-url>/266053
4107*1208bc7eSAndroid Build Coastguard Worker  # There are two pairs <count: size>, the first inuse objects/space, and the
4108*1208bc7eSAndroid Build Coastguard Worker  # second allocated objects/space.  This is followed optionally by a profile
4109*1208bc7eSAndroid Build Coastguard Worker  # type, and if that is present, optionally by a sampling frequency.
4110*1208bc7eSAndroid Build Coastguard Worker  # For remote heap profiles (v1):
4111*1208bc7eSAndroid Build Coastguard Worker  # The interpretation of the sampling frequency is that the profiler, for
4112*1208bc7eSAndroid Build Coastguard Worker  # each sample, calculates a uniformly distributed random integer less than
4113*1208bc7eSAndroid Build Coastguard Worker  # the given value, and records the next sample after that many bytes have
4114*1208bc7eSAndroid Build Coastguard Worker  # been allocated.  Therefore, the expected sample interval is half of the
4115*1208bc7eSAndroid Build Coastguard Worker  # given frequency.  By default, if not specified, the expected sample
4116*1208bc7eSAndroid Build Coastguard Worker  # interval is 128KB.  Only remote-heap-page profiles are adjusted for
4117*1208bc7eSAndroid Build Coastguard Worker  # sample size.
4118*1208bc7eSAndroid Build Coastguard Worker  # For remote heap profiles (v2):
4119*1208bc7eSAndroid Build Coastguard Worker  # The sampling frequency is the rate of a Poisson process. This means that
4120*1208bc7eSAndroid Build Coastguard Worker  # the probability of sampling an allocation of size X with sampling rate Y
4121*1208bc7eSAndroid Build Coastguard Worker  # is 1 - exp(-X/Y)
4122*1208bc7eSAndroid Build Coastguard Worker  # For version 2, a typical header line might look like this:
4123*1208bc7eSAndroid Build Coastguard Worker  # heap profile:   1922: 127792360 [  1922: 127792360] @ <heap-url>_v2/524288
4124*1208bc7eSAndroid Build Coastguard Worker  # the trailing number (524288) is the sampling rate. (Version 1 showed
4125*1208bc7eSAndroid Build Coastguard Worker  # double the 'rate' here)
4126*1208bc7eSAndroid Build Coastguard Worker  my $sampling_algorithm = 0;
4127*1208bc7eSAndroid Build Coastguard Worker  my $sample_adjustment = 0;
4128*1208bc7eSAndroid Build Coastguard Worker  chomp($header);
4129*1208bc7eSAndroid Build Coastguard Worker  my $type = "unknown";
4130*1208bc7eSAndroid Build Coastguard Worker  if ($header =~ m"^heap profile:\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\](\s*@\s*([^/]*)(/(\d+))?)?") {
4131*1208bc7eSAndroid Build Coastguard Worker    if (defined($6) && ($6 ne '')) {
4132*1208bc7eSAndroid Build Coastguard Worker      $type = $6;
4133*1208bc7eSAndroid Build Coastguard Worker      my $sample_period = $8;
4134*1208bc7eSAndroid Build Coastguard Worker      # $type is "heapprofile" for profiles generated by the
4135*1208bc7eSAndroid Build Coastguard Worker      # heap-profiler, and either "heap" or "heap_v2" for profiles
4136*1208bc7eSAndroid Build Coastguard Worker      # generated by sampling directly within tcmalloc.  It can also
4137*1208bc7eSAndroid Build Coastguard Worker      # be "growth" for heap-growth profiles.  The first is typically
4138*1208bc7eSAndroid Build Coastguard Worker      # found for profiles generated locally, and the others for
4139*1208bc7eSAndroid Build Coastguard Worker      # remote profiles.
4140*1208bc7eSAndroid Build Coastguard Worker      if (($type eq "heapprofile") || ($type !~ /heap/) ) {
4141*1208bc7eSAndroid Build Coastguard Worker        # No need to adjust for the sampling rate with heap-profiler-derived data
4142*1208bc7eSAndroid Build Coastguard Worker        $sampling_algorithm = 0;
4143*1208bc7eSAndroid Build Coastguard Worker      } elsif ($type =~ /_v2/) {
4144*1208bc7eSAndroid Build Coastguard Worker        $sampling_algorithm = 2;     # version 2 sampling
4145*1208bc7eSAndroid Build Coastguard Worker        if (defined($sample_period) && ($sample_period ne '')) {
4146*1208bc7eSAndroid Build Coastguard Worker          $sample_adjustment = int($sample_period);
4147*1208bc7eSAndroid Build Coastguard Worker        }
4148*1208bc7eSAndroid Build Coastguard Worker      } else {
4149*1208bc7eSAndroid Build Coastguard Worker        $sampling_algorithm = 1;     # version 1 sampling
4150*1208bc7eSAndroid Build Coastguard Worker        if (defined($sample_period) && ($sample_period ne '')) {
4151*1208bc7eSAndroid Build Coastguard Worker          $sample_adjustment = int($sample_period)/2;
4152*1208bc7eSAndroid Build Coastguard Worker        }
4153*1208bc7eSAndroid Build Coastguard Worker      }
4154*1208bc7eSAndroid Build Coastguard Worker    } else {
4155*1208bc7eSAndroid Build Coastguard Worker      # We detect whether or not this is a remote-heap profile by checking
4156*1208bc7eSAndroid Build Coastguard Worker      # that the total-allocated stats ($n2,$s2) are exactly the
4157*1208bc7eSAndroid Build Coastguard Worker      # same as the in-use stats ($n1,$s1).  It is remotely conceivable
4158*1208bc7eSAndroid Build Coastguard Worker      # that a non-remote-heap profile may pass this check, but it is hard
4159*1208bc7eSAndroid Build Coastguard Worker      # to imagine how that could happen.
4160*1208bc7eSAndroid Build Coastguard Worker      # In this case it's so old it's guaranteed to be remote-heap version 1.
4161*1208bc7eSAndroid Build Coastguard Worker      my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
4162*1208bc7eSAndroid Build Coastguard Worker      if (($n1 == $n2) && ($s1 == $s2)) {
4163*1208bc7eSAndroid Build Coastguard Worker        # This is likely to be a remote-heap based sample profile
4164*1208bc7eSAndroid Build Coastguard Worker        $sampling_algorithm = 1;
4165*1208bc7eSAndroid Build Coastguard Worker      }
4166*1208bc7eSAndroid Build Coastguard Worker    }
4167*1208bc7eSAndroid Build Coastguard Worker  }
4168*1208bc7eSAndroid Build Coastguard Worker
4169*1208bc7eSAndroid Build Coastguard Worker  if ($sampling_algorithm > 0) {
4170*1208bc7eSAndroid Build Coastguard Worker    # For remote-heap generated profiles, adjust the counts and sizes to
4171*1208bc7eSAndroid Build Coastguard Worker    # account for the sample rate (we sample once every 128KB by default).
4172*1208bc7eSAndroid Build Coastguard Worker    if ($sample_adjustment == 0) {
4173*1208bc7eSAndroid Build Coastguard Worker      # Turn on profile adjustment.
4174*1208bc7eSAndroid Build Coastguard Worker      $sample_adjustment = 128*1024;
4175*1208bc7eSAndroid Build Coastguard Worker      print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n";
4176*1208bc7eSAndroid Build Coastguard Worker    } else {
4177*1208bc7eSAndroid Build Coastguard Worker      printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n",
4178*1208bc7eSAndroid Build Coastguard Worker                     $sample_adjustment);
4179*1208bc7eSAndroid Build Coastguard Worker    }
4180*1208bc7eSAndroid Build Coastguard Worker    if ($sampling_algorithm > 1) {
4181*1208bc7eSAndroid Build Coastguard Worker      # We don't bother printing anything for the original version (version 1)
4182*1208bc7eSAndroid Build Coastguard Worker      printf STDERR "Heap version $sampling_algorithm\n";
4183*1208bc7eSAndroid Build Coastguard Worker    }
4184*1208bc7eSAndroid Build Coastguard Worker  }
4185*1208bc7eSAndroid Build Coastguard Worker
4186*1208bc7eSAndroid Build Coastguard Worker  my $profile = {};
4187*1208bc7eSAndroid Build Coastguard Worker  my $pcs = {};
4188*1208bc7eSAndroid Build Coastguard Worker  my $map = "";
4189*1208bc7eSAndroid Build Coastguard Worker
4190*1208bc7eSAndroid Build Coastguard Worker  while (<PROFILE>) {
4191*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;         # turn windows-looking lines into unix-looking lines
4192*1208bc7eSAndroid Build Coastguard Worker    if (/^MAPPED_LIBRARIES:/) {
4193*1208bc7eSAndroid Build Coastguard Worker      $map .= ReadMappedLibraries(*PROFILE);
4194*1208bc7eSAndroid Build Coastguard Worker      last;
4195*1208bc7eSAndroid Build Coastguard Worker    }
4196*1208bc7eSAndroid Build Coastguard Worker
4197*1208bc7eSAndroid Build Coastguard Worker    if (/^--- Memory map:/) {
4198*1208bc7eSAndroid Build Coastguard Worker      $map .= ReadMemoryMap(*PROFILE);
4199*1208bc7eSAndroid Build Coastguard Worker      last;
4200*1208bc7eSAndroid Build Coastguard Worker    }
4201*1208bc7eSAndroid Build Coastguard Worker
4202*1208bc7eSAndroid Build Coastguard Worker    # Read entry of the form:
4203*1208bc7eSAndroid Build Coastguard Worker    #  <count1>: <bytes1> [<count2>: <bytes2>] @ a1 a2 a3 ... an
4204*1208bc7eSAndroid Build Coastguard Worker    s/^\s*//;
4205*1208bc7eSAndroid Build Coastguard Worker    s/\s*$//;
4206*1208bc7eSAndroid Build Coastguard Worker    if (m/^\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]\s+@\s+(.*)$/) {
4207*1208bc7eSAndroid Build Coastguard Worker      my $stack = $5;
4208*1208bc7eSAndroid Build Coastguard Worker      my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
4209*1208bc7eSAndroid Build Coastguard Worker      my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm,
4210*1208bc7eSAndroid Build Coastguard Worker                                 $n1, $s1, $n2, $s2);
4211*1208bc7eSAndroid Build Coastguard Worker      AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]);
4212*1208bc7eSAndroid Build Coastguard Worker    }
4213*1208bc7eSAndroid Build Coastguard Worker  }
4214*1208bc7eSAndroid Build Coastguard Worker
4215*1208bc7eSAndroid Build Coastguard Worker  my $r = {};
4216*1208bc7eSAndroid Build Coastguard Worker  $r->{version} = "heap";
4217*1208bc7eSAndroid Build Coastguard Worker  $r->{period} = 1;
4218*1208bc7eSAndroid Build Coastguard Worker  $r->{profile} = $profile;
4219*1208bc7eSAndroid Build Coastguard Worker  $r->{libs} = ParseLibraries($prog, $map, $pcs);
4220*1208bc7eSAndroid Build Coastguard Worker  $r->{pcs} = $pcs;
4221*1208bc7eSAndroid Build Coastguard Worker  return $r;
4222*1208bc7eSAndroid Build Coastguard Worker}
4223*1208bc7eSAndroid Build Coastguard Worker
4224*1208bc7eSAndroid Build Coastguard Workersub ReadThreadedHeapProfile {
4225*1208bc7eSAndroid Build Coastguard Worker  my ($prog, $fname, $header) = @_;
4226*1208bc7eSAndroid Build Coastguard Worker
4227*1208bc7eSAndroid Build Coastguard Worker  my $index = HeapProfileIndex();
4228*1208bc7eSAndroid Build Coastguard Worker  my $sampling_algorithm = 0;
4229*1208bc7eSAndroid Build Coastguard Worker  my $sample_adjustment = 0;
4230*1208bc7eSAndroid Build Coastguard Worker  chomp($header);
4231*1208bc7eSAndroid Build Coastguard Worker  my $type = "unknown";
4232*1208bc7eSAndroid Build Coastguard Worker  # Assuming a very specific type of header for now.
4233*1208bc7eSAndroid Build Coastguard Worker  if ($header =~ m"^heap_v2/(\d+)") {
4234*1208bc7eSAndroid Build Coastguard Worker    $type = "_v2";
4235*1208bc7eSAndroid Build Coastguard Worker    $sampling_algorithm = 2;
4236*1208bc7eSAndroid Build Coastguard Worker    $sample_adjustment = int($1);
4237*1208bc7eSAndroid Build Coastguard Worker  }
4238*1208bc7eSAndroid Build Coastguard Worker  if ($type ne "_v2" || !defined($sample_adjustment)) {
4239*1208bc7eSAndroid Build Coastguard Worker    die "Threaded heap profiles require v2 sampling with a sample rate\n";
4240*1208bc7eSAndroid Build Coastguard Worker  }
4241*1208bc7eSAndroid Build Coastguard Worker
4242*1208bc7eSAndroid Build Coastguard Worker  my $profile = {};
4243*1208bc7eSAndroid Build Coastguard Worker  my $thread_profiles = {};
4244*1208bc7eSAndroid Build Coastguard Worker  my $pcs = {};
4245*1208bc7eSAndroid Build Coastguard Worker  my $map = "";
4246*1208bc7eSAndroid Build Coastguard Worker  my $stack = "";
4247*1208bc7eSAndroid Build Coastguard Worker
4248*1208bc7eSAndroid Build Coastguard Worker  while (<PROFILE>) {
4249*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;
4250*1208bc7eSAndroid Build Coastguard Worker    if (/^MAPPED_LIBRARIES:/) {
4251*1208bc7eSAndroid Build Coastguard Worker      $map .= ReadMappedLibraries(*PROFILE);
4252*1208bc7eSAndroid Build Coastguard Worker      last;
4253*1208bc7eSAndroid Build Coastguard Worker    }
4254*1208bc7eSAndroid Build Coastguard Worker
4255*1208bc7eSAndroid Build Coastguard Worker    if (/^--- Memory map:/) {
4256*1208bc7eSAndroid Build Coastguard Worker      $map .= ReadMemoryMap(*PROFILE);
4257*1208bc7eSAndroid Build Coastguard Worker      last;
4258*1208bc7eSAndroid Build Coastguard Worker    }
4259*1208bc7eSAndroid Build Coastguard Worker
4260*1208bc7eSAndroid Build Coastguard Worker    # Read entry of the form:
4261*1208bc7eSAndroid Build Coastguard Worker    # @ a1 a2 ... an
4262*1208bc7eSAndroid Build Coastguard Worker    #   t*: <count1>: <bytes1> [<count2>: <bytes2>]
4263*1208bc7eSAndroid Build Coastguard Worker    #   t1: <count1>: <bytes1> [<count2>: <bytes2>]
4264*1208bc7eSAndroid Build Coastguard Worker    #     ...
4265*1208bc7eSAndroid Build Coastguard Worker    #   tn: <count1>: <bytes1> [<count2>: <bytes2>]
4266*1208bc7eSAndroid Build Coastguard Worker    s/^\s*//;
4267*1208bc7eSAndroid Build Coastguard Worker    s/\s*$//;
4268*1208bc7eSAndroid Build Coastguard Worker    if (m/^@\s+(.*)$/) {
4269*1208bc7eSAndroid Build Coastguard Worker      $stack = $1;
4270*1208bc7eSAndroid Build Coastguard Worker    } elsif (m/^\s*(t(\*|\d+)):\s+(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]$/) {
4271*1208bc7eSAndroid Build Coastguard Worker      if ($stack eq "") {
4272*1208bc7eSAndroid Build Coastguard Worker        # Still in the header, so this is just a per-thread summary.
4273*1208bc7eSAndroid Build Coastguard Worker        next;
4274*1208bc7eSAndroid Build Coastguard Worker      }
4275*1208bc7eSAndroid Build Coastguard Worker      my $thread = $2;
4276*1208bc7eSAndroid Build Coastguard Worker      my ($n1, $s1, $n2, $s2) = ($3, $4, $5, $6);
4277*1208bc7eSAndroid Build Coastguard Worker      my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm,
4278*1208bc7eSAndroid Build Coastguard Worker                                 $n1, $s1, $n2, $s2);
4279*1208bc7eSAndroid Build Coastguard Worker      if ($thread eq "*") {
4280*1208bc7eSAndroid Build Coastguard Worker        AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]);
4281*1208bc7eSAndroid Build Coastguard Worker      } else {
4282*1208bc7eSAndroid Build Coastguard Worker        if (!exists($thread_profiles->{$thread})) {
4283*1208bc7eSAndroid Build Coastguard Worker          $thread_profiles->{$thread} = {};
4284*1208bc7eSAndroid Build Coastguard Worker        }
4285*1208bc7eSAndroid Build Coastguard Worker        AddEntries($thread_profiles->{$thread}, $pcs,
4286*1208bc7eSAndroid Build Coastguard Worker                   FixCallerAddresses($stack), $counts[$index]);
4287*1208bc7eSAndroid Build Coastguard Worker      }
4288*1208bc7eSAndroid Build Coastguard Worker    }
4289*1208bc7eSAndroid Build Coastguard Worker  }
4290*1208bc7eSAndroid Build Coastguard Worker
4291*1208bc7eSAndroid Build Coastguard Worker  my $r = {};
4292*1208bc7eSAndroid Build Coastguard Worker  $r->{version} = "heap";
4293*1208bc7eSAndroid Build Coastguard Worker  $r->{period} = 1;
4294*1208bc7eSAndroid Build Coastguard Worker  $r->{profile} = $profile;
4295*1208bc7eSAndroid Build Coastguard Worker  $r->{threads} = $thread_profiles;
4296*1208bc7eSAndroid Build Coastguard Worker  $r->{libs} = ParseLibraries($prog, $map, $pcs);
4297*1208bc7eSAndroid Build Coastguard Worker  $r->{pcs} = $pcs;
4298*1208bc7eSAndroid Build Coastguard Worker  return $r;
4299*1208bc7eSAndroid Build Coastguard Worker}
4300*1208bc7eSAndroid Build Coastguard Worker
4301*1208bc7eSAndroid Build Coastguard Workersub ReadSynchProfile {
4302*1208bc7eSAndroid Build Coastguard Worker  my $prog = shift;
4303*1208bc7eSAndroid Build Coastguard Worker  local *PROFILE = shift;
4304*1208bc7eSAndroid Build Coastguard Worker  my $header = shift;
4305*1208bc7eSAndroid Build Coastguard Worker
4306*1208bc7eSAndroid Build Coastguard Worker  my $map = '';
4307*1208bc7eSAndroid Build Coastguard Worker  my $profile = {};
4308*1208bc7eSAndroid Build Coastguard Worker  my $pcs = {};
4309*1208bc7eSAndroid Build Coastguard Worker  my $sampling_period = 1;
4310*1208bc7eSAndroid Build Coastguard Worker  my $cyclespernanosec = 2.8;   # Default assumption for old binaries
4311*1208bc7eSAndroid Build Coastguard Worker  my $seen_clockrate = 0;
4312*1208bc7eSAndroid Build Coastguard Worker  my $line;
4313*1208bc7eSAndroid Build Coastguard Worker
4314*1208bc7eSAndroid Build Coastguard Worker  my $index = 0;
4315*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_total_delay) {
4316*1208bc7eSAndroid Build Coastguard Worker    $index = 0;
4317*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_contentions) {
4318*1208bc7eSAndroid Build Coastguard Worker    $index = 1;
4319*1208bc7eSAndroid Build Coastguard Worker  } elsif ($main::opt_mean_delay) {
4320*1208bc7eSAndroid Build Coastguard Worker    $index = 2;
4321*1208bc7eSAndroid Build Coastguard Worker  }
4322*1208bc7eSAndroid Build Coastguard Worker
4323*1208bc7eSAndroid Build Coastguard Worker  while ( $line = <PROFILE> ) {
4324*1208bc7eSAndroid Build Coastguard Worker    $line =~ s/\r//g;      # turn windows-looking lines into unix-looking lines
4325*1208bc7eSAndroid Build Coastguard Worker    if ( $line =~ /^\s*(\d+)\s+(\d+) \@\s*(.*?)\s*$/ ) {
4326*1208bc7eSAndroid Build Coastguard Worker      my ($cycles, $count, $stack) = ($1, $2, $3);
4327*1208bc7eSAndroid Build Coastguard Worker
4328*1208bc7eSAndroid Build Coastguard Worker      # Convert cycles to nanoseconds
4329*1208bc7eSAndroid Build Coastguard Worker      $cycles /= $cyclespernanosec;
4330*1208bc7eSAndroid Build Coastguard Worker
4331*1208bc7eSAndroid Build Coastguard Worker      # Adjust for sampling done by application
4332*1208bc7eSAndroid Build Coastguard Worker      $cycles *= $sampling_period;
4333*1208bc7eSAndroid Build Coastguard Worker      $count *= $sampling_period;
4334*1208bc7eSAndroid Build Coastguard Worker
4335*1208bc7eSAndroid Build Coastguard Worker      my @values = ($cycles, $count, $cycles / $count);
4336*1208bc7eSAndroid Build Coastguard Worker      AddEntries($profile, $pcs, FixCallerAddresses($stack), $values[$index]);
4337*1208bc7eSAndroid Build Coastguard Worker
4338*1208bc7eSAndroid Build Coastguard Worker    } elsif ( $line =~ /^(slow release).*thread \d+  \@\s*(.*?)\s*$/ ||
4339*1208bc7eSAndroid Build Coastguard Worker              $line =~ /^\s*(\d+) \@\s*(.*?)\s*$/ ) {
4340*1208bc7eSAndroid Build Coastguard Worker      my ($cycles, $stack) = ($1, $2);
4341*1208bc7eSAndroid Build Coastguard Worker      if ($cycles !~ /^\d+$/) {
4342*1208bc7eSAndroid Build Coastguard Worker        next;
4343*1208bc7eSAndroid Build Coastguard Worker      }
4344*1208bc7eSAndroid Build Coastguard Worker
4345*1208bc7eSAndroid Build Coastguard Worker      # Convert cycles to nanoseconds
4346*1208bc7eSAndroid Build Coastguard Worker      $cycles /= $cyclespernanosec;
4347*1208bc7eSAndroid Build Coastguard Worker
4348*1208bc7eSAndroid Build Coastguard Worker      # Adjust for sampling done by application
4349*1208bc7eSAndroid Build Coastguard Worker      $cycles *= $sampling_period;
4350*1208bc7eSAndroid Build Coastguard Worker
4351*1208bc7eSAndroid Build Coastguard Worker      AddEntries($profile, $pcs, FixCallerAddresses($stack), $cycles);
4352*1208bc7eSAndroid Build Coastguard Worker
4353*1208bc7eSAndroid Build Coastguard Worker    } elsif ( $line =~ m/^([a-z][^=]*)=(.*)$/ ) {
4354*1208bc7eSAndroid Build Coastguard Worker      my ($variable, $value) = ($1,$2);
4355*1208bc7eSAndroid Build Coastguard Worker      for ($variable, $value) {
4356*1208bc7eSAndroid Build Coastguard Worker        s/^\s+//;
4357*1208bc7eSAndroid Build Coastguard Worker        s/\s+$//;
4358*1208bc7eSAndroid Build Coastguard Worker      }
4359*1208bc7eSAndroid Build Coastguard Worker      if ($variable eq "cycles/second") {
4360*1208bc7eSAndroid Build Coastguard Worker        $cyclespernanosec = $value / 1e9;
4361*1208bc7eSAndroid Build Coastguard Worker        $seen_clockrate = 1;
4362*1208bc7eSAndroid Build Coastguard Worker      } elsif ($variable eq "sampling period") {
4363*1208bc7eSAndroid Build Coastguard Worker        $sampling_period = $value;
4364*1208bc7eSAndroid Build Coastguard Worker      } elsif ($variable eq "ms since reset") {
4365*1208bc7eSAndroid Build Coastguard Worker        # Currently nothing is done with this value in jeprof
4366*1208bc7eSAndroid Build Coastguard Worker        # So we just silently ignore it for now
4367*1208bc7eSAndroid Build Coastguard Worker      } elsif ($variable eq "discarded samples") {
4368*1208bc7eSAndroid Build Coastguard Worker        # Currently nothing is done with this value in jeprof
4369*1208bc7eSAndroid Build Coastguard Worker        # So we just silently ignore it for now
4370*1208bc7eSAndroid Build Coastguard Worker      } else {
4371*1208bc7eSAndroid Build Coastguard Worker        printf STDERR ("Ignoring unnknown variable in /contention output: " .
4372*1208bc7eSAndroid Build Coastguard Worker                       "'%s' = '%s'\n",$variable,$value);
4373*1208bc7eSAndroid Build Coastguard Worker      }
4374*1208bc7eSAndroid Build Coastguard Worker    } else {
4375*1208bc7eSAndroid Build Coastguard Worker      # Memory map entry
4376*1208bc7eSAndroid Build Coastguard Worker      $map .= $line;
4377*1208bc7eSAndroid Build Coastguard Worker    }
4378*1208bc7eSAndroid Build Coastguard Worker  }
4379*1208bc7eSAndroid Build Coastguard Worker
4380*1208bc7eSAndroid Build Coastguard Worker  if (!$seen_clockrate) {
4381*1208bc7eSAndroid Build Coastguard Worker    printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n",
4382*1208bc7eSAndroid Build Coastguard Worker                   $cyclespernanosec);
4383*1208bc7eSAndroid Build Coastguard Worker  }
4384*1208bc7eSAndroid Build Coastguard Worker
4385*1208bc7eSAndroid Build Coastguard Worker  my $r = {};
4386*1208bc7eSAndroid Build Coastguard Worker  $r->{version} = 0;
4387*1208bc7eSAndroid Build Coastguard Worker  $r->{period} = $sampling_period;
4388*1208bc7eSAndroid Build Coastguard Worker  $r->{profile} = $profile;
4389*1208bc7eSAndroid Build Coastguard Worker  $r->{libs} = ParseLibraries($prog, $map, $pcs);
4390*1208bc7eSAndroid Build Coastguard Worker  $r->{pcs} = $pcs;
4391*1208bc7eSAndroid Build Coastguard Worker  return $r;
4392*1208bc7eSAndroid Build Coastguard Worker}
4393*1208bc7eSAndroid Build Coastguard Worker
4394*1208bc7eSAndroid Build Coastguard Worker# Given a hex value in the form "0x1abcd" or "1abcd", return either
4395*1208bc7eSAndroid Build Coastguard Worker# "0001abcd" or "000000000001abcd", depending on the current (global)
4396*1208bc7eSAndroid Build Coastguard Worker# address length.
4397*1208bc7eSAndroid Build Coastguard Workersub HexExtend {
4398*1208bc7eSAndroid Build Coastguard Worker  my $addr = shift;
4399*1208bc7eSAndroid Build Coastguard Worker
4400*1208bc7eSAndroid Build Coastguard Worker  $addr =~ s/^(0x)?0*//;
4401*1208bc7eSAndroid Build Coastguard Worker  my $zeros_needed = $address_length - length($addr);
4402*1208bc7eSAndroid Build Coastguard Worker  if ($zeros_needed < 0) {
4403*1208bc7eSAndroid Build Coastguard Worker    printf STDERR "Warning: address $addr is longer than address length $address_length\n";
4404*1208bc7eSAndroid Build Coastguard Worker    return $addr;
4405*1208bc7eSAndroid Build Coastguard Worker  }
4406*1208bc7eSAndroid Build Coastguard Worker  return ("0" x $zeros_needed) . $addr;
4407*1208bc7eSAndroid Build Coastguard Worker}
4408*1208bc7eSAndroid Build Coastguard Worker
4409*1208bc7eSAndroid Build Coastguard Worker##### Symbol extraction #####
4410*1208bc7eSAndroid Build Coastguard Worker
4411*1208bc7eSAndroid Build Coastguard Worker# Aggressively search the lib_prefix values for the given library
4412*1208bc7eSAndroid Build Coastguard Worker# If all else fails, just return the name of the library unmodified.
4413*1208bc7eSAndroid Build Coastguard Worker# If the lib_prefix is "/my/path,/other/path" and $file is "/lib/dir/mylib.so"
4414*1208bc7eSAndroid Build Coastguard Worker# it will search the following locations in this order, until it finds a file:
4415*1208bc7eSAndroid Build Coastguard Worker#   /my/path/lib/dir/mylib.so
4416*1208bc7eSAndroid Build Coastguard Worker#   /other/path/lib/dir/mylib.so
4417*1208bc7eSAndroid Build Coastguard Worker#   /my/path/dir/mylib.so
4418*1208bc7eSAndroid Build Coastguard Worker#   /other/path/dir/mylib.so
4419*1208bc7eSAndroid Build Coastguard Worker#   /my/path/mylib.so
4420*1208bc7eSAndroid Build Coastguard Worker#   /other/path/mylib.so
4421*1208bc7eSAndroid Build Coastguard Worker#   /lib/dir/mylib.so              (returned as last resort)
4422*1208bc7eSAndroid Build Coastguard Workersub FindLibrary {
4423*1208bc7eSAndroid Build Coastguard Worker  my $file = shift;
4424*1208bc7eSAndroid Build Coastguard Worker  my $suffix = $file;
4425*1208bc7eSAndroid Build Coastguard Worker
4426*1208bc7eSAndroid Build Coastguard Worker  # Search for the library as described above
4427*1208bc7eSAndroid Build Coastguard Worker  do {
4428*1208bc7eSAndroid Build Coastguard Worker    foreach my $prefix (@prefix_list) {
4429*1208bc7eSAndroid Build Coastguard Worker      my $fullpath = $prefix . $suffix;
4430*1208bc7eSAndroid Build Coastguard Worker      if (-e $fullpath) {
4431*1208bc7eSAndroid Build Coastguard Worker        return $fullpath;
4432*1208bc7eSAndroid Build Coastguard Worker      }
4433*1208bc7eSAndroid Build Coastguard Worker    }
4434*1208bc7eSAndroid Build Coastguard Worker  } while ($suffix =~ s|^/[^/]+/|/|);
4435*1208bc7eSAndroid Build Coastguard Worker  return $file;
4436*1208bc7eSAndroid Build Coastguard Worker}
4437*1208bc7eSAndroid Build Coastguard Worker
4438*1208bc7eSAndroid Build Coastguard Worker# Return path to library with debugging symbols.
4439*1208bc7eSAndroid Build Coastguard Worker# For libc libraries, the copy in /usr/lib/debug contains debugging symbols
4440*1208bc7eSAndroid Build Coastguard Workersub DebuggingLibrary {
4441*1208bc7eSAndroid Build Coastguard Worker  my $file = shift;
4442*1208bc7eSAndroid Build Coastguard Worker  if ($file =~ m|^/|) {
4443*1208bc7eSAndroid Build Coastguard Worker      if (-f "/usr/lib/debug$file") {
4444*1208bc7eSAndroid Build Coastguard Worker        return "/usr/lib/debug$file";
4445*1208bc7eSAndroid Build Coastguard Worker      } elsif (-f "/usr/lib/debug$file.debug") {
4446*1208bc7eSAndroid Build Coastguard Worker        return "/usr/lib/debug$file.debug";
4447*1208bc7eSAndroid Build Coastguard Worker      }
4448*1208bc7eSAndroid Build Coastguard Worker  }
4449*1208bc7eSAndroid Build Coastguard Worker  return undef;
4450*1208bc7eSAndroid Build Coastguard Worker}
4451*1208bc7eSAndroid Build Coastguard Worker
4452*1208bc7eSAndroid Build Coastguard Worker# Parse text section header of a library using objdump
4453*1208bc7eSAndroid Build Coastguard Workersub ParseTextSectionHeaderFromObjdump {
4454*1208bc7eSAndroid Build Coastguard Worker  my $lib = shift;
4455*1208bc7eSAndroid Build Coastguard Worker
4456*1208bc7eSAndroid Build Coastguard Worker  my $size = undef;
4457*1208bc7eSAndroid Build Coastguard Worker  my $vma;
4458*1208bc7eSAndroid Build Coastguard Worker  my $file_offset;
4459*1208bc7eSAndroid Build Coastguard Worker  # Get objdump output from the library file to figure out how to
4460*1208bc7eSAndroid Build Coastguard Worker  # map between mapped addresses and addresses in the library.
4461*1208bc7eSAndroid Build Coastguard Worker  my $cmd = ShellEscape($obj_tool_map{"objdump"}, "-h", $lib);
4462*1208bc7eSAndroid Build Coastguard Worker  open(OBJDUMP, "$cmd |") || error("$cmd: $!\n");
4463*1208bc7eSAndroid Build Coastguard Worker  while (<OBJDUMP>) {
4464*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;         # turn windows-looking lines into unix-looking lines
4465*1208bc7eSAndroid Build Coastguard Worker    # Idx Name          Size      VMA       LMA       File off  Algn
4466*1208bc7eSAndroid Build Coastguard Worker    #  10 .text         00104b2c  420156f0  420156f0  000156f0  2**4
4467*1208bc7eSAndroid Build Coastguard Worker    # For 64-bit objects, VMA and LMA will be 16 hex digits, size and file
4468*1208bc7eSAndroid Build Coastguard Worker    # offset may still be 8.  But AddressSub below will still handle that.
4469*1208bc7eSAndroid Build Coastguard Worker    my @x = split;
4470*1208bc7eSAndroid Build Coastguard Worker    if (($#x >= 6) && ($x[1] eq '.text')) {
4471*1208bc7eSAndroid Build Coastguard Worker      $size = $x[2];
4472*1208bc7eSAndroid Build Coastguard Worker      $vma = $x[3];
4473*1208bc7eSAndroid Build Coastguard Worker      $file_offset = $x[5];
4474*1208bc7eSAndroid Build Coastguard Worker      last;
4475*1208bc7eSAndroid Build Coastguard Worker    }
4476*1208bc7eSAndroid Build Coastguard Worker  }
4477*1208bc7eSAndroid Build Coastguard Worker  close(OBJDUMP);
4478*1208bc7eSAndroid Build Coastguard Worker
4479*1208bc7eSAndroid Build Coastguard Worker  if (!defined($size)) {
4480*1208bc7eSAndroid Build Coastguard Worker    return undef;
4481*1208bc7eSAndroid Build Coastguard Worker  }
4482*1208bc7eSAndroid Build Coastguard Worker
4483*1208bc7eSAndroid Build Coastguard Worker  my $r = {};
4484*1208bc7eSAndroid Build Coastguard Worker  $r->{size} = $size;
4485*1208bc7eSAndroid Build Coastguard Worker  $r->{vma} = $vma;
4486*1208bc7eSAndroid Build Coastguard Worker  $r->{file_offset} = $file_offset;
4487*1208bc7eSAndroid Build Coastguard Worker
4488*1208bc7eSAndroid Build Coastguard Worker  return $r;
4489*1208bc7eSAndroid Build Coastguard Worker}
4490*1208bc7eSAndroid Build Coastguard Worker
4491*1208bc7eSAndroid Build Coastguard Worker# Parse text section header of a library using otool (on OS X)
4492*1208bc7eSAndroid Build Coastguard Workersub ParseTextSectionHeaderFromOtool {
4493*1208bc7eSAndroid Build Coastguard Worker  my $lib = shift;
4494*1208bc7eSAndroid Build Coastguard Worker
4495*1208bc7eSAndroid Build Coastguard Worker  my $size = undef;
4496*1208bc7eSAndroid Build Coastguard Worker  my $vma = undef;
4497*1208bc7eSAndroid Build Coastguard Worker  my $file_offset = undef;
4498*1208bc7eSAndroid Build Coastguard Worker  # Get otool output from the library file to figure out how to
4499*1208bc7eSAndroid Build Coastguard Worker  # map between mapped addresses and addresses in the library.
4500*1208bc7eSAndroid Build Coastguard Worker  my $command = ShellEscape($obj_tool_map{"otool"}, "-l", $lib);
4501*1208bc7eSAndroid Build Coastguard Worker  open(OTOOL, "$command |") || error("$command: $!\n");
4502*1208bc7eSAndroid Build Coastguard Worker  my $cmd = "";
4503*1208bc7eSAndroid Build Coastguard Worker  my $sectname = "";
4504*1208bc7eSAndroid Build Coastguard Worker  my $segname = "";
4505*1208bc7eSAndroid Build Coastguard Worker  foreach my $line (<OTOOL>) {
4506*1208bc7eSAndroid Build Coastguard Worker    $line =~ s/\r//g;      # turn windows-looking lines into unix-looking lines
4507*1208bc7eSAndroid Build Coastguard Worker    # Load command <#>
4508*1208bc7eSAndroid Build Coastguard Worker    #       cmd LC_SEGMENT
4509*1208bc7eSAndroid Build Coastguard Worker    # [...]
4510*1208bc7eSAndroid Build Coastguard Worker    # Section
4511*1208bc7eSAndroid Build Coastguard Worker    #   sectname __text
4512*1208bc7eSAndroid Build Coastguard Worker    #    segname __TEXT
4513*1208bc7eSAndroid Build Coastguard Worker    #       addr 0x000009f8
4514*1208bc7eSAndroid Build Coastguard Worker    #       size 0x00018b9e
4515*1208bc7eSAndroid Build Coastguard Worker    #     offset 2552
4516*1208bc7eSAndroid Build Coastguard Worker    #      align 2^2 (4)
4517*1208bc7eSAndroid Build Coastguard Worker    # We will need to strip off the leading 0x from the hex addresses,
4518*1208bc7eSAndroid Build Coastguard Worker    # and convert the offset into hex.
4519*1208bc7eSAndroid Build Coastguard Worker    if ($line =~ /Load command/) {
4520*1208bc7eSAndroid Build Coastguard Worker      $cmd = "";
4521*1208bc7eSAndroid Build Coastguard Worker      $sectname = "";
4522*1208bc7eSAndroid Build Coastguard Worker      $segname = "";
4523*1208bc7eSAndroid Build Coastguard Worker    } elsif ($line =~ /Section/) {
4524*1208bc7eSAndroid Build Coastguard Worker      $sectname = "";
4525*1208bc7eSAndroid Build Coastguard Worker      $segname = "";
4526*1208bc7eSAndroid Build Coastguard Worker    } elsif ($line =~ /cmd (\w+)/) {
4527*1208bc7eSAndroid Build Coastguard Worker      $cmd = $1;
4528*1208bc7eSAndroid Build Coastguard Worker    } elsif ($line =~ /sectname (\w+)/) {
4529*1208bc7eSAndroid Build Coastguard Worker      $sectname = $1;
4530*1208bc7eSAndroid Build Coastguard Worker    } elsif ($line =~ /segname (\w+)/) {
4531*1208bc7eSAndroid Build Coastguard Worker      $segname = $1;
4532*1208bc7eSAndroid Build Coastguard Worker    } elsif (!(($cmd eq "LC_SEGMENT" || $cmd eq "LC_SEGMENT_64") &&
4533*1208bc7eSAndroid Build Coastguard Worker               $sectname eq "__text" &&
4534*1208bc7eSAndroid Build Coastguard Worker               $segname eq "__TEXT")) {
4535*1208bc7eSAndroid Build Coastguard Worker      next;
4536*1208bc7eSAndroid Build Coastguard Worker    } elsif ($line =~ /\baddr 0x([0-9a-fA-F]+)/) {
4537*1208bc7eSAndroid Build Coastguard Worker      $vma = $1;
4538*1208bc7eSAndroid Build Coastguard Worker    } elsif ($line =~ /\bsize 0x([0-9a-fA-F]+)/) {
4539*1208bc7eSAndroid Build Coastguard Worker      $size = $1;
4540*1208bc7eSAndroid Build Coastguard Worker    } elsif ($line =~ /\boffset ([0-9]+)/) {
4541*1208bc7eSAndroid Build Coastguard Worker      $file_offset = sprintf("%016x", $1);
4542*1208bc7eSAndroid Build Coastguard Worker    }
4543*1208bc7eSAndroid Build Coastguard Worker    if (defined($vma) && defined($size) && defined($file_offset)) {
4544*1208bc7eSAndroid Build Coastguard Worker      last;
4545*1208bc7eSAndroid Build Coastguard Worker    }
4546*1208bc7eSAndroid Build Coastguard Worker  }
4547*1208bc7eSAndroid Build Coastguard Worker  close(OTOOL);
4548*1208bc7eSAndroid Build Coastguard Worker
4549*1208bc7eSAndroid Build Coastguard Worker  if (!defined($vma) || !defined($size) || !defined($file_offset)) {
4550*1208bc7eSAndroid Build Coastguard Worker     return undef;
4551*1208bc7eSAndroid Build Coastguard Worker  }
4552*1208bc7eSAndroid Build Coastguard Worker
4553*1208bc7eSAndroid Build Coastguard Worker  my $r = {};
4554*1208bc7eSAndroid Build Coastguard Worker  $r->{size} = $size;
4555*1208bc7eSAndroid Build Coastguard Worker  $r->{vma} = $vma;
4556*1208bc7eSAndroid Build Coastguard Worker  $r->{file_offset} = $file_offset;
4557*1208bc7eSAndroid Build Coastguard Worker
4558*1208bc7eSAndroid Build Coastguard Worker  return $r;
4559*1208bc7eSAndroid Build Coastguard Worker}
4560*1208bc7eSAndroid Build Coastguard Worker
4561*1208bc7eSAndroid Build Coastguard Workersub ParseTextSectionHeader {
4562*1208bc7eSAndroid Build Coastguard Worker  # obj_tool_map("otool") is only defined if we're in a Mach-O environment
4563*1208bc7eSAndroid Build Coastguard Worker  if (defined($obj_tool_map{"otool"})) {
4564*1208bc7eSAndroid Build Coastguard Worker    my $r = ParseTextSectionHeaderFromOtool(@_);
4565*1208bc7eSAndroid Build Coastguard Worker    if (defined($r)){
4566*1208bc7eSAndroid Build Coastguard Worker      return $r;
4567*1208bc7eSAndroid Build Coastguard Worker    }
4568*1208bc7eSAndroid Build Coastguard Worker  }
4569*1208bc7eSAndroid Build Coastguard Worker  # If otool doesn't work, or we don't have it, fall back to objdump
4570*1208bc7eSAndroid Build Coastguard Worker  return ParseTextSectionHeaderFromObjdump(@_);
4571*1208bc7eSAndroid Build Coastguard Worker}
4572*1208bc7eSAndroid Build Coastguard Worker
4573*1208bc7eSAndroid Build Coastguard Worker# Split /proc/pid/maps dump into a list of libraries
4574*1208bc7eSAndroid Build Coastguard Workersub ParseLibraries {
4575*1208bc7eSAndroid Build Coastguard Worker  return if $main::use_symbol_page;  # We don't need libraries info.
4576*1208bc7eSAndroid Build Coastguard Worker  my $prog = Cwd::abs_path(shift);
4577*1208bc7eSAndroid Build Coastguard Worker  my $map = shift;
4578*1208bc7eSAndroid Build Coastguard Worker  my $pcs = shift;
4579*1208bc7eSAndroid Build Coastguard Worker
4580*1208bc7eSAndroid Build Coastguard Worker  my $result = [];
4581*1208bc7eSAndroid Build Coastguard Worker  my $h = "[a-f0-9]+";
4582*1208bc7eSAndroid Build Coastguard Worker  my $zero_offset = HexExtend("0");
4583*1208bc7eSAndroid Build Coastguard Worker
4584*1208bc7eSAndroid Build Coastguard Worker  my $buildvar = "";
4585*1208bc7eSAndroid Build Coastguard Worker  foreach my $l (split("\n", $map)) {
4586*1208bc7eSAndroid Build Coastguard Worker    if ($l =~ m/^\s*build=(.*)$/) {
4587*1208bc7eSAndroid Build Coastguard Worker      $buildvar = $1;
4588*1208bc7eSAndroid Build Coastguard Worker    }
4589*1208bc7eSAndroid Build Coastguard Worker
4590*1208bc7eSAndroid Build Coastguard Worker    my $start;
4591*1208bc7eSAndroid Build Coastguard Worker    my $finish;
4592*1208bc7eSAndroid Build Coastguard Worker    my $offset;
4593*1208bc7eSAndroid Build Coastguard Worker    my $lib;
4594*1208bc7eSAndroid Build Coastguard Worker    if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d+){0,3})?)$/i) {
4595*1208bc7eSAndroid Build Coastguard Worker      # Full line from /proc/self/maps.  Example:
4596*1208bc7eSAndroid Build Coastguard Worker      #   40000000-40015000 r-xp 00000000 03:01 12845071   /lib/ld-2.3.2.so
4597*1208bc7eSAndroid Build Coastguard Worker      $start = HexExtend($1);
4598*1208bc7eSAndroid Build Coastguard Worker      $finish = HexExtend($2);
4599*1208bc7eSAndroid Build Coastguard Worker      $offset = HexExtend($3);
4600*1208bc7eSAndroid Build Coastguard Worker      $lib = $4;
4601*1208bc7eSAndroid Build Coastguard Worker      $lib =~ s|\\|/|g;     # turn windows-style paths into unix-style paths
4602*1208bc7eSAndroid Build Coastguard Worker    } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) {
4603*1208bc7eSAndroid Build Coastguard Worker      # Cooked line from DumpAddressMap.  Example:
4604*1208bc7eSAndroid Build Coastguard Worker      #   40000000-40015000: /lib/ld-2.3.2.so
4605*1208bc7eSAndroid Build Coastguard Worker      $start = HexExtend($1);
4606*1208bc7eSAndroid Build Coastguard Worker      $finish = HexExtend($2);
4607*1208bc7eSAndroid Build Coastguard Worker      $offset = $zero_offset;
4608*1208bc7eSAndroid Build Coastguard Worker      $lib = $3;
4609*1208bc7eSAndroid Build Coastguard Worker    } elsif (($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+)$/i) && ($4 eq $prog)) {
4610*1208bc7eSAndroid Build Coastguard Worker      # PIEs and address space randomization do not play well with our
4611*1208bc7eSAndroid Build Coastguard Worker      # default assumption that main executable is at lowest
4612*1208bc7eSAndroid Build Coastguard Worker      # addresses. So we're detecting main executable in
4613*1208bc7eSAndroid Build Coastguard Worker      # /proc/self/maps as well.
4614*1208bc7eSAndroid Build Coastguard Worker      $start = HexExtend($1);
4615*1208bc7eSAndroid Build Coastguard Worker      $finish = HexExtend($2);
4616*1208bc7eSAndroid Build Coastguard Worker      $offset = HexExtend($3);
4617*1208bc7eSAndroid Build Coastguard Worker      $lib = $4;
4618*1208bc7eSAndroid Build Coastguard Worker      $lib =~ s|\\|/|g;     # turn windows-style paths into unix-style paths
4619*1208bc7eSAndroid Build Coastguard Worker    }
4620*1208bc7eSAndroid Build Coastguard Worker    # FreeBSD 10.0 virtual memory map /proc/curproc/map as defined in
4621*1208bc7eSAndroid Build Coastguard Worker    # function procfs_doprocmap (sys/fs/procfs/procfs_map.c)
4622*1208bc7eSAndroid Build Coastguard Worker    #
4623*1208bc7eSAndroid Build Coastguard Worker    # Example:
4624*1208bc7eSAndroid Build Coastguard Worker    # 0x800600000 0x80061a000 26 0 0xfffff800035a0000 r-x 75 33 0x1004 COW NC vnode /libexec/ld-elf.s
4625*1208bc7eSAndroid Build Coastguard Worker    # o.1 NCH -1
4626*1208bc7eSAndroid Build Coastguard Worker    elsif ($l =~ /^(0x$h)\s(0x$h)\s\d+\s\d+\s0x$h\sr-x\s\d+\s\d+\s0x\d+\s(COW|NCO)\s(NC|NNC)\svnode\s(\S+\.so(\.\d+)*)/) {
4627*1208bc7eSAndroid Build Coastguard Worker      $start = HexExtend($1);
4628*1208bc7eSAndroid Build Coastguard Worker      $finish = HexExtend($2);
4629*1208bc7eSAndroid Build Coastguard Worker      $offset = $zero_offset;
4630*1208bc7eSAndroid Build Coastguard Worker      $lib = FindLibrary($5);
4631*1208bc7eSAndroid Build Coastguard Worker
4632*1208bc7eSAndroid Build Coastguard Worker    } else {
4633*1208bc7eSAndroid Build Coastguard Worker      next;
4634*1208bc7eSAndroid Build Coastguard Worker    }
4635*1208bc7eSAndroid Build Coastguard Worker
4636*1208bc7eSAndroid Build Coastguard Worker    # Expand "$build" variable if available
4637*1208bc7eSAndroid Build Coastguard Worker    $lib =~ s/\$build\b/$buildvar/g;
4638*1208bc7eSAndroid Build Coastguard Worker
4639*1208bc7eSAndroid Build Coastguard Worker    $lib = FindLibrary($lib);
4640*1208bc7eSAndroid Build Coastguard Worker
4641*1208bc7eSAndroid Build Coastguard Worker    # Check for pre-relocated libraries, which use pre-relocated symbol tables
4642*1208bc7eSAndroid Build Coastguard Worker    # and thus require adjusting the offset that we'll use to translate
4643*1208bc7eSAndroid Build Coastguard Worker    # VM addresses into symbol table addresses.
4644*1208bc7eSAndroid Build Coastguard Worker    # Only do this if we're not going to fetch the symbol table from a
4645*1208bc7eSAndroid Build Coastguard Worker    # debugging copy of the library.
4646*1208bc7eSAndroid Build Coastguard Worker    if (!DebuggingLibrary($lib)) {
4647*1208bc7eSAndroid Build Coastguard Worker      my $text = ParseTextSectionHeader($lib);
4648*1208bc7eSAndroid Build Coastguard Worker      if (defined($text)) {
4649*1208bc7eSAndroid Build Coastguard Worker         my $vma_offset = AddressSub($text->{vma}, $text->{file_offset});
4650*1208bc7eSAndroid Build Coastguard Worker         $offset = AddressAdd($offset, $vma_offset);
4651*1208bc7eSAndroid Build Coastguard Worker      }
4652*1208bc7eSAndroid Build Coastguard Worker    }
4653*1208bc7eSAndroid Build Coastguard Worker
4654*1208bc7eSAndroid Build Coastguard Worker    if($main::opt_debug) { printf STDERR "$start:$finish ($offset) $lib\n"; }
4655*1208bc7eSAndroid Build Coastguard Worker    push(@{$result}, [$lib, $start, $finish, $offset]);
4656*1208bc7eSAndroid Build Coastguard Worker  }
4657*1208bc7eSAndroid Build Coastguard Worker
4658*1208bc7eSAndroid Build Coastguard Worker  # Append special entry for additional library (not relocated)
4659*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_lib ne "") {
4660*1208bc7eSAndroid Build Coastguard Worker    my $text = ParseTextSectionHeader($main::opt_lib);
4661*1208bc7eSAndroid Build Coastguard Worker    if (defined($text)) {
4662*1208bc7eSAndroid Build Coastguard Worker       my $start = $text->{vma};
4663*1208bc7eSAndroid Build Coastguard Worker       my $finish = AddressAdd($start, $text->{size});
4664*1208bc7eSAndroid Build Coastguard Worker
4665*1208bc7eSAndroid Build Coastguard Worker       push(@{$result}, [$main::opt_lib, $start, $finish, $start]);
4666*1208bc7eSAndroid Build Coastguard Worker    }
4667*1208bc7eSAndroid Build Coastguard Worker  }
4668*1208bc7eSAndroid Build Coastguard Worker
4669*1208bc7eSAndroid Build Coastguard Worker  # Append special entry for the main program.  This covers
4670*1208bc7eSAndroid Build Coastguard Worker  # 0..max_pc_value_seen, so that we assume pc values not found in one
4671*1208bc7eSAndroid Build Coastguard Worker  # of the library ranges will be treated as coming from the main
4672*1208bc7eSAndroid Build Coastguard Worker  # program binary.
4673*1208bc7eSAndroid Build Coastguard Worker  my $min_pc = HexExtend("0");
4674*1208bc7eSAndroid Build Coastguard Worker  my $max_pc = $min_pc;          # find the maximal PC value in any sample
4675*1208bc7eSAndroid Build Coastguard Worker  foreach my $pc (keys(%{$pcs})) {
4676*1208bc7eSAndroid Build Coastguard Worker    if (HexExtend($pc) gt $max_pc) { $max_pc = HexExtend($pc); }
4677*1208bc7eSAndroid Build Coastguard Worker  }
4678*1208bc7eSAndroid Build Coastguard Worker  push(@{$result}, [$prog, $min_pc, $max_pc, $zero_offset]);
4679*1208bc7eSAndroid Build Coastguard Worker
4680*1208bc7eSAndroid Build Coastguard Worker  return $result;
4681*1208bc7eSAndroid Build Coastguard Worker}
4682*1208bc7eSAndroid Build Coastguard Worker
4683*1208bc7eSAndroid Build Coastguard Worker# Add two hex addresses of length $address_length.
4684*1208bc7eSAndroid Build Coastguard Worker# Run jeprof --test for unit test if this is changed.
4685*1208bc7eSAndroid Build Coastguard Workersub AddressAdd {
4686*1208bc7eSAndroid Build Coastguard Worker  my $addr1 = shift;
4687*1208bc7eSAndroid Build Coastguard Worker  my $addr2 = shift;
4688*1208bc7eSAndroid Build Coastguard Worker  my $sum;
4689*1208bc7eSAndroid Build Coastguard Worker
4690*1208bc7eSAndroid Build Coastguard Worker  if ($address_length == 8) {
4691*1208bc7eSAndroid Build Coastguard Worker    # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
4692*1208bc7eSAndroid Build Coastguard Worker    $sum = (hex($addr1)+hex($addr2)) % (0x10000000 * 16);
4693*1208bc7eSAndroid Build Coastguard Worker    return sprintf("%08x", $sum);
4694*1208bc7eSAndroid Build Coastguard Worker
4695*1208bc7eSAndroid Build Coastguard Worker  } else {
4696*1208bc7eSAndroid Build Coastguard Worker    # Do the addition in 7-nibble chunks to trivialize carry handling.
4697*1208bc7eSAndroid Build Coastguard Worker
4698*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_debug and $main::opt_test) {
4699*1208bc7eSAndroid Build Coastguard Worker      print STDERR "AddressAdd $addr1 + $addr2 = ";
4700*1208bc7eSAndroid Build Coastguard Worker    }
4701*1208bc7eSAndroid Build Coastguard Worker
4702*1208bc7eSAndroid Build Coastguard Worker    my $a1 = substr($addr1,-7);
4703*1208bc7eSAndroid Build Coastguard Worker    $addr1 = substr($addr1,0,-7);
4704*1208bc7eSAndroid Build Coastguard Worker    my $a2 = substr($addr2,-7);
4705*1208bc7eSAndroid Build Coastguard Worker    $addr2 = substr($addr2,0,-7);
4706*1208bc7eSAndroid Build Coastguard Worker    $sum = hex($a1) + hex($a2);
4707*1208bc7eSAndroid Build Coastguard Worker    my $c = 0;
4708*1208bc7eSAndroid Build Coastguard Worker    if ($sum > 0xfffffff) {
4709*1208bc7eSAndroid Build Coastguard Worker      $c = 1;
4710*1208bc7eSAndroid Build Coastguard Worker      $sum -= 0x10000000;
4711*1208bc7eSAndroid Build Coastguard Worker    }
4712*1208bc7eSAndroid Build Coastguard Worker    my $r = sprintf("%07x", $sum);
4713*1208bc7eSAndroid Build Coastguard Worker
4714*1208bc7eSAndroid Build Coastguard Worker    $a1 = substr($addr1,-7);
4715*1208bc7eSAndroid Build Coastguard Worker    $addr1 = substr($addr1,0,-7);
4716*1208bc7eSAndroid Build Coastguard Worker    $a2 = substr($addr2,-7);
4717*1208bc7eSAndroid Build Coastguard Worker    $addr2 = substr($addr2,0,-7);
4718*1208bc7eSAndroid Build Coastguard Worker    $sum = hex($a1) + hex($a2) + $c;
4719*1208bc7eSAndroid Build Coastguard Worker    $c = 0;
4720*1208bc7eSAndroid Build Coastguard Worker    if ($sum > 0xfffffff) {
4721*1208bc7eSAndroid Build Coastguard Worker      $c = 1;
4722*1208bc7eSAndroid Build Coastguard Worker      $sum -= 0x10000000;
4723*1208bc7eSAndroid Build Coastguard Worker    }
4724*1208bc7eSAndroid Build Coastguard Worker    $r = sprintf("%07x", $sum) . $r;
4725*1208bc7eSAndroid Build Coastguard Worker
4726*1208bc7eSAndroid Build Coastguard Worker    $sum = hex($addr1) + hex($addr2) + $c;
4727*1208bc7eSAndroid Build Coastguard Worker    if ($sum > 0xff) { $sum -= 0x100; }
4728*1208bc7eSAndroid Build Coastguard Worker    $r = sprintf("%02x", $sum) . $r;
4729*1208bc7eSAndroid Build Coastguard Worker
4730*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_debug and $main::opt_test) { print STDERR "$r\n"; }
4731*1208bc7eSAndroid Build Coastguard Worker
4732*1208bc7eSAndroid Build Coastguard Worker    return $r;
4733*1208bc7eSAndroid Build Coastguard Worker  }
4734*1208bc7eSAndroid Build Coastguard Worker}
4735*1208bc7eSAndroid Build Coastguard Worker
4736*1208bc7eSAndroid Build Coastguard Worker
4737*1208bc7eSAndroid Build Coastguard Worker# Subtract two hex addresses of length $address_length.
4738*1208bc7eSAndroid Build Coastguard Worker# Run jeprof --test for unit test if this is changed.
4739*1208bc7eSAndroid Build Coastguard Workersub AddressSub {
4740*1208bc7eSAndroid Build Coastguard Worker  my $addr1 = shift;
4741*1208bc7eSAndroid Build Coastguard Worker  my $addr2 = shift;
4742*1208bc7eSAndroid Build Coastguard Worker  my $diff;
4743*1208bc7eSAndroid Build Coastguard Worker
4744*1208bc7eSAndroid Build Coastguard Worker  if ($address_length == 8) {
4745*1208bc7eSAndroid Build Coastguard Worker    # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
4746*1208bc7eSAndroid Build Coastguard Worker    $diff = (hex($addr1)-hex($addr2)) % (0x10000000 * 16);
4747*1208bc7eSAndroid Build Coastguard Worker    return sprintf("%08x", $diff);
4748*1208bc7eSAndroid Build Coastguard Worker
4749*1208bc7eSAndroid Build Coastguard Worker  } else {
4750*1208bc7eSAndroid Build Coastguard Worker    # Do the addition in 7-nibble chunks to trivialize borrow handling.
4751*1208bc7eSAndroid Build Coastguard Worker    # if ($main::opt_debug) { print STDERR "AddressSub $addr1 - $addr2 = "; }
4752*1208bc7eSAndroid Build Coastguard Worker
4753*1208bc7eSAndroid Build Coastguard Worker    my $a1 = hex(substr($addr1,-7));
4754*1208bc7eSAndroid Build Coastguard Worker    $addr1 = substr($addr1,0,-7);
4755*1208bc7eSAndroid Build Coastguard Worker    my $a2 = hex(substr($addr2,-7));
4756*1208bc7eSAndroid Build Coastguard Worker    $addr2 = substr($addr2,0,-7);
4757*1208bc7eSAndroid Build Coastguard Worker    my $b = 0;
4758*1208bc7eSAndroid Build Coastguard Worker    if ($a2 > $a1) {
4759*1208bc7eSAndroid Build Coastguard Worker      $b = 1;
4760*1208bc7eSAndroid Build Coastguard Worker      $a1 += 0x10000000;
4761*1208bc7eSAndroid Build Coastguard Worker    }
4762*1208bc7eSAndroid Build Coastguard Worker    $diff = $a1 - $a2;
4763*1208bc7eSAndroid Build Coastguard Worker    my $r = sprintf("%07x", $diff);
4764*1208bc7eSAndroid Build Coastguard Worker
4765*1208bc7eSAndroid Build Coastguard Worker    $a1 = hex(substr($addr1,-7));
4766*1208bc7eSAndroid Build Coastguard Worker    $addr1 = substr($addr1,0,-7);
4767*1208bc7eSAndroid Build Coastguard Worker    $a2 = hex(substr($addr2,-7)) + $b;
4768*1208bc7eSAndroid Build Coastguard Worker    $addr2 = substr($addr2,0,-7);
4769*1208bc7eSAndroid Build Coastguard Worker    $b = 0;
4770*1208bc7eSAndroid Build Coastguard Worker    if ($a2 > $a1) {
4771*1208bc7eSAndroid Build Coastguard Worker      $b = 1;
4772*1208bc7eSAndroid Build Coastguard Worker      $a1 += 0x10000000;
4773*1208bc7eSAndroid Build Coastguard Worker    }
4774*1208bc7eSAndroid Build Coastguard Worker    $diff = $a1 - $a2;
4775*1208bc7eSAndroid Build Coastguard Worker    $r = sprintf("%07x", $diff) . $r;
4776*1208bc7eSAndroid Build Coastguard Worker
4777*1208bc7eSAndroid Build Coastguard Worker    $a1 = hex($addr1);
4778*1208bc7eSAndroid Build Coastguard Worker    $a2 = hex($addr2) + $b;
4779*1208bc7eSAndroid Build Coastguard Worker    if ($a2 > $a1) { $a1 += 0x100; }
4780*1208bc7eSAndroid Build Coastguard Worker    $diff = $a1 - $a2;
4781*1208bc7eSAndroid Build Coastguard Worker    $r = sprintf("%02x", $diff) . $r;
4782*1208bc7eSAndroid Build Coastguard Worker
4783*1208bc7eSAndroid Build Coastguard Worker    # if ($main::opt_debug) { print STDERR "$r\n"; }
4784*1208bc7eSAndroid Build Coastguard Worker
4785*1208bc7eSAndroid Build Coastguard Worker    return $r;
4786*1208bc7eSAndroid Build Coastguard Worker  }
4787*1208bc7eSAndroid Build Coastguard Worker}
4788*1208bc7eSAndroid Build Coastguard Worker
4789*1208bc7eSAndroid Build Coastguard Worker# Increment a hex addresses of length $address_length.
4790*1208bc7eSAndroid Build Coastguard Worker# Run jeprof --test for unit test if this is changed.
4791*1208bc7eSAndroid Build Coastguard Workersub AddressInc {
4792*1208bc7eSAndroid Build Coastguard Worker  my $addr = shift;
4793*1208bc7eSAndroid Build Coastguard Worker  my $sum;
4794*1208bc7eSAndroid Build Coastguard Worker
4795*1208bc7eSAndroid Build Coastguard Worker  if ($address_length == 8) {
4796*1208bc7eSAndroid Build Coastguard Worker    # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
4797*1208bc7eSAndroid Build Coastguard Worker    $sum = (hex($addr)+1) % (0x10000000 * 16);
4798*1208bc7eSAndroid Build Coastguard Worker    return sprintf("%08x", $sum);
4799*1208bc7eSAndroid Build Coastguard Worker
4800*1208bc7eSAndroid Build Coastguard Worker  } else {
4801*1208bc7eSAndroid Build Coastguard Worker    # Do the addition in 7-nibble chunks to trivialize carry handling.
4802*1208bc7eSAndroid Build Coastguard Worker    # We are always doing this to step through the addresses in a function,
4803*1208bc7eSAndroid Build Coastguard Worker    # and will almost never overflow the first chunk, so we check for this
4804*1208bc7eSAndroid Build Coastguard Worker    # case and exit early.
4805*1208bc7eSAndroid Build Coastguard Worker
4806*1208bc7eSAndroid Build Coastguard Worker    # if ($main::opt_debug) { print STDERR "AddressInc $addr1 = "; }
4807*1208bc7eSAndroid Build Coastguard Worker
4808*1208bc7eSAndroid Build Coastguard Worker    my $a1 = substr($addr,-7);
4809*1208bc7eSAndroid Build Coastguard Worker    $addr = substr($addr,0,-7);
4810*1208bc7eSAndroid Build Coastguard Worker    $sum = hex($a1) + 1;
4811*1208bc7eSAndroid Build Coastguard Worker    my $r = sprintf("%07x", $sum);
4812*1208bc7eSAndroid Build Coastguard Worker    if ($sum <= 0xfffffff) {
4813*1208bc7eSAndroid Build Coastguard Worker      $r = $addr . $r;
4814*1208bc7eSAndroid Build Coastguard Worker      # if ($main::opt_debug) { print STDERR "$r\n"; }
4815*1208bc7eSAndroid Build Coastguard Worker      return HexExtend($r);
4816*1208bc7eSAndroid Build Coastguard Worker    } else {
4817*1208bc7eSAndroid Build Coastguard Worker      $r = "0000000";
4818*1208bc7eSAndroid Build Coastguard Worker    }
4819*1208bc7eSAndroid Build Coastguard Worker
4820*1208bc7eSAndroid Build Coastguard Worker    $a1 = substr($addr,-7);
4821*1208bc7eSAndroid Build Coastguard Worker    $addr = substr($addr,0,-7);
4822*1208bc7eSAndroid Build Coastguard Worker    $sum = hex($a1) + 1;
4823*1208bc7eSAndroid Build Coastguard Worker    $r = sprintf("%07x", $sum) . $r;
4824*1208bc7eSAndroid Build Coastguard Worker    if ($sum <= 0xfffffff) {
4825*1208bc7eSAndroid Build Coastguard Worker      $r = $addr . $r;
4826*1208bc7eSAndroid Build Coastguard Worker      # if ($main::opt_debug) { print STDERR "$r\n"; }
4827*1208bc7eSAndroid Build Coastguard Worker      return HexExtend($r);
4828*1208bc7eSAndroid Build Coastguard Worker    } else {
4829*1208bc7eSAndroid Build Coastguard Worker      $r = "00000000000000";
4830*1208bc7eSAndroid Build Coastguard Worker    }
4831*1208bc7eSAndroid Build Coastguard Worker
4832*1208bc7eSAndroid Build Coastguard Worker    $sum = hex($addr) + 1;
4833*1208bc7eSAndroid Build Coastguard Worker    if ($sum > 0xff) { $sum -= 0x100; }
4834*1208bc7eSAndroid Build Coastguard Worker    $r = sprintf("%02x", $sum) . $r;
4835*1208bc7eSAndroid Build Coastguard Worker
4836*1208bc7eSAndroid Build Coastguard Worker    # if ($main::opt_debug) { print STDERR "$r\n"; }
4837*1208bc7eSAndroid Build Coastguard Worker    return $r;
4838*1208bc7eSAndroid Build Coastguard Worker  }
4839*1208bc7eSAndroid Build Coastguard Worker}
4840*1208bc7eSAndroid Build Coastguard Worker
4841*1208bc7eSAndroid Build Coastguard Worker# Extract symbols for all PC values found in profile
4842*1208bc7eSAndroid Build Coastguard Workersub ExtractSymbols {
4843*1208bc7eSAndroid Build Coastguard Worker  my $libs = shift;
4844*1208bc7eSAndroid Build Coastguard Worker  my $pcset = shift;
4845*1208bc7eSAndroid Build Coastguard Worker
4846*1208bc7eSAndroid Build Coastguard Worker  my $symbols = {};
4847*1208bc7eSAndroid Build Coastguard Worker
4848*1208bc7eSAndroid Build Coastguard Worker  # Map each PC value to the containing library.  To make this faster,
4849*1208bc7eSAndroid Build Coastguard Worker  # we sort libraries by their starting pc value (highest first), and
4850*1208bc7eSAndroid Build Coastguard Worker  # advance through the libraries as we advance the pc.  Sometimes the
4851*1208bc7eSAndroid Build Coastguard Worker  # addresses of libraries may overlap with the addresses of the main
4852*1208bc7eSAndroid Build Coastguard Worker  # binary, so to make sure the libraries 'win', we iterate over the
4853*1208bc7eSAndroid Build Coastguard Worker  # libraries in reverse order (which assumes the binary doesn't start
4854*1208bc7eSAndroid Build Coastguard Worker  # in the middle of a library, which seems a fair assumption).
4855*1208bc7eSAndroid Build Coastguard Worker  my @pcs = (sort { $a cmp $b } keys(%{$pcset}));  # pcset is 0-extended strings
4856*1208bc7eSAndroid Build Coastguard Worker  foreach my $lib (sort {$b->[1] cmp $a->[1]} @{$libs}) {
4857*1208bc7eSAndroid Build Coastguard Worker    my $libname = $lib->[0];
4858*1208bc7eSAndroid Build Coastguard Worker    my $start = $lib->[1];
4859*1208bc7eSAndroid Build Coastguard Worker    my $finish = $lib->[2];
4860*1208bc7eSAndroid Build Coastguard Worker    my $offset = $lib->[3];
4861*1208bc7eSAndroid Build Coastguard Worker
4862*1208bc7eSAndroid Build Coastguard Worker    # Use debug library if it exists
4863*1208bc7eSAndroid Build Coastguard Worker    my $debug_libname = DebuggingLibrary($libname);
4864*1208bc7eSAndroid Build Coastguard Worker    if ($debug_libname) {
4865*1208bc7eSAndroid Build Coastguard Worker        $libname = $debug_libname;
4866*1208bc7eSAndroid Build Coastguard Worker    }
4867*1208bc7eSAndroid Build Coastguard Worker
4868*1208bc7eSAndroid Build Coastguard Worker    # Get list of pcs that belong in this library.
4869*1208bc7eSAndroid Build Coastguard Worker    my $contained = [];
4870*1208bc7eSAndroid Build Coastguard Worker    my ($start_pc_index, $finish_pc_index);
4871*1208bc7eSAndroid Build Coastguard Worker    # Find smallest finish_pc_index such that $finish < $pc[$finish_pc_index].
4872*1208bc7eSAndroid Build Coastguard Worker    for ($finish_pc_index = $#pcs + 1; $finish_pc_index > 0;
4873*1208bc7eSAndroid Build Coastguard Worker         $finish_pc_index--) {
4874*1208bc7eSAndroid Build Coastguard Worker      last if $pcs[$finish_pc_index - 1] le $finish;
4875*1208bc7eSAndroid Build Coastguard Worker    }
4876*1208bc7eSAndroid Build Coastguard Worker    # Find smallest start_pc_index such that $start <= $pc[$start_pc_index].
4877*1208bc7eSAndroid Build Coastguard Worker    for ($start_pc_index = $finish_pc_index; $start_pc_index > 0;
4878*1208bc7eSAndroid Build Coastguard Worker         $start_pc_index--) {
4879*1208bc7eSAndroid Build Coastguard Worker      last if $pcs[$start_pc_index - 1] lt $start;
4880*1208bc7eSAndroid Build Coastguard Worker    }
4881*1208bc7eSAndroid Build Coastguard Worker    # This keeps PC values higher than $pc[$finish_pc_index] in @pcs,
4882*1208bc7eSAndroid Build Coastguard Worker    # in case there are overlaps in libraries and the main binary.
4883*1208bc7eSAndroid Build Coastguard Worker    @{$contained} = splice(@pcs, $start_pc_index,
4884*1208bc7eSAndroid Build Coastguard Worker                           $finish_pc_index - $start_pc_index);
4885*1208bc7eSAndroid Build Coastguard Worker    # Map to symbols
4886*1208bc7eSAndroid Build Coastguard Worker    MapToSymbols($libname, AddressSub($start, $offset), $contained, $symbols);
4887*1208bc7eSAndroid Build Coastguard Worker  }
4888*1208bc7eSAndroid Build Coastguard Worker
4889*1208bc7eSAndroid Build Coastguard Worker  return $symbols;
4890*1208bc7eSAndroid Build Coastguard Worker}
4891*1208bc7eSAndroid Build Coastguard Worker
4892*1208bc7eSAndroid Build Coastguard Worker# Map list of PC values to symbols for a given image
4893*1208bc7eSAndroid Build Coastguard Workersub MapToSymbols {
4894*1208bc7eSAndroid Build Coastguard Worker  my $image = shift;
4895*1208bc7eSAndroid Build Coastguard Worker  my $offset = shift;
4896*1208bc7eSAndroid Build Coastguard Worker  my $pclist = shift;
4897*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
4898*1208bc7eSAndroid Build Coastguard Worker
4899*1208bc7eSAndroid Build Coastguard Worker  my $debug = 0;
4900*1208bc7eSAndroid Build Coastguard Worker
4901*1208bc7eSAndroid Build Coastguard Worker  # Ignore empty binaries
4902*1208bc7eSAndroid Build Coastguard Worker  if ($#{$pclist} < 0) { return; }
4903*1208bc7eSAndroid Build Coastguard Worker
4904*1208bc7eSAndroid Build Coastguard Worker  # Figure out the addr2line command to use
4905*1208bc7eSAndroid Build Coastguard Worker  my $addr2line = $obj_tool_map{"addr2line"};
4906*1208bc7eSAndroid Build Coastguard Worker  my $cmd = ShellEscape($addr2line, "-f", "-C", "-e", $image);
4907*1208bc7eSAndroid Build Coastguard Worker  if (exists $obj_tool_map{"addr2line_pdb"}) {
4908*1208bc7eSAndroid Build Coastguard Worker    $addr2line = $obj_tool_map{"addr2line_pdb"};
4909*1208bc7eSAndroid Build Coastguard Worker    $cmd = ShellEscape($addr2line, "--demangle", "-f", "-C", "-e", $image);
4910*1208bc7eSAndroid Build Coastguard Worker  }
4911*1208bc7eSAndroid Build Coastguard Worker
4912*1208bc7eSAndroid Build Coastguard Worker  # If "addr2line" isn't installed on the system at all, just use
4913*1208bc7eSAndroid Build Coastguard Worker  # nm to get what info we can (function names, but not line numbers).
4914*1208bc7eSAndroid Build Coastguard Worker  if (system(ShellEscape($addr2line, "--help") . " >$dev_null 2>&1") != 0) {
4915*1208bc7eSAndroid Build Coastguard Worker    MapSymbolsWithNM($image, $offset, $pclist, $symbols);
4916*1208bc7eSAndroid Build Coastguard Worker    return;
4917*1208bc7eSAndroid Build Coastguard Worker  }
4918*1208bc7eSAndroid Build Coastguard Worker
4919*1208bc7eSAndroid Build Coastguard Worker  # "addr2line -i" can produce a variable number of lines per input
4920*1208bc7eSAndroid Build Coastguard Worker  # address, with no separator that allows us to tell when data for
4921*1208bc7eSAndroid Build Coastguard Worker  # the next address starts.  So we find the address for a special
4922*1208bc7eSAndroid Build Coastguard Worker  # symbol (_fini) and interleave this address between all real
4923*1208bc7eSAndroid Build Coastguard Worker  # addresses passed to addr2line.  The name of this special symbol
4924*1208bc7eSAndroid Build Coastguard Worker  # can then be used as a separator.
4925*1208bc7eSAndroid Build Coastguard Worker  $sep_address = undef;  # May be filled in by MapSymbolsWithNM()
4926*1208bc7eSAndroid Build Coastguard Worker  my $nm_symbols = {};
4927*1208bc7eSAndroid Build Coastguard Worker  MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols);
4928*1208bc7eSAndroid Build Coastguard Worker  if (defined($sep_address)) {
4929*1208bc7eSAndroid Build Coastguard Worker    # Only add " -i" to addr2line if the binary supports it.
4930*1208bc7eSAndroid Build Coastguard Worker    # addr2line --help returns 0, but not if it sees an unknown flag first.
4931*1208bc7eSAndroid Build Coastguard Worker    if (system("$cmd -i --help >$dev_null 2>&1") == 0) {
4932*1208bc7eSAndroid Build Coastguard Worker      $cmd .= " -i";
4933*1208bc7eSAndroid Build Coastguard Worker    } else {
4934*1208bc7eSAndroid Build Coastguard Worker      $sep_address = undef;   # no need for sep_address if we don't support -i
4935*1208bc7eSAndroid Build Coastguard Worker    }
4936*1208bc7eSAndroid Build Coastguard Worker  }
4937*1208bc7eSAndroid Build Coastguard Worker
4938*1208bc7eSAndroid Build Coastguard Worker  # Make file with all PC values with intervening 'sep_address' so
4939*1208bc7eSAndroid Build Coastguard Worker  # that we can reliably detect the end of inlined function list
4940*1208bc7eSAndroid Build Coastguard Worker  open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n");
4941*1208bc7eSAndroid Build Coastguard Worker  if ($debug) { print("---- $image ---\n"); }
4942*1208bc7eSAndroid Build Coastguard Worker  for (my $i = 0; $i <= $#{$pclist}; $i++) {
4943*1208bc7eSAndroid Build Coastguard Worker    # addr2line always reads hex addresses, and does not need '0x' prefix.
4944*1208bc7eSAndroid Build Coastguard Worker    if ($debug) { printf STDERR ("%s\n", $pclist->[$i]); }
4945*1208bc7eSAndroid Build Coastguard Worker    printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
4946*1208bc7eSAndroid Build Coastguard Worker    if (defined($sep_address)) {
4947*1208bc7eSAndroid Build Coastguard Worker      printf ADDRESSES ("%s\n", $sep_address);
4948*1208bc7eSAndroid Build Coastguard Worker    }
4949*1208bc7eSAndroid Build Coastguard Worker  }
4950*1208bc7eSAndroid Build Coastguard Worker  close(ADDRESSES);
4951*1208bc7eSAndroid Build Coastguard Worker  if ($debug) {
4952*1208bc7eSAndroid Build Coastguard Worker    print("----\n");
4953*1208bc7eSAndroid Build Coastguard Worker    system("cat", $main::tmpfile_sym);
4954*1208bc7eSAndroid Build Coastguard Worker    print("----\n");
4955*1208bc7eSAndroid Build Coastguard Worker    system("$cmd < " . ShellEscape($main::tmpfile_sym));
4956*1208bc7eSAndroid Build Coastguard Worker    print("----\n");
4957*1208bc7eSAndroid Build Coastguard Worker  }
4958*1208bc7eSAndroid Build Coastguard Worker
4959*1208bc7eSAndroid Build Coastguard Worker  open(SYMBOLS, "$cmd <" . ShellEscape($main::tmpfile_sym) . " |")
4960*1208bc7eSAndroid Build Coastguard Worker      || error("$cmd: $!\n");
4961*1208bc7eSAndroid Build Coastguard Worker  my $count = 0;   # Index in pclist
4962*1208bc7eSAndroid Build Coastguard Worker  while (<SYMBOLS>) {
4963*1208bc7eSAndroid Build Coastguard Worker    # Read fullfunction and filelineinfo from next pair of lines
4964*1208bc7eSAndroid Build Coastguard Worker    s/\r?\n$//g;
4965*1208bc7eSAndroid Build Coastguard Worker    my $fullfunction = $_;
4966*1208bc7eSAndroid Build Coastguard Worker    $_ = <SYMBOLS>;
4967*1208bc7eSAndroid Build Coastguard Worker    s/\r?\n$//g;
4968*1208bc7eSAndroid Build Coastguard Worker    my $filelinenum = $_;
4969*1208bc7eSAndroid Build Coastguard Worker
4970*1208bc7eSAndroid Build Coastguard Worker    if (defined($sep_address) && $fullfunction eq $sep_symbol) {
4971*1208bc7eSAndroid Build Coastguard Worker      # Terminating marker for data for this address
4972*1208bc7eSAndroid Build Coastguard Worker      $count++;
4973*1208bc7eSAndroid Build Coastguard Worker      next;
4974*1208bc7eSAndroid Build Coastguard Worker    }
4975*1208bc7eSAndroid Build Coastguard Worker
4976*1208bc7eSAndroid Build Coastguard Worker    $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths
4977*1208bc7eSAndroid Build Coastguard Worker
4978*1208bc7eSAndroid Build Coastguard Worker    my $pcstr = $pclist->[$count];
4979*1208bc7eSAndroid Build Coastguard Worker    my $function = ShortFunctionName($fullfunction);
4980*1208bc7eSAndroid Build Coastguard Worker    my $nms = $nm_symbols->{$pcstr};
4981*1208bc7eSAndroid Build Coastguard Worker    if (defined($nms)) {
4982*1208bc7eSAndroid Build Coastguard Worker      if ($fullfunction eq '??') {
4983*1208bc7eSAndroid Build Coastguard Worker        # nm found a symbol for us.
4984*1208bc7eSAndroid Build Coastguard Worker        $function = $nms->[0];
4985*1208bc7eSAndroid Build Coastguard Worker        $fullfunction = $nms->[2];
4986*1208bc7eSAndroid Build Coastguard Worker      } else {
4987*1208bc7eSAndroid Build Coastguard Worker	# MapSymbolsWithNM tags each routine with its starting address,
4988*1208bc7eSAndroid Build Coastguard Worker	# useful in case the image has multiple occurrences of this
4989*1208bc7eSAndroid Build Coastguard Worker	# routine.  (It uses a syntax that resembles template paramters,
4990*1208bc7eSAndroid Build Coastguard Worker	# that are automatically stripped out by ShortFunctionName().)
4991*1208bc7eSAndroid Build Coastguard Worker	# addr2line does not provide the same information.  So we check
4992*1208bc7eSAndroid Build Coastguard Worker	# if nm disambiguated our symbol, and if so take the annotated
4993*1208bc7eSAndroid Build Coastguard Worker	# (nm) version of the routine-name.  TODO(csilvers): this won't
4994*1208bc7eSAndroid Build Coastguard Worker	# catch overloaded, inlined symbols, which nm doesn't see.
4995*1208bc7eSAndroid Build Coastguard Worker	# Better would be to do a check similar to nm's, in this fn.
4996*1208bc7eSAndroid Build Coastguard Worker	if ($nms->[2] =~ m/^\Q$function\E/) {  # sanity check it's the right fn
4997*1208bc7eSAndroid Build Coastguard Worker	  $function = $nms->[0];
4998*1208bc7eSAndroid Build Coastguard Worker	  $fullfunction = $nms->[2];
4999*1208bc7eSAndroid Build Coastguard Worker	}
5000*1208bc7eSAndroid Build Coastguard Worker      }
5001*1208bc7eSAndroid Build Coastguard Worker    }
5002*1208bc7eSAndroid Build Coastguard Worker
5003*1208bc7eSAndroid Build Coastguard Worker    # Prepend to accumulated symbols for pcstr
5004*1208bc7eSAndroid Build Coastguard Worker    # (so that caller comes before callee)
5005*1208bc7eSAndroid Build Coastguard Worker    my $sym = $symbols->{$pcstr};
5006*1208bc7eSAndroid Build Coastguard Worker    if (!defined($sym)) {
5007*1208bc7eSAndroid Build Coastguard Worker      $sym = [];
5008*1208bc7eSAndroid Build Coastguard Worker      $symbols->{$pcstr} = $sym;
5009*1208bc7eSAndroid Build Coastguard Worker    }
5010*1208bc7eSAndroid Build Coastguard Worker    unshift(@{$sym}, $function, $filelinenum, $fullfunction);
5011*1208bc7eSAndroid Build Coastguard Worker    if ($debug) { printf STDERR ("%s => [%s]\n", $pcstr, join(" ", @{$sym})); }
5012*1208bc7eSAndroid Build Coastguard Worker    if (!defined($sep_address)) {
5013*1208bc7eSAndroid Build Coastguard Worker      # Inlining is off, so this entry ends immediately
5014*1208bc7eSAndroid Build Coastguard Worker      $count++;
5015*1208bc7eSAndroid Build Coastguard Worker    }
5016*1208bc7eSAndroid Build Coastguard Worker  }
5017*1208bc7eSAndroid Build Coastguard Worker  close(SYMBOLS);
5018*1208bc7eSAndroid Build Coastguard Worker}
5019*1208bc7eSAndroid Build Coastguard Worker
5020*1208bc7eSAndroid Build Coastguard Worker# Use nm to map the list of referenced PCs to symbols.  Return true iff we
5021*1208bc7eSAndroid Build Coastguard Worker# are able to read procedure information via nm.
5022*1208bc7eSAndroid Build Coastguard Workersub MapSymbolsWithNM {
5023*1208bc7eSAndroid Build Coastguard Worker  my $image = shift;
5024*1208bc7eSAndroid Build Coastguard Worker  my $offset = shift;
5025*1208bc7eSAndroid Build Coastguard Worker  my $pclist = shift;
5026*1208bc7eSAndroid Build Coastguard Worker  my $symbols = shift;
5027*1208bc7eSAndroid Build Coastguard Worker
5028*1208bc7eSAndroid Build Coastguard Worker  # Get nm output sorted by increasing address
5029*1208bc7eSAndroid Build Coastguard Worker  my $symbol_table = GetProcedureBoundaries($image, ".");
5030*1208bc7eSAndroid Build Coastguard Worker  if (!%{$symbol_table}) {
5031*1208bc7eSAndroid Build Coastguard Worker    return 0;
5032*1208bc7eSAndroid Build Coastguard Worker  }
5033*1208bc7eSAndroid Build Coastguard Worker  # Start addresses are already the right length (8 or 16 hex digits).
5034*1208bc7eSAndroid Build Coastguard Worker  my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] }
5035*1208bc7eSAndroid Build Coastguard Worker    keys(%{$symbol_table});
5036*1208bc7eSAndroid Build Coastguard Worker
5037*1208bc7eSAndroid Build Coastguard Worker  if ($#names < 0) {
5038*1208bc7eSAndroid Build Coastguard Worker    # No symbols: just use addresses
5039*1208bc7eSAndroid Build Coastguard Worker    foreach my $pc (@{$pclist}) {
5040*1208bc7eSAndroid Build Coastguard Worker      my $pcstr = "0x" . $pc;
5041*1208bc7eSAndroid Build Coastguard Worker      $symbols->{$pc} = [$pcstr, "?", $pcstr];
5042*1208bc7eSAndroid Build Coastguard Worker    }
5043*1208bc7eSAndroid Build Coastguard Worker    return 0;
5044*1208bc7eSAndroid Build Coastguard Worker  }
5045*1208bc7eSAndroid Build Coastguard Worker
5046*1208bc7eSAndroid Build Coastguard Worker  # Sort addresses so we can do a join against nm output
5047*1208bc7eSAndroid Build Coastguard Worker  my $index = 0;
5048*1208bc7eSAndroid Build Coastguard Worker  my $fullname = $names[0];
5049*1208bc7eSAndroid Build Coastguard Worker  my $name = ShortFunctionName($fullname);
5050*1208bc7eSAndroid Build Coastguard Worker  foreach my $pc (sort { $a cmp $b } @{$pclist}) {
5051*1208bc7eSAndroid Build Coastguard Worker    # Adjust for mapped offset
5052*1208bc7eSAndroid Build Coastguard Worker    my $mpc = AddressSub($pc, $offset);
5053*1208bc7eSAndroid Build Coastguard Worker    while (($index < $#names) && ($mpc ge $symbol_table->{$fullname}->[1])){
5054*1208bc7eSAndroid Build Coastguard Worker      $index++;
5055*1208bc7eSAndroid Build Coastguard Worker      $fullname = $names[$index];
5056*1208bc7eSAndroid Build Coastguard Worker      $name = ShortFunctionName($fullname);
5057*1208bc7eSAndroid Build Coastguard Worker    }
5058*1208bc7eSAndroid Build Coastguard Worker    if ($mpc lt $symbol_table->{$fullname}->[1]) {
5059*1208bc7eSAndroid Build Coastguard Worker      $symbols->{$pc} = [$name, "?", $fullname];
5060*1208bc7eSAndroid Build Coastguard Worker    } else {
5061*1208bc7eSAndroid Build Coastguard Worker      my $pcstr = "0x" . $pc;
5062*1208bc7eSAndroid Build Coastguard Worker      $symbols->{$pc} = [$pcstr, "?", $pcstr];
5063*1208bc7eSAndroid Build Coastguard Worker    }
5064*1208bc7eSAndroid Build Coastguard Worker  }
5065*1208bc7eSAndroid Build Coastguard Worker  return 1;
5066*1208bc7eSAndroid Build Coastguard Worker}
5067*1208bc7eSAndroid Build Coastguard Worker
5068*1208bc7eSAndroid Build Coastguard Workersub ShortFunctionName {
5069*1208bc7eSAndroid Build Coastguard Worker  my $function = shift;
5070*1208bc7eSAndroid Build Coastguard Worker  while ($function =~ s/\([^()]*\)(\s*const)?//g) { }   # Argument types
5071*1208bc7eSAndroid Build Coastguard Worker  while ($function =~ s/<[^<>]*>//g)  { }    # Remove template arguments
5072*1208bc7eSAndroid Build Coastguard Worker  $function =~ s/^.*\s+(\w+::)/$1/;          # Remove leading type
5073*1208bc7eSAndroid Build Coastguard Worker  return $function;
5074*1208bc7eSAndroid Build Coastguard Worker}
5075*1208bc7eSAndroid Build Coastguard Worker
5076*1208bc7eSAndroid Build Coastguard Worker# Trim overly long symbols found in disassembler output
5077*1208bc7eSAndroid Build Coastguard Workersub CleanDisassembly {
5078*1208bc7eSAndroid Build Coastguard Worker  my $d = shift;
5079*1208bc7eSAndroid Build Coastguard Worker  while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
5080*1208bc7eSAndroid Build Coastguard Worker  while ($d =~ s/(\w+)<[^<>]*>/$1/g)  { }       # Remove template arguments
5081*1208bc7eSAndroid Build Coastguard Worker  return $d;
5082*1208bc7eSAndroid Build Coastguard Worker}
5083*1208bc7eSAndroid Build Coastguard Worker
5084*1208bc7eSAndroid Build Coastguard Worker# Clean file name for display
5085*1208bc7eSAndroid Build Coastguard Workersub CleanFileName {
5086*1208bc7eSAndroid Build Coastguard Worker  my ($f) = @_;
5087*1208bc7eSAndroid Build Coastguard Worker  $f =~ s|^/proc/self/cwd/||;
5088*1208bc7eSAndroid Build Coastguard Worker  $f =~ s|^\./||;
5089*1208bc7eSAndroid Build Coastguard Worker  return $f;
5090*1208bc7eSAndroid Build Coastguard Worker}
5091*1208bc7eSAndroid Build Coastguard Worker
5092*1208bc7eSAndroid Build Coastguard Worker# Make address relative to section and clean up for display
5093*1208bc7eSAndroid Build Coastguard Workersub UnparseAddress {
5094*1208bc7eSAndroid Build Coastguard Worker  my ($offset, $address) = @_;
5095*1208bc7eSAndroid Build Coastguard Worker  $address = AddressSub($address, $offset);
5096*1208bc7eSAndroid Build Coastguard Worker  $address =~ s/^0x//;
5097*1208bc7eSAndroid Build Coastguard Worker  $address =~ s/^0*//;
5098*1208bc7eSAndroid Build Coastguard Worker  return $address;
5099*1208bc7eSAndroid Build Coastguard Worker}
5100*1208bc7eSAndroid Build Coastguard Worker
5101*1208bc7eSAndroid Build Coastguard Worker##### Miscellaneous #####
5102*1208bc7eSAndroid Build Coastguard Worker
5103*1208bc7eSAndroid Build Coastguard Worker# Find the right versions of the above object tools to use.  The
5104*1208bc7eSAndroid Build Coastguard Worker# argument is the program file being analyzed, and should be an ELF
5105*1208bc7eSAndroid Build Coastguard Worker# 32-bit or ELF 64-bit executable file.  The location of the tools
5106*1208bc7eSAndroid Build Coastguard Worker# is determined by considering the following options in this order:
5107*1208bc7eSAndroid Build Coastguard Worker#   1) --tools option, if set
5108*1208bc7eSAndroid Build Coastguard Worker#   2) JEPROF_TOOLS environment variable, if set
5109*1208bc7eSAndroid Build Coastguard Worker#   3) the environment
5110*1208bc7eSAndroid Build Coastguard Workersub ConfigureObjTools {
5111*1208bc7eSAndroid Build Coastguard Worker  my $prog_file = shift;
5112*1208bc7eSAndroid Build Coastguard Worker
5113*1208bc7eSAndroid Build Coastguard Worker  # Check for the existence of $prog_file because /usr/bin/file does not
5114*1208bc7eSAndroid Build Coastguard Worker  # predictably return error status in prod.
5115*1208bc7eSAndroid Build Coastguard Worker  (-e $prog_file)  || error("$prog_file does not exist.\n");
5116*1208bc7eSAndroid Build Coastguard Worker
5117*1208bc7eSAndroid Build Coastguard Worker  my $file_type = undef;
5118*1208bc7eSAndroid Build Coastguard Worker  if (-e "/usr/bin/file") {
5119*1208bc7eSAndroid Build Coastguard Worker    # Follow symlinks (at least for systems where "file" supports that).
5120*1208bc7eSAndroid Build Coastguard Worker    my $escaped_prog_file = ShellEscape($prog_file);
5121*1208bc7eSAndroid Build Coastguard Worker    $file_type = `/usr/bin/file -L $escaped_prog_file 2>$dev_null ||
5122*1208bc7eSAndroid Build Coastguard Worker                  /usr/bin/file $escaped_prog_file`;
5123*1208bc7eSAndroid Build Coastguard Worker  } elsif ($^O == "MSWin32") {
5124*1208bc7eSAndroid Build Coastguard Worker    $file_type = "MS Windows";
5125*1208bc7eSAndroid Build Coastguard Worker  } else {
5126*1208bc7eSAndroid Build Coastguard Worker    print STDERR "WARNING: Can't determine the file type of $prog_file";
5127*1208bc7eSAndroid Build Coastguard Worker  }
5128*1208bc7eSAndroid Build Coastguard Worker
5129*1208bc7eSAndroid Build Coastguard Worker  if ($file_type =~ /64-bit/) {
5130*1208bc7eSAndroid Build Coastguard Worker    # Change $address_length to 16 if the program file is ELF 64-bit.
5131*1208bc7eSAndroid Build Coastguard Worker    # We can't detect this from many (most?) heap or lock contention
5132*1208bc7eSAndroid Build Coastguard Worker    # profiles, since the actual addresses referenced are generally in low
5133*1208bc7eSAndroid Build Coastguard Worker    # memory even for 64-bit programs.
5134*1208bc7eSAndroid Build Coastguard Worker    $address_length = 16;
5135*1208bc7eSAndroid Build Coastguard Worker  }
5136*1208bc7eSAndroid Build Coastguard Worker
5137*1208bc7eSAndroid Build Coastguard Worker  if ($file_type =~ /MS Windows/) {
5138*1208bc7eSAndroid Build Coastguard Worker    # For windows, we provide a version of nm and addr2line as part of
5139*1208bc7eSAndroid Build Coastguard Worker    # the opensource release, which is capable of parsing
5140*1208bc7eSAndroid Build Coastguard Worker    # Windows-style PDB executables.  It should live in the path, or
5141*1208bc7eSAndroid Build Coastguard Worker    # in the same directory as jeprof.
5142*1208bc7eSAndroid Build Coastguard Worker    $obj_tool_map{"nm_pdb"} = "nm-pdb";
5143*1208bc7eSAndroid Build Coastguard Worker    $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb";
5144*1208bc7eSAndroid Build Coastguard Worker  }
5145*1208bc7eSAndroid Build Coastguard Worker
5146*1208bc7eSAndroid Build Coastguard Worker  if ($file_type =~ /Mach-O/) {
5147*1208bc7eSAndroid Build Coastguard Worker    # OS X uses otool to examine Mach-O files, rather than objdump.
5148*1208bc7eSAndroid Build Coastguard Worker    $obj_tool_map{"otool"} = "otool";
5149*1208bc7eSAndroid Build Coastguard Worker    $obj_tool_map{"addr2line"} = "false";  # no addr2line
5150*1208bc7eSAndroid Build Coastguard Worker    $obj_tool_map{"objdump"} = "false";  # no objdump
5151*1208bc7eSAndroid Build Coastguard Worker  }
5152*1208bc7eSAndroid Build Coastguard Worker
5153*1208bc7eSAndroid Build Coastguard Worker  # Go fill in %obj_tool_map with the pathnames to use:
5154*1208bc7eSAndroid Build Coastguard Worker  foreach my $tool (keys %obj_tool_map) {
5155*1208bc7eSAndroid Build Coastguard Worker    $obj_tool_map{$tool} = ConfigureTool($obj_tool_map{$tool});
5156*1208bc7eSAndroid Build Coastguard Worker  }
5157*1208bc7eSAndroid Build Coastguard Worker}
5158*1208bc7eSAndroid Build Coastguard Worker
5159*1208bc7eSAndroid Build Coastguard Worker# Returns the path of a caller-specified object tool.  If --tools or
5160*1208bc7eSAndroid Build Coastguard Worker# JEPROF_TOOLS are specified, then returns the full path to the tool
5161*1208bc7eSAndroid Build Coastguard Worker# with that prefix.  Otherwise, returns the path unmodified (which
5162*1208bc7eSAndroid Build Coastguard Worker# means we will look for it on PATH).
5163*1208bc7eSAndroid Build Coastguard Workersub ConfigureTool {
5164*1208bc7eSAndroid Build Coastguard Worker  my $tool = shift;
5165*1208bc7eSAndroid Build Coastguard Worker  my $path;
5166*1208bc7eSAndroid Build Coastguard Worker
5167*1208bc7eSAndroid Build Coastguard Worker  # --tools (or $JEPROF_TOOLS) is a comma separated list, where each
5168*1208bc7eSAndroid Build Coastguard Worker  # item is either a) a pathname prefix, or b) a map of the form
5169*1208bc7eSAndroid Build Coastguard Worker  # <tool>:<path>.  First we look for an entry of type (b) for our
5170*1208bc7eSAndroid Build Coastguard Worker  # tool.  If one is found, we use it.  Otherwise, we consider all the
5171*1208bc7eSAndroid Build Coastguard Worker  # pathname prefixes in turn, until one yields an existing file.  If
5172*1208bc7eSAndroid Build Coastguard Worker  # none does, we use a default path.
5173*1208bc7eSAndroid Build Coastguard Worker  my $tools = $main::opt_tools || $ENV{"JEPROF_TOOLS"} || "";
5174*1208bc7eSAndroid Build Coastguard Worker  if ($tools =~ m/(,|^)\Q$tool\E:([^,]*)/) {
5175*1208bc7eSAndroid Build Coastguard Worker    $path = $2;
5176*1208bc7eSAndroid Build Coastguard Worker    # TODO(csilvers): sanity-check that $path exists?  Hard if it's relative.
5177*1208bc7eSAndroid Build Coastguard Worker  } elsif ($tools ne '') {
5178*1208bc7eSAndroid Build Coastguard Worker    foreach my $prefix (split(',', $tools)) {
5179*1208bc7eSAndroid Build Coastguard Worker      next if ($prefix =~ /:/);    # ignore "tool:fullpath" entries in the list
5180*1208bc7eSAndroid Build Coastguard Worker      if (-x $prefix . $tool) {
5181*1208bc7eSAndroid Build Coastguard Worker        $path = $prefix . $tool;
5182*1208bc7eSAndroid Build Coastguard Worker        last;
5183*1208bc7eSAndroid Build Coastguard Worker      }
5184*1208bc7eSAndroid Build Coastguard Worker    }
5185*1208bc7eSAndroid Build Coastguard Worker    if (!$path) {
5186*1208bc7eSAndroid Build Coastguard Worker      error("No '$tool' found with prefix specified by " .
5187*1208bc7eSAndroid Build Coastguard Worker            "--tools (or \$JEPROF_TOOLS) '$tools'\n");
5188*1208bc7eSAndroid Build Coastguard Worker    }
5189*1208bc7eSAndroid Build Coastguard Worker  } else {
5190*1208bc7eSAndroid Build Coastguard Worker    # ... otherwise use the version that exists in the same directory as
5191*1208bc7eSAndroid Build Coastguard Worker    # jeprof.  If there's nothing there, use $PATH.
5192*1208bc7eSAndroid Build Coastguard Worker    $0 =~ m,[^/]*$,;     # this is everything after the last slash
5193*1208bc7eSAndroid Build Coastguard Worker    my $dirname = $`;    # this is everything up to and including the last slash
5194*1208bc7eSAndroid Build Coastguard Worker    if (-x "$dirname$tool") {
5195*1208bc7eSAndroid Build Coastguard Worker      $path = "$dirname$tool";
5196*1208bc7eSAndroid Build Coastguard Worker    } else {
5197*1208bc7eSAndroid Build Coastguard Worker      $path = $tool;
5198*1208bc7eSAndroid Build Coastguard Worker    }
5199*1208bc7eSAndroid Build Coastguard Worker  }
5200*1208bc7eSAndroid Build Coastguard Worker  if ($main::opt_debug) { print STDERR "Using '$path' for '$tool'.\n"; }
5201*1208bc7eSAndroid Build Coastguard Worker  return $path;
5202*1208bc7eSAndroid Build Coastguard Worker}
5203*1208bc7eSAndroid Build Coastguard Worker
5204*1208bc7eSAndroid Build Coastguard Workersub ShellEscape {
5205*1208bc7eSAndroid Build Coastguard Worker  my @escaped_words = ();
5206*1208bc7eSAndroid Build Coastguard Worker  foreach my $word (@_) {
5207*1208bc7eSAndroid Build Coastguard Worker    my $escaped_word = $word;
5208*1208bc7eSAndroid Build Coastguard Worker    if ($word =~ m![^a-zA-Z0-9/.,_=-]!) {  # check for anything not in whitelist
5209*1208bc7eSAndroid Build Coastguard Worker      $escaped_word =~ s/'/'\\''/;
5210*1208bc7eSAndroid Build Coastguard Worker      $escaped_word = "'$escaped_word'";
5211*1208bc7eSAndroid Build Coastguard Worker    }
5212*1208bc7eSAndroid Build Coastguard Worker    push(@escaped_words, $escaped_word);
5213*1208bc7eSAndroid Build Coastguard Worker  }
5214*1208bc7eSAndroid Build Coastguard Worker  return join(" ", @escaped_words);
5215*1208bc7eSAndroid Build Coastguard Worker}
5216*1208bc7eSAndroid Build Coastguard Worker
5217*1208bc7eSAndroid Build Coastguard Workersub cleanup {
5218*1208bc7eSAndroid Build Coastguard Worker  unlink($main::tmpfile_sym);
5219*1208bc7eSAndroid Build Coastguard Worker  unlink(keys %main::tempnames);
5220*1208bc7eSAndroid Build Coastguard Worker
5221*1208bc7eSAndroid Build Coastguard Worker  # We leave any collected profiles in $HOME/jeprof in case the user wants
5222*1208bc7eSAndroid Build Coastguard Worker  # to look at them later.  We print a message informing them of this.
5223*1208bc7eSAndroid Build Coastguard Worker  if ((scalar(@main::profile_files) > 0) &&
5224*1208bc7eSAndroid Build Coastguard Worker      defined($main::collected_profile)) {
5225*1208bc7eSAndroid Build Coastguard Worker    if (scalar(@main::profile_files) == 1) {
5226*1208bc7eSAndroid Build Coastguard Worker      print STDERR "Dynamically gathered profile is in $main::collected_profile\n";
5227*1208bc7eSAndroid Build Coastguard Worker    }
5228*1208bc7eSAndroid Build Coastguard Worker    print STDERR "If you want to investigate this profile further, you can do:\n";
5229*1208bc7eSAndroid Build Coastguard Worker    print STDERR "\n";
5230*1208bc7eSAndroid Build Coastguard Worker    print STDERR "  jeprof \\\n";
5231*1208bc7eSAndroid Build Coastguard Worker    print STDERR "    $main::prog \\\n";
5232*1208bc7eSAndroid Build Coastguard Worker    print STDERR "    $main::collected_profile\n";
5233*1208bc7eSAndroid Build Coastguard Worker    print STDERR "\n";
5234*1208bc7eSAndroid Build Coastguard Worker  }
5235*1208bc7eSAndroid Build Coastguard Worker}
5236*1208bc7eSAndroid Build Coastguard Worker
5237*1208bc7eSAndroid Build Coastguard Workersub sighandler {
5238*1208bc7eSAndroid Build Coastguard Worker  cleanup();
5239*1208bc7eSAndroid Build Coastguard Worker  exit(1);
5240*1208bc7eSAndroid Build Coastguard Worker}
5241*1208bc7eSAndroid Build Coastguard Worker
5242*1208bc7eSAndroid Build Coastguard Workersub error {
5243*1208bc7eSAndroid Build Coastguard Worker  my $msg = shift;
5244*1208bc7eSAndroid Build Coastguard Worker  print STDERR $msg;
5245*1208bc7eSAndroid Build Coastguard Worker  cleanup();
5246*1208bc7eSAndroid Build Coastguard Worker  exit(1);
5247*1208bc7eSAndroid Build Coastguard Worker}
5248*1208bc7eSAndroid Build Coastguard Worker
5249*1208bc7eSAndroid Build Coastguard Worker
5250*1208bc7eSAndroid Build Coastguard Worker# Run $nm_command and get all the resulting procedure boundaries whose
5251*1208bc7eSAndroid Build Coastguard Worker# names match "$regexp" and returns them in a hashtable mapping from
5252*1208bc7eSAndroid Build Coastguard Worker# procedure name to a two-element vector of [start address, end address]
5253*1208bc7eSAndroid Build Coastguard Workersub GetProcedureBoundariesViaNm {
5254*1208bc7eSAndroid Build Coastguard Worker  my $escaped_nm_command = shift;    # shell-escaped
5255*1208bc7eSAndroid Build Coastguard Worker  my $regexp = shift;
5256*1208bc7eSAndroid Build Coastguard Worker
5257*1208bc7eSAndroid Build Coastguard Worker  my $symbol_table = {};
5258*1208bc7eSAndroid Build Coastguard Worker  open(NM, "$escaped_nm_command |") || error("$escaped_nm_command: $!\n");
5259*1208bc7eSAndroid Build Coastguard Worker  my $last_start = "0";
5260*1208bc7eSAndroid Build Coastguard Worker  my $routine = "";
5261*1208bc7eSAndroid Build Coastguard Worker  while (<NM>) {
5262*1208bc7eSAndroid Build Coastguard Worker    s/\r//g;         # turn windows-looking lines into unix-looking lines
5263*1208bc7eSAndroid Build Coastguard Worker    if (m/^\s*([0-9a-f]+) (.) (..*)/) {
5264*1208bc7eSAndroid Build Coastguard Worker      my $start_val = $1;
5265*1208bc7eSAndroid Build Coastguard Worker      my $type = $2;
5266*1208bc7eSAndroid Build Coastguard Worker      my $this_routine = $3;
5267*1208bc7eSAndroid Build Coastguard Worker
5268*1208bc7eSAndroid Build Coastguard Worker      # It's possible for two symbols to share the same address, if
5269*1208bc7eSAndroid Build Coastguard Worker      # one is a zero-length variable (like __start_google_malloc) or
5270*1208bc7eSAndroid Build Coastguard Worker      # one symbol is a weak alias to another (like __libc_malloc).
5271*1208bc7eSAndroid Build Coastguard Worker      # In such cases, we want to ignore all values except for the
5272*1208bc7eSAndroid Build Coastguard Worker      # actual symbol, which in nm-speak has type "T".  The logic
5273*1208bc7eSAndroid Build Coastguard Worker      # below does this, though it's a bit tricky: what happens when
5274*1208bc7eSAndroid Build Coastguard Worker      # we have a series of lines with the same address, is the first
5275*1208bc7eSAndroid Build Coastguard Worker      # one gets queued up to be processed.  However, it won't
5276*1208bc7eSAndroid Build Coastguard Worker      # *actually* be processed until later, when we read a line with
5277*1208bc7eSAndroid Build Coastguard Worker      # a different address.  That means that as long as we're reading
5278*1208bc7eSAndroid Build Coastguard Worker      # lines with the same address, we have a chance to replace that
5279*1208bc7eSAndroid Build Coastguard Worker      # item in the queue, which we do whenever we see a 'T' entry --
5280*1208bc7eSAndroid Build Coastguard Worker      # that is, a line with type 'T'.  If we never see a 'T' entry,
5281*1208bc7eSAndroid Build Coastguard Worker      # we'll just go ahead and process the first entry (which never
5282*1208bc7eSAndroid Build Coastguard Worker      # got touched in the queue), and ignore the others.
5283*1208bc7eSAndroid Build Coastguard Worker      if ($start_val eq $last_start && $type =~ /t/i) {
5284*1208bc7eSAndroid Build Coastguard Worker        # We are the 'T' symbol at this address, replace previous symbol.
5285*1208bc7eSAndroid Build Coastguard Worker        $routine = $this_routine;
5286*1208bc7eSAndroid Build Coastguard Worker        next;
5287*1208bc7eSAndroid Build Coastguard Worker      } elsif ($start_val eq $last_start) {
5288*1208bc7eSAndroid Build Coastguard Worker        # We're not the 'T' symbol at this address, so ignore us.
5289*1208bc7eSAndroid Build Coastguard Worker        next;
5290*1208bc7eSAndroid Build Coastguard Worker      }
5291*1208bc7eSAndroid Build Coastguard Worker
5292*1208bc7eSAndroid Build Coastguard Worker      if ($this_routine eq $sep_symbol) {
5293*1208bc7eSAndroid Build Coastguard Worker        $sep_address = HexExtend($start_val);
5294*1208bc7eSAndroid Build Coastguard Worker      }
5295*1208bc7eSAndroid Build Coastguard Worker
5296*1208bc7eSAndroid Build Coastguard Worker      # Tag this routine with the starting address in case the image
5297*1208bc7eSAndroid Build Coastguard Worker      # has multiple occurrences of this routine.  We use a syntax
5298*1208bc7eSAndroid Build Coastguard Worker      # that resembles template parameters that are automatically
5299*1208bc7eSAndroid Build Coastguard Worker      # stripped out by ShortFunctionName()
5300*1208bc7eSAndroid Build Coastguard Worker      $this_routine .= "<$start_val>";
5301*1208bc7eSAndroid Build Coastguard Worker
5302*1208bc7eSAndroid Build Coastguard Worker      if (defined($routine) && $routine =~ m/$regexp/) {
5303*1208bc7eSAndroid Build Coastguard Worker        $symbol_table->{$routine} = [HexExtend($last_start),
5304*1208bc7eSAndroid Build Coastguard Worker                                     HexExtend($start_val)];
5305*1208bc7eSAndroid Build Coastguard Worker      }
5306*1208bc7eSAndroid Build Coastguard Worker      $last_start = $start_val;
5307*1208bc7eSAndroid Build Coastguard Worker      $routine = $this_routine;
5308*1208bc7eSAndroid Build Coastguard Worker    } elsif (m/^Loaded image name: (.+)/) {
5309*1208bc7eSAndroid Build Coastguard Worker      # The win32 nm workalike emits information about the binary it is using.
5310*1208bc7eSAndroid Build Coastguard Worker      if ($main::opt_debug) { print STDERR "Using Image $1\n"; }
5311*1208bc7eSAndroid Build Coastguard Worker    } elsif (m/^PDB file name: (.+)/) {
5312*1208bc7eSAndroid Build Coastguard Worker      # The win32 nm workalike emits information about the pdb it is using.
5313*1208bc7eSAndroid Build Coastguard Worker      if ($main::opt_debug) { print STDERR "Using PDB $1\n"; }
5314*1208bc7eSAndroid Build Coastguard Worker    }
5315*1208bc7eSAndroid Build Coastguard Worker  }
5316*1208bc7eSAndroid Build Coastguard Worker  close(NM);
5317*1208bc7eSAndroid Build Coastguard Worker  # Handle the last line in the nm output.  Unfortunately, we don't know
5318*1208bc7eSAndroid Build Coastguard Worker  # how big this last symbol is, because we don't know how big the file
5319*1208bc7eSAndroid Build Coastguard Worker  # is.  For now, we just give it a size of 0.
5320*1208bc7eSAndroid Build Coastguard Worker  # TODO(csilvers): do better here.
5321*1208bc7eSAndroid Build Coastguard Worker  if (defined($routine) && $routine =~ m/$regexp/) {
5322*1208bc7eSAndroid Build Coastguard Worker    $symbol_table->{$routine} = [HexExtend($last_start),
5323*1208bc7eSAndroid Build Coastguard Worker                                 HexExtend($last_start)];
5324*1208bc7eSAndroid Build Coastguard Worker  }
5325*1208bc7eSAndroid Build Coastguard Worker  return $symbol_table;
5326*1208bc7eSAndroid Build Coastguard Worker}
5327*1208bc7eSAndroid Build Coastguard Worker
5328*1208bc7eSAndroid Build Coastguard Worker# Gets the procedure boundaries for all routines in "$image" whose names
5329*1208bc7eSAndroid Build Coastguard Worker# match "$regexp" and returns them in a hashtable mapping from procedure
5330*1208bc7eSAndroid Build Coastguard Worker# name to a two-element vector of [start address, end address].
5331*1208bc7eSAndroid Build Coastguard Worker# Will return an empty map if nm is not installed or not working properly.
5332*1208bc7eSAndroid Build Coastguard Workersub GetProcedureBoundaries {
5333*1208bc7eSAndroid Build Coastguard Worker  my $image = shift;
5334*1208bc7eSAndroid Build Coastguard Worker  my $regexp = shift;
5335*1208bc7eSAndroid Build Coastguard Worker
5336*1208bc7eSAndroid Build Coastguard Worker  # If $image doesn't start with /, then put ./ in front of it.  This works
5337*1208bc7eSAndroid Build Coastguard Worker  # around an obnoxious bug in our probing of nm -f behavior.
5338*1208bc7eSAndroid Build Coastguard Worker  # "nm -f $image" is supposed to fail on GNU nm, but if:
5339*1208bc7eSAndroid Build Coastguard Worker  #
5340*1208bc7eSAndroid Build Coastguard Worker  # a. $image starts with [BbSsPp] (for example, bin/foo/bar), AND
5341*1208bc7eSAndroid Build Coastguard Worker  # b. you have a.out in your current directory (a not uncommon occurence)
5342*1208bc7eSAndroid Build Coastguard Worker  #
5343*1208bc7eSAndroid Build Coastguard Worker  # then "nm -f $image" succeeds because -f only looks at the first letter of
5344*1208bc7eSAndroid Build Coastguard Worker  # the argument, which looks valid because it's [BbSsPp], and then since
5345*1208bc7eSAndroid Build Coastguard Worker  # there's no image provided, it looks for a.out and finds it.
5346*1208bc7eSAndroid Build Coastguard Worker  #
5347*1208bc7eSAndroid Build Coastguard Worker  # This regex makes sure that $image starts with . or /, forcing the -f
5348*1208bc7eSAndroid Build Coastguard Worker  # parsing to fail since . and / are not valid formats.
5349*1208bc7eSAndroid Build Coastguard Worker  $image =~ s#^[^/]#./$&#;
5350*1208bc7eSAndroid Build Coastguard Worker
5351*1208bc7eSAndroid Build Coastguard Worker  # For libc libraries, the copy in /usr/lib/debug contains debugging symbols
5352*1208bc7eSAndroid Build Coastguard Worker  my $debugging = DebuggingLibrary($image);
5353*1208bc7eSAndroid Build Coastguard Worker  if ($debugging) {
5354*1208bc7eSAndroid Build Coastguard Worker    $image = $debugging;
5355*1208bc7eSAndroid Build Coastguard Worker  }
5356*1208bc7eSAndroid Build Coastguard Worker
5357*1208bc7eSAndroid Build Coastguard Worker  my $nm = $obj_tool_map{"nm"};
5358*1208bc7eSAndroid Build Coastguard Worker  my $cppfilt = $obj_tool_map{"c++filt"};
5359*1208bc7eSAndroid Build Coastguard Worker
5360*1208bc7eSAndroid Build Coastguard Worker  # nm can fail for two reasons: 1) $image isn't a debug library; 2) nm
5361*1208bc7eSAndroid Build Coastguard Worker  # binary doesn't support --demangle.  In addition, for OS X we need
5362*1208bc7eSAndroid Build Coastguard Worker  # to use the -f flag to get 'flat' nm output (otherwise we don't sort
5363*1208bc7eSAndroid Build Coastguard Worker  # properly and get incorrect results).  Unfortunately, GNU nm uses -f
5364*1208bc7eSAndroid Build Coastguard Worker  # in an incompatible way.  So first we test whether our nm supports
5365*1208bc7eSAndroid Build Coastguard Worker  # --demangle and -f.
5366*1208bc7eSAndroid Build Coastguard Worker  my $demangle_flag = "";
5367*1208bc7eSAndroid Build Coastguard Worker  my $cppfilt_flag = "";
5368*1208bc7eSAndroid Build Coastguard Worker  my $to_devnull = ">$dev_null 2>&1";
5369*1208bc7eSAndroid Build Coastguard Worker  if (system(ShellEscape($nm, "--demangle", "image") . $to_devnull) == 0) {
5370*1208bc7eSAndroid Build Coastguard Worker    # In this mode, we do "nm --demangle <foo>"
5371*1208bc7eSAndroid Build Coastguard Worker    $demangle_flag = "--demangle";
5372*1208bc7eSAndroid Build Coastguard Worker    $cppfilt_flag = "";
5373*1208bc7eSAndroid Build Coastguard Worker  } elsif (system(ShellEscape($cppfilt, $image) . $to_devnull) == 0) {
5374*1208bc7eSAndroid Build Coastguard Worker    # In this mode, we do "nm <foo> | c++filt"
5375*1208bc7eSAndroid Build Coastguard Worker    $cppfilt_flag = " | " . ShellEscape($cppfilt);
5376*1208bc7eSAndroid Build Coastguard Worker  };
5377*1208bc7eSAndroid Build Coastguard Worker  my $flatten_flag = "";
5378*1208bc7eSAndroid Build Coastguard Worker  if (system(ShellEscape($nm, "-f", $image) . $to_devnull) == 0) {
5379*1208bc7eSAndroid Build Coastguard Worker    $flatten_flag = "-f";
5380*1208bc7eSAndroid Build Coastguard Worker  }
5381*1208bc7eSAndroid Build Coastguard Worker
5382*1208bc7eSAndroid Build Coastguard Worker  # Finally, in the case $imagie isn't a debug library, we try again with
5383*1208bc7eSAndroid Build Coastguard Worker  # -D to at least get *exported* symbols.  If we can't use --demangle,
5384*1208bc7eSAndroid Build Coastguard Worker  # we use c++filt instead, if it exists on this system.
5385*1208bc7eSAndroid Build Coastguard Worker  my @nm_commands = (ShellEscape($nm, "-n", $flatten_flag, $demangle_flag,
5386*1208bc7eSAndroid Build Coastguard Worker                                 $image) . " 2>$dev_null $cppfilt_flag",
5387*1208bc7eSAndroid Build Coastguard Worker                     ShellEscape($nm, "-D", "-n", $flatten_flag, $demangle_flag,
5388*1208bc7eSAndroid Build Coastguard Worker                                 $image) . " 2>$dev_null $cppfilt_flag",
5389*1208bc7eSAndroid Build Coastguard Worker                     # 6nm is for Go binaries
5390*1208bc7eSAndroid Build Coastguard Worker                     ShellEscape("6nm", "$image") . " 2>$dev_null | sort",
5391*1208bc7eSAndroid Build Coastguard Worker                     );
5392*1208bc7eSAndroid Build Coastguard Worker
5393*1208bc7eSAndroid Build Coastguard Worker  # If the executable is an MS Windows PDB-format executable, we'll
5394*1208bc7eSAndroid Build Coastguard Worker  # have set up obj_tool_map("nm_pdb").  In this case, we actually
5395*1208bc7eSAndroid Build Coastguard Worker  # want to use both unix nm and windows-specific nm_pdb, since
5396*1208bc7eSAndroid Build Coastguard Worker  # PDB-format executables can apparently include dwarf .o files.
5397*1208bc7eSAndroid Build Coastguard Worker  if (exists $obj_tool_map{"nm_pdb"}) {
5398*1208bc7eSAndroid Build Coastguard Worker    push(@nm_commands,
5399*1208bc7eSAndroid Build Coastguard Worker         ShellEscape($obj_tool_map{"nm_pdb"}, "--demangle", $image)
5400*1208bc7eSAndroid Build Coastguard Worker         . " 2>$dev_null");
5401*1208bc7eSAndroid Build Coastguard Worker  }
5402*1208bc7eSAndroid Build Coastguard Worker
5403*1208bc7eSAndroid Build Coastguard Worker  foreach my $nm_command (@nm_commands) {
5404*1208bc7eSAndroid Build Coastguard Worker    my $symbol_table = GetProcedureBoundariesViaNm($nm_command, $regexp);
5405*1208bc7eSAndroid Build Coastguard Worker    return $symbol_table if (%{$symbol_table});
5406*1208bc7eSAndroid Build Coastguard Worker  }
5407*1208bc7eSAndroid Build Coastguard Worker  my $symbol_table = {};
5408*1208bc7eSAndroid Build Coastguard Worker  return $symbol_table;
5409*1208bc7eSAndroid Build Coastguard Worker}
5410*1208bc7eSAndroid Build Coastguard Worker
5411*1208bc7eSAndroid Build Coastguard Worker
5412*1208bc7eSAndroid Build Coastguard Worker# The test vectors for AddressAdd/Sub/Inc are 8-16-nibble hex strings.
5413*1208bc7eSAndroid Build Coastguard Worker# To make them more readable, we add underscores at interesting places.
5414*1208bc7eSAndroid Build Coastguard Worker# This routine removes the underscores, producing the canonical representation
5415*1208bc7eSAndroid Build Coastguard Worker# used by jeprof to represent addresses, particularly in the tested routines.
5416*1208bc7eSAndroid Build Coastguard Workersub CanonicalHex {
5417*1208bc7eSAndroid Build Coastguard Worker  my $arg = shift;
5418*1208bc7eSAndroid Build Coastguard Worker  return join '', (split '_',$arg);
5419*1208bc7eSAndroid Build Coastguard Worker}
5420*1208bc7eSAndroid Build Coastguard Worker
5421*1208bc7eSAndroid Build Coastguard Worker
5422*1208bc7eSAndroid Build Coastguard Worker# Unit test for AddressAdd:
5423*1208bc7eSAndroid Build Coastguard Workersub AddressAddUnitTest {
5424*1208bc7eSAndroid Build Coastguard Worker  my $test_data_8 = shift;
5425*1208bc7eSAndroid Build Coastguard Worker  my $test_data_16 = shift;
5426*1208bc7eSAndroid Build Coastguard Worker  my $error_count = 0;
5427*1208bc7eSAndroid Build Coastguard Worker  my $fail_count = 0;
5428*1208bc7eSAndroid Build Coastguard Worker  my $pass_count = 0;
5429*1208bc7eSAndroid Build Coastguard Worker  # print STDERR "AddressAddUnitTest: ", 1+$#{$test_data_8}, " tests\n";
5430*1208bc7eSAndroid Build Coastguard Worker
5431*1208bc7eSAndroid Build Coastguard Worker  # First a few 8-nibble addresses.  Note that this implementation uses
5432*1208bc7eSAndroid Build Coastguard Worker  # plain old arithmetic, so a quick sanity check along with verifying what
5433*1208bc7eSAndroid Build Coastguard Worker  # happens to overflow (we want it to wrap):
5434*1208bc7eSAndroid Build Coastguard Worker  $address_length = 8;
5435*1208bc7eSAndroid Build Coastguard Worker  foreach my $row (@{$test_data_8}) {
5436*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
5437*1208bc7eSAndroid Build Coastguard Worker    my $sum = AddressAdd ($row->[0], $row->[1]);
5438*1208bc7eSAndroid Build Coastguard Worker    if ($sum ne $row->[2]) {
5439*1208bc7eSAndroid Build Coastguard Worker      printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
5440*1208bc7eSAndroid Build Coastguard Worker             $row->[0], $row->[1], $row->[2];
5441*1208bc7eSAndroid Build Coastguard Worker      ++$fail_count;
5442*1208bc7eSAndroid Build Coastguard Worker    } else {
5443*1208bc7eSAndroid Build Coastguard Worker      ++$pass_count;
5444*1208bc7eSAndroid Build Coastguard Worker    }
5445*1208bc7eSAndroid Build Coastguard Worker  }
5446*1208bc7eSAndroid Build Coastguard Worker  printf STDERR "AddressAdd 32-bit tests: %d passes, %d failures\n",
5447*1208bc7eSAndroid Build Coastguard Worker         $pass_count, $fail_count;
5448*1208bc7eSAndroid Build Coastguard Worker  $error_count = $fail_count;
5449*1208bc7eSAndroid Build Coastguard Worker  $fail_count = 0;
5450*1208bc7eSAndroid Build Coastguard Worker  $pass_count = 0;
5451*1208bc7eSAndroid Build Coastguard Worker
5452*1208bc7eSAndroid Build Coastguard Worker  # Now 16-nibble addresses.
5453*1208bc7eSAndroid Build Coastguard Worker  $address_length = 16;
5454*1208bc7eSAndroid Build Coastguard Worker  foreach my $row (@{$test_data_16}) {
5455*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
5456*1208bc7eSAndroid Build Coastguard Worker    my $sum = AddressAdd (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
5457*1208bc7eSAndroid Build Coastguard Worker    my $expected = join '', (split '_',$row->[2]);
5458*1208bc7eSAndroid Build Coastguard Worker    if ($sum ne CanonicalHex($row->[2])) {
5459*1208bc7eSAndroid Build Coastguard Worker      printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
5460*1208bc7eSAndroid Build Coastguard Worker             $row->[0], $row->[1], $row->[2];
5461*1208bc7eSAndroid Build Coastguard Worker      ++$fail_count;
5462*1208bc7eSAndroid Build Coastguard Worker    } else {
5463*1208bc7eSAndroid Build Coastguard Worker      ++$pass_count;
5464*1208bc7eSAndroid Build Coastguard Worker    }
5465*1208bc7eSAndroid Build Coastguard Worker  }
5466*1208bc7eSAndroid Build Coastguard Worker  printf STDERR "AddressAdd 64-bit tests: %d passes, %d failures\n",
5467*1208bc7eSAndroid Build Coastguard Worker         $pass_count, $fail_count;
5468*1208bc7eSAndroid Build Coastguard Worker  $error_count += $fail_count;
5469*1208bc7eSAndroid Build Coastguard Worker
5470*1208bc7eSAndroid Build Coastguard Worker  return $error_count;
5471*1208bc7eSAndroid Build Coastguard Worker}
5472*1208bc7eSAndroid Build Coastguard Worker
5473*1208bc7eSAndroid Build Coastguard Worker
5474*1208bc7eSAndroid Build Coastguard Worker# Unit test for AddressSub:
5475*1208bc7eSAndroid Build Coastguard Workersub AddressSubUnitTest {
5476*1208bc7eSAndroid Build Coastguard Worker  my $test_data_8 = shift;
5477*1208bc7eSAndroid Build Coastguard Worker  my $test_data_16 = shift;
5478*1208bc7eSAndroid Build Coastguard Worker  my $error_count = 0;
5479*1208bc7eSAndroid Build Coastguard Worker  my $fail_count = 0;
5480*1208bc7eSAndroid Build Coastguard Worker  my $pass_count = 0;
5481*1208bc7eSAndroid Build Coastguard Worker  # print STDERR "AddressSubUnitTest: ", 1+$#{$test_data_8}, " tests\n";
5482*1208bc7eSAndroid Build Coastguard Worker
5483*1208bc7eSAndroid Build Coastguard Worker  # First a few 8-nibble addresses.  Note that this implementation uses
5484*1208bc7eSAndroid Build Coastguard Worker  # plain old arithmetic, so a quick sanity check along with verifying what
5485*1208bc7eSAndroid Build Coastguard Worker  # happens to overflow (we want it to wrap):
5486*1208bc7eSAndroid Build Coastguard Worker  $address_length = 8;
5487*1208bc7eSAndroid Build Coastguard Worker  foreach my $row (@{$test_data_8}) {
5488*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
5489*1208bc7eSAndroid Build Coastguard Worker    my $sum = AddressSub ($row->[0], $row->[1]);
5490*1208bc7eSAndroid Build Coastguard Worker    if ($sum ne $row->[3]) {
5491*1208bc7eSAndroid Build Coastguard Worker      printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
5492*1208bc7eSAndroid Build Coastguard Worker             $row->[0], $row->[1], $row->[3];
5493*1208bc7eSAndroid Build Coastguard Worker      ++$fail_count;
5494*1208bc7eSAndroid Build Coastguard Worker    } else {
5495*1208bc7eSAndroid Build Coastguard Worker      ++$pass_count;
5496*1208bc7eSAndroid Build Coastguard Worker    }
5497*1208bc7eSAndroid Build Coastguard Worker  }
5498*1208bc7eSAndroid Build Coastguard Worker  printf STDERR "AddressSub 32-bit tests: %d passes, %d failures\n",
5499*1208bc7eSAndroid Build Coastguard Worker         $pass_count, $fail_count;
5500*1208bc7eSAndroid Build Coastguard Worker  $error_count = $fail_count;
5501*1208bc7eSAndroid Build Coastguard Worker  $fail_count = 0;
5502*1208bc7eSAndroid Build Coastguard Worker  $pass_count = 0;
5503*1208bc7eSAndroid Build Coastguard Worker
5504*1208bc7eSAndroid Build Coastguard Worker  # Now 16-nibble addresses.
5505*1208bc7eSAndroid Build Coastguard Worker  $address_length = 16;
5506*1208bc7eSAndroid Build Coastguard Worker  foreach my $row (@{$test_data_16}) {
5507*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
5508*1208bc7eSAndroid Build Coastguard Worker    my $sum = AddressSub (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
5509*1208bc7eSAndroid Build Coastguard Worker    if ($sum ne CanonicalHex($row->[3])) {
5510*1208bc7eSAndroid Build Coastguard Worker      printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
5511*1208bc7eSAndroid Build Coastguard Worker             $row->[0], $row->[1], $row->[3];
5512*1208bc7eSAndroid Build Coastguard Worker      ++$fail_count;
5513*1208bc7eSAndroid Build Coastguard Worker    } else {
5514*1208bc7eSAndroid Build Coastguard Worker      ++$pass_count;
5515*1208bc7eSAndroid Build Coastguard Worker    }
5516*1208bc7eSAndroid Build Coastguard Worker  }
5517*1208bc7eSAndroid Build Coastguard Worker  printf STDERR "AddressSub 64-bit tests: %d passes, %d failures\n",
5518*1208bc7eSAndroid Build Coastguard Worker         $pass_count, $fail_count;
5519*1208bc7eSAndroid Build Coastguard Worker  $error_count += $fail_count;
5520*1208bc7eSAndroid Build Coastguard Worker
5521*1208bc7eSAndroid Build Coastguard Worker  return $error_count;
5522*1208bc7eSAndroid Build Coastguard Worker}
5523*1208bc7eSAndroid Build Coastguard Worker
5524*1208bc7eSAndroid Build Coastguard Worker
5525*1208bc7eSAndroid Build Coastguard Worker# Unit test for AddressInc:
5526*1208bc7eSAndroid Build Coastguard Workersub AddressIncUnitTest {
5527*1208bc7eSAndroid Build Coastguard Worker  my $test_data_8 = shift;
5528*1208bc7eSAndroid Build Coastguard Worker  my $test_data_16 = shift;
5529*1208bc7eSAndroid Build Coastguard Worker  my $error_count = 0;
5530*1208bc7eSAndroid Build Coastguard Worker  my $fail_count = 0;
5531*1208bc7eSAndroid Build Coastguard Worker  my $pass_count = 0;
5532*1208bc7eSAndroid Build Coastguard Worker  # print STDERR "AddressIncUnitTest: ", 1+$#{$test_data_8}, " tests\n";
5533*1208bc7eSAndroid Build Coastguard Worker
5534*1208bc7eSAndroid Build Coastguard Worker  # First a few 8-nibble addresses.  Note that this implementation uses
5535*1208bc7eSAndroid Build Coastguard Worker  # plain old arithmetic, so a quick sanity check along with verifying what
5536*1208bc7eSAndroid Build Coastguard Worker  # happens to overflow (we want it to wrap):
5537*1208bc7eSAndroid Build Coastguard Worker  $address_length = 8;
5538*1208bc7eSAndroid Build Coastguard Worker  foreach my $row (@{$test_data_8}) {
5539*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
5540*1208bc7eSAndroid Build Coastguard Worker    my $sum = AddressInc ($row->[0]);
5541*1208bc7eSAndroid Build Coastguard Worker    if ($sum ne $row->[4]) {
5542*1208bc7eSAndroid Build Coastguard Worker      printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
5543*1208bc7eSAndroid Build Coastguard Worker             $row->[0], $row->[4];
5544*1208bc7eSAndroid Build Coastguard Worker      ++$fail_count;
5545*1208bc7eSAndroid Build Coastguard Worker    } else {
5546*1208bc7eSAndroid Build Coastguard Worker      ++$pass_count;
5547*1208bc7eSAndroid Build Coastguard Worker    }
5548*1208bc7eSAndroid Build Coastguard Worker  }
5549*1208bc7eSAndroid Build Coastguard Worker  printf STDERR "AddressInc 32-bit tests: %d passes, %d failures\n",
5550*1208bc7eSAndroid Build Coastguard Worker         $pass_count, $fail_count;
5551*1208bc7eSAndroid Build Coastguard Worker  $error_count = $fail_count;
5552*1208bc7eSAndroid Build Coastguard Worker  $fail_count = 0;
5553*1208bc7eSAndroid Build Coastguard Worker  $pass_count = 0;
5554*1208bc7eSAndroid Build Coastguard Worker
5555*1208bc7eSAndroid Build Coastguard Worker  # Now 16-nibble addresses.
5556*1208bc7eSAndroid Build Coastguard Worker  $address_length = 16;
5557*1208bc7eSAndroid Build Coastguard Worker  foreach my $row (@{$test_data_16}) {
5558*1208bc7eSAndroid Build Coastguard Worker    if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
5559*1208bc7eSAndroid Build Coastguard Worker    my $sum = AddressInc (CanonicalHex($row->[0]));
5560*1208bc7eSAndroid Build Coastguard Worker    if ($sum ne CanonicalHex($row->[4])) {
5561*1208bc7eSAndroid Build Coastguard Worker      printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
5562*1208bc7eSAndroid Build Coastguard Worker             $row->[0], $row->[4];
5563*1208bc7eSAndroid Build Coastguard Worker      ++$fail_count;
5564*1208bc7eSAndroid Build Coastguard Worker    } else {
5565*1208bc7eSAndroid Build Coastguard Worker      ++$pass_count;
5566*1208bc7eSAndroid Build Coastguard Worker    }
5567*1208bc7eSAndroid Build Coastguard Worker  }
5568*1208bc7eSAndroid Build Coastguard Worker  printf STDERR "AddressInc 64-bit tests: %d passes, %d failures\n",
5569*1208bc7eSAndroid Build Coastguard Worker         $pass_count, $fail_count;
5570*1208bc7eSAndroid Build Coastguard Worker  $error_count += $fail_count;
5571*1208bc7eSAndroid Build Coastguard Worker
5572*1208bc7eSAndroid Build Coastguard Worker  return $error_count;
5573*1208bc7eSAndroid Build Coastguard Worker}
5574*1208bc7eSAndroid Build Coastguard Worker
5575*1208bc7eSAndroid Build Coastguard Worker
5576*1208bc7eSAndroid Build Coastguard Worker# Driver for unit tests.
5577*1208bc7eSAndroid Build Coastguard Worker# Currently just the address add/subtract/increment routines for 64-bit.
5578*1208bc7eSAndroid Build Coastguard Workersub RunUnitTests {
5579*1208bc7eSAndroid Build Coastguard Worker  my $error_count = 0;
5580*1208bc7eSAndroid Build Coastguard Worker
5581*1208bc7eSAndroid Build Coastguard Worker  # This is a list of tuples [a, b, a+b, a-b, a+1]
5582*1208bc7eSAndroid Build Coastguard Worker  my $unit_test_data_8 = [
5583*1208bc7eSAndroid Build Coastguard Worker    [qw(aaaaaaaa 50505050 fafafafa 5a5a5a5a aaaaaaab)],
5584*1208bc7eSAndroid Build Coastguard Worker    [qw(50505050 aaaaaaaa fafafafa a5a5a5a6 50505051)],
5585*1208bc7eSAndroid Build Coastguard Worker    [qw(ffffffff aaaaaaaa aaaaaaa9 55555555 00000000)],
5586*1208bc7eSAndroid Build Coastguard Worker    [qw(00000001 ffffffff 00000000 00000002 00000002)],
5587*1208bc7eSAndroid Build Coastguard Worker    [qw(00000001 fffffff0 fffffff1 00000011 00000002)],
5588*1208bc7eSAndroid Build Coastguard Worker  ];
5589*1208bc7eSAndroid Build Coastguard Worker  my $unit_test_data_16 = [
5590*1208bc7eSAndroid Build Coastguard Worker    # The implementation handles data in 7-nibble chunks, so those are the
5591*1208bc7eSAndroid Build Coastguard Worker    # interesting boundaries.
5592*1208bc7eSAndroid Build Coastguard Worker    [qw(aaaaaaaa 50505050
5593*1208bc7eSAndroid Build Coastguard Worker        00_000000f_afafafa 00_0000005_a5a5a5a 00_000000a_aaaaaab)],
5594*1208bc7eSAndroid Build Coastguard Worker    [qw(50505050 aaaaaaaa
5595*1208bc7eSAndroid Build Coastguard Worker        00_000000f_afafafa ff_ffffffa_5a5a5a6 00_0000005_0505051)],
5596*1208bc7eSAndroid Build Coastguard Worker    [qw(ffffffff aaaaaaaa
5597*1208bc7eSAndroid Build Coastguard Worker        00_000001a_aaaaaa9 00_0000005_5555555 00_0000010_0000000)],
5598*1208bc7eSAndroid Build Coastguard Worker    [qw(00000001 ffffffff
5599*1208bc7eSAndroid Build Coastguard Worker        00_0000010_0000000 ff_ffffff0_0000002 00_0000000_0000002)],
5600*1208bc7eSAndroid Build Coastguard Worker    [qw(00000001 fffffff0
5601*1208bc7eSAndroid Build Coastguard Worker        00_000000f_ffffff1 ff_ffffff0_0000011 00_0000000_0000002)],
5602*1208bc7eSAndroid Build Coastguard Worker
5603*1208bc7eSAndroid Build Coastguard Worker    [qw(00_a00000a_aaaaaaa 50505050
5604*1208bc7eSAndroid Build Coastguard Worker        00_a00000f_afafafa 00_a000005_a5a5a5a 00_a00000a_aaaaaab)],
5605*1208bc7eSAndroid Build Coastguard Worker    [qw(0f_fff0005_0505050 aaaaaaaa
5606*1208bc7eSAndroid Build Coastguard Worker        0f_fff000f_afafafa 0f_ffefffa_5a5a5a6 0f_fff0005_0505051)],
5607*1208bc7eSAndroid Build Coastguard Worker    [qw(00_000000f_fffffff 01_800000a_aaaaaaa
5608*1208bc7eSAndroid Build Coastguard Worker        01_800001a_aaaaaa9 fe_8000005_5555555 00_0000010_0000000)],
5609*1208bc7eSAndroid Build Coastguard Worker    [qw(00_0000000_0000001 ff_fffffff_fffffff
5610*1208bc7eSAndroid Build Coastguard Worker        00_0000000_0000000 00_0000000_0000002 00_0000000_0000002)],
5611*1208bc7eSAndroid Build Coastguard Worker    [qw(00_0000000_0000001 ff_fffffff_ffffff0
5612*1208bc7eSAndroid Build Coastguard Worker        ff_fffffff_ffffff1 00_0000000_0000011 00_0000000_0000002)],
5613*1208bc7eSAndroid Build Coastguard Worker  ];
5614*1208bc7eSAndroid Build Coastguard Worker
5615*1208bc7eSAndroid Build Coastguard Worker  $error_count += AddressAddUnitTest($unit_test_data_8, $unit_test_data_16);
5616*1208bc7eSAndroid Build Coastguard Worker  $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16);
5617*1208bc7eSAndroid Build Coastguard Worker  $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16);
5618*1208bc7eSAndroid Build Coastguard Worker  if ($error_count > 0) {
5619*1208bc7eSAndroid Build Coastguard Worker    print STDERR $error_count, " errors: FAILED\n";
5620*1208bc7eSAndroid Build Coastguard Worker  } else {
5621*1208bc7eSAndroid Build Coastguard Worker    print STDERR "PASS\n";
5622*1208bc7eSAndroid Build Coastguard Worker  }
5623*1208bc7eSAndroid Build Coastguard Worker  exit ($error_count);
5624*1208bc7eSAndroid Build Coastguard Worker}
5625