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/&/&/g; 1560*1208bc7eSAndroid Build Coastguard Worker $text =~ s/</</g; 1561*1208bc7eSAndroid Build Coastguard Worker $text =~ s/>/>/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