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