82
82
my $PPROF_VERSION = "1.5";
84
# NOTE: All mentions of c++filt have been expunged from this script
85
# because (1) we don't use C++, and (2) the copy of c++filt that ships
86
# on OS X is from 2007 and destroys nm output by "demangling" the
87
# first two columns (address and symbol type).
84
89
# These are the object tools we use which can come from a
85
90
# user-specified location using --tools, from the PPROF_TOOLS
86
91
# environment variable, or from the environment.
88
93
"objdump" => "objdump",
90
95
"addr2line" => "addr2line",
91
"c++filt" => "c++filt",
92
96
## ConfigureObjTools may add architecture-specific entries:
93
97
#"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables
94
98
#"addr2line_pdb" => "addr2line-pdb", # ditto
634
638
# (only matters when --heapcheck is given but we must be
635
639
# compatible with old branches that did not pass --heapcheck always):
636
640
if ($total != 0) {
637
printf("Total: %s %s\n", Unparse($total), Units());
641
Infof("Total: %s %s\n", Unparse($total), Units());
639
643
PrintText($symbols, $flat, $cumulative, $total, -1);
640
644
} elsif ($main::opt_raw) {
931
933
if ($focus ne '') {
932
934
$profile = FocusProfile($symbols, $profile, $focus);
933
935
my $focus_count = TotalProfile($profile);
934
printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
936
Infof("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
936
938
Unparse($focus_count), Units(),
937
939
Unparse($total_count), ($focus_count*100.0) / $total_count);
939
941
if ($ignore ne '') {
940
942
$profile = IgnoreProfile($symbols, $profile, $ignore);
941
943
my $ignore_count = TotalProfile($profile);
942
printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
944
Infof("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
944
946
Unparse($ignore_count), Units(),
945
947
Unparse($total_count),
2972
2985
sub IsProfileURL {
2973
2986
my $profile_name = shift;
2974
my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
2987
my ($scheme, $host, $port, $prefix, $path) = ParseProfileURL($profile_name);
2975
2988
return defined($host) and defined($port) and defined($path);
2978
2991
sub ParseProfileURL {
2979
2992
my $profile_name = shift;
2980
2993
if (defined($profile_name) &&
2981
$profile_name =~ m,^(http://|)([^/:]+):(\d+)(|\@\d+)(|/|(.*?)($PROFILE_PAGE|$PMUPROFILE_PAGE|$HEAP_PAGE|$GROWTH_PAGE|$THREAD_PAGE|$CONTENTION_PAGE|$WALL_PAGE|$FILTEREDPROFILE_PAGE))$,o) {
2994
$profile_name =~ m,^(?:(https?)://|)([^/:]+):(\d+)(|\@\d+)(|/|(.*?)($PROFILE_PAGE|$PMUPROFILE_PAGE|$HEAP_PAGE|$GROWTH_PAGE|$THREAD_PAGE|$CONTENTION_PAGE|$WALL_PAGE|$FILTEREDPROFILE_PAGE))$,o) {
2982
2995
# $7 is $PROFILE_PAGE/$HEAP_PAGE/etc. $5 is *everything* after
2983
2996
# the hostname, as long as that everything is the empty string,
2984
2997
# a slash, or something ending in $PROFILE_PAGE/$HEAP_PAGE/etc.
2985
2998
# So "$7 || $5" is $PROFILE_PAGE/etc if there, or else it's "/" or "".
2986
return ($2, $3, $6, $7 || $5);
2999
return ($1 || "http", $2, $3, $6, $7 || $5);
2991
3004
# We fetch symbols from the first profile argument.
2992
3005
sub SymbolPageURL {
2993
my ($host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
2994
return "http://$host:$port$prefix$SYMBOL_PAGE";
3006
my ($scheme, $host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
3007
return "$scheme://$host:$port$prefix$SYMBOL_PAGE";
2997
3010
sub FetchProgramName() {
2998
my ($host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
2999
my $url = "http://$host:$port$prefix$PROGRAM_NAME_PAGE";
3011
my ($scheme, $host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
3012
my $url = "$scheme://$host:$port$prefix$PROGRAM_NAME_PAGE";
3000
3013
my $command_line = "$CURL -s '$url'";
3001
3014
open(CMDLINE, "$command_line |") or error($command_line);
3002
3015
my $cmdline = <CMDLINE>;
3084
3097
my $url = SymbolPageURL();
3085
3098
$url = ResolveRedirectionForCurl($url);
3086
3099
my $command_line = "$CURL -sd '\@$main::tmpfile_sym' '$url'";
3087
# We use c++filt in case $SYMBOL_PAGE gives us mangled symbols.
3088
my $cppfilt = $obj_tool_map{"c++filt"};
3089
open(SYMBOL, "$command_line | $cppfilt |") or error($command_line);
3100
open(SYMBOL, "$command_line |") or error($command_line);
3090
3101
ReadSymbols(*SYMBOL{IO}, $symbol_map);
3129
3140
sub MakeProfileBaseName {
3130
3141
my ($binary_name, $profile_name) = @_;
3131
my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
3142
my ($scheme, $host, $port, $prefix, $path) = ParseProfileURL($profile_name);
3132
3143
my $binary_shortname = BaseName($binary_name);
3133
3144
return sprintf("%s.%s.%s-port%s",
3134
3145
$binary_shortname, $main::op_time, $host, $port);
3143
3154
if (!IsProfileURL($profile_name)) {
3144
3155
return $profile_name;
3146
my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
3157
my ($scheme, $host, $port, $prefix, $path) = ParseProfileURL($profile_name);
3147
3158
if ($path eq "" || $path eq "/") {
3148
3159
# Missing type specifier defaults to cpu-profile
3149
3160
$path = $PROFILE_PAGE;
3155
3166
my $curl_timeout;
3156
3167
if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)) {
3157
3168
if ($path =~ m/$PROFILE_PAGE/) {
3158
$url = sprintf("http://$host:$port$prefix$path?seconds=%d",
3169
$url = sprintf("$scheme://$host:$port$prefix$path?seconds=%d",
3159
3170
$main::opt_seconds);
3161
3172
if ($profile_name =~ m/[?]/) {
3203
3214
(system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n");
3215
open(TMPPROF, "$tmp_profile") || error("Cannot open $tmp_profile: $!\n");
3216
my $line = <TMPPROF>;
3218
$line !~ /^Could not enable CPU profiling/ || error($line);
3204
3219
(system("mv $tmp_profile $real_profile") == 0) || error("Unable to rename profile\n");
3205
3220
print STDERR "Wrote profile to $real_profile\n";
3206
3221
$main::collected_profile = $real_profile;
4398
4417
$cmd = "$addr2line --demangle -f -C -e $image";
4401
if (system("$addr2line --help >/dev/null 2>&1") != 0) {
4402
# addr2line must not exist. Fall back to go tool addr2line.
4403
$addr2line = "go tool addr2line";
4404
$cmd = "$addr2line $image";
4420
# Use the go version because we know it works on all platforms
4421
$addr2line = "go tool addr2line";
4422
$cmd = "$addr2line $image";
4407
4424
# If "addr2line" isn't installed on the system at all, just use
4408
4425
# nm to get what info we can (function names, but not line numbers).
4781
4798
# in an incompatible way. So first we test whether our nm supports
4782
4799
# --demangle and -f.
4783
4800
my $demangle_flag = "";
4784
my $cppfilt_flag = "";
4785
4801
if (system("$nm --demangle $image >/dev/null 2>&1") == 0) {
4786
4802
# In this mode, we do "nm --demangle <foo>"
4787
4803
$demangle_flag = "--demangle";
4789
} elsif (system("$cppfilt $image >/dev/null 2>&1") == 0) {
4790
# In this mode, we do "nm <foo> | c++filt"
4791
$cppfilt_flag = " | $cppfilt";
4793
4805
my $flatten_flag = "";
4794
4806
if (system("$nm -f $image >/dev/null 2>&1") == 0) {
4795
4807
$flatten_flag = "-f";
4798
# Finally, in the case $imagie isn't a debug library, we try again with
4799
# -D to at least get *exported* symbols. If we can't use --demangle,
4800
# we use c++filt instead, if it exists on this system.
4810
# Finally, in the case $image isn't a debug library, we try again with
4811
# -D to at least get *exported* symbols. If we can't use --demangle, too bad.
4801
4812
my @nm_commands = ("$nm -n $flatten_flag $demangle_flag" .
4802
" $image 2>/dev/null $cppfilt_flag",
4813
" $image 2>/dev/null",
4803
4814
"$nm -D -n $flatten_flag $demangle_flag" .
4804
" $image 2>/dev/null $cppfilt_flag",
4805
# 6nm is for Go binaries
4806
"6nm $image 2>/dev/null | sort");
4815
" $image 2>/dev/null",
4816
# go tool nm is for Go binaries
4817
"go tool nm $image 2>/dev/null | sort");
4808
# If the executable is an MS Windows PDB-format executable, we'll
4809
# have set up obj_tool_map("nm_pdb"). In this case, we actually
4810
# want to use both unix nm and windows-specific nm_pdb, since
4811
# PDB-format executables can apparently include dwarf .o files.
4812
if (exists $obj_tool_map{"nm_pdb"}) {
4813
my $nm_pdb = $obj_tool_map{"nm_pdb"};
4814
push(@nm_commands, "$nm_pdb --demangle $image 2>/dev/null");
4819
# If the executable is an MS Windows Go executable, we'll
4820
# have set up obj_tool_map("is_windows").
4821
if (exists $obj_tool_map{"is_windows"}) {
4822
@nm_commands = ("go tool nm $image 2>/dev/null | sort");
4817
4825
foreach my $nm_command (@nm_commands) {