Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(586)

Side by Side Diff: third_party/tcmalloc/chromium/src/pprof

Issue 576001: Merged third_party/tcmalloc/vendor/src(google-perftools r87) into... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Removed the unnecessary printf and ASSERT(0) Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 #! /usr/bin/env perl 1 #! /usr/bin/env perl
2 2
3 # Copyright (c) 1998-2007, Google Inc. 3 # Copyright (c) 1998-2007, Google Inc.
4 # All rights reserved. 4 # All rights reserved.
5 # 5 #
6 # Redistribution and use in source and binary forms, with or without 6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are 7 # modification, are permitted provided that the following conditions are
8 # met: 8 # met:
9 # 9 #
10 # * Redistributions of source code must retain the above copyright 10 # * Redistributions of source code must retain the above copyright
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 # Generates disassembly listing of all routines with at least one 65 # Generates disassembly listing of all routines with at least one
66 # sample that match the --disasm=<regexp> pattern. The listing is 66 # sample that match the --disasm=<regexp> pattern. The listing is
67 # annotated with the flat and cumulative sample counts at each PC value. 67 # annotated with the flat and cumulative sample counts at each PC value.
68 # 68 #
69 # TODO: Use color to indicate files? 69 # TODO: Use color to indicate files?
70 70
71 use strict; 71 use strict;
72 use warnings; 72 use warnings;
73 use Getopt::Long; 73 use Getopt::Long;
74 74
75 my $PPROF_VERSION = "1.4"; 75 my $PPROF_VERSION = "1.5";
76 76
77 # These are the object tools we use which can come from a 77 # These are the object tools we use which can come from a
78 # user-specified location using --tools, from the PPROF_TOOLS 78 # user-specified location using --tools, from the PPROF_TOOLS
79 # environment variable, or from the environment. 79 # environment variable, or from the environment.
80 my %obj_tool_map = ( 80 my %obj_tool_map = (
81 "objdump" => "objdump", 81 "objdump" => "objdump",
82 "nm" => "nm", 82 "nm" => "nm",
83 "addr2line" => "addr2line", 83 "addr2line" => "addr2line",
84 "c++filt" => "c++filt", 84 "c++filt" => "c++filt",
85 ## ConfigureObjTools may add architecture-specific entries: 85 ## ConfigureObjTools may add architecture-specific entries:
86 #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables 86 #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables
87 #"addr2line_pdb" => "addr2line-pdb", # ditto 87 #"addr2line_pdb" => "addr2line-pdb", # ditto
88 #"otool" => "otool", # equivalent of objdump on OS X 88 #"otool" => "otool", # equivalent of objdump on OS X
89 ); 89 );
90 my $DOT = "dot"; # leave non-absolute, since it may be in /usr/local 90 my $DOT = "dot"; # leave non-absolute, since it may be in /usr/local
91 my $GV = "gv"; 91 my $GV = "gv";
92 my $PS2PDF = "ps2pdf"; 92 my $PS2PDF = "ps2pdf";
93 # These are used for dynamic profiles 93 # These are used for dynamic profiles
94 my $WGET = "wget"; 94 my $WGET = "wget";
95 my $WGET_FLAGS = "--no-http-keep-alive"; # only supported by some wgets
95 my $CURL = "curl"; 96 my $CURL = "curl";
96 97
97 # These are the web pages that servers need to support for dynamic profiles 98 # These are the web pages that servers need to support for dynamic profiles
98 my $HEAP_PAGE = "/pprof/heap"; 99 my $HEAP_PAGE = "/pprof/heap";
99 my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#" 100 my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#"
100 my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param 101 my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param
101 # ?seconds=#&event=x&period=n 102 # ?seconds=#&event=x&period=n
102 my $GROWTH_PAGE = "/pprof/growth"; 103 my $GROWTH_PAGE = "/pprof/growth";
103 my $CONTENTION_PAGE = "/pprof/contention"; 104 my $CONTENTION_PAGE = "/pprof/contention";
104 my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter 105 my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter
105 my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?"; 106 my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?";
106 my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST 107 my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST
107 my $PROGRAM_NAME_PAGE = "/pprof/cmdline"; 108 my $PROGRAM_NAME_PAGE = "/pprof/cmdline";
108 109
109 # default binary name 110 # default binary name
110 my $UNKNOWN_BINARY = "(unknown)"; 111 my $UNKNOWN_BINARY = "(unknown)";
111 112
112 # There is a pervasive dependency on the length (in hex characters, 113 # There is a pervasive dependency on the length (in hex characters,
113 # i.e., nibbles) of an address, distinguishing between 32-bit and 114 # i.e., nibbles) of an address, distinguishing between 32-bit and
114 # 64-bit profiles. To err on the safe size, default to 64-bit here: 115 # 64-bit profiles. To err on the safe size, default to 64-bit here:
115 my $address_length = 16; 116 my $address_length = 16;
116 117
117 # A list of paths to search for shared object files 118 # A list of paths to search for shared object files
118 my @prefix_list = (); 119 my @prefix_list = ();
119 120
121 # Special routine name that should not have any symbols.
122 # Used as separator to parse "addr2line -i" output.
123 my $sep_symbol = '_fini';
124 my $sep_address = undef;
125
120 ##### Argument parsing ##### 126 ##### Argument parsing #####
121 127
122 sub usage_string { 128 sub usage_string {
123 return <<EOF; 129 return <<EOF;
124 Usage: 130 Usage:
125 pprof [options] <program> <profiles> 131 pprof [options] <program> <profiles>
126 <profiles> is a space separated list of profile names. 132 <profiles> is a space separated list of profile names.
127 pprof [options] <symbolized-profiles> 133 pprof [options] <symbolized-profiles>
128 <symbolized-profiles> is a list of profile files where each file contains 134 <symbolized-profiles> is a list of profile files where each file contains
129 the necessary symbol mappings as well as profile data (likely generated 135 the necessary symbol mappings as well as profile data (likely generated
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 if ($main::use_symbol_page) { 503 if ($main::use_symbol_page) {
498 unless (IsProfileURL($main::pfile_args[0])) { 504 unless (IsProfileURL($main::pfile_args[0])) {
499 error("The first profile should be a remote form to use $SYMBOL_PAGE\n"); 505 error("The first profile should be a remote form to use $SYMBOL_PAGE\n");
500 } 506 }
501 CheckSymbolPage(); 507 CheckSymbolPage();
502 $main::prog = FetchProgramName(); 508 $main::prog = FetchProgramName();
503 } elsif (!$main::use_symbolized_profile) { # may not need objtools! 509 } elsif (!$main::use_symbolized_profile) { # may not need objtools!
504 ConfigureObjTools($main::prog) 510 ConfigureObjTools($main::prog)
505 } 511 }
506 512
513 # Check what flags our commandline utilities support
514 if (open(TFILE, "$WGET $WGET_FLAGS -V 2>&1 |")) {
515 my @lines = <TFILE>;
516 if (grep(/unrecognized/, @lines) > 0) {
517 # grep found 'unrecognized' token from WGET, clear WGET flags
518 $WGET_FLAGS = "";
519 }
520 close(TFILE);
521 }
522 # TODO(csilvers): check all the other binaries and objtools to see
523 # if they are installed and what flags they support, and store that
524 # in a data structure here, rather than scattering these tests about.
525 # Then, ideally, rewrite code to use wget OR curl OR GET or ...
526
507 # Break the opt_list_prefix into the prefix_list array 527 # Break the opt_list_prefix into the prefix_list array
508 @prefix_list = split (',', $main::opt_lib_prefix); 528 @prefix_list = split (',', $main::opt_lib_prefix);
509 529
510 # Remove trailing / from the prefixes, in the list to prevent 530 # Remove trailing / from the prefixes, in the list to prevent
511 # searching things like /my/path//lib/mylib.so 531 # searching things like /my/path//lib/mylib.so
512 foreach (@prefix_list) { 532 foreach (@prefix_list) {
513 s|/+$||; 533 s|/+$||;
514 } 534 }
515 } 535 }
516 536
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 my $prog = shift; 965 my $prog = shift;
946 966
947 $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash 967 $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
948 my $symbol_marker = $&; 968 my $symbol_marker = $&;
949 969
950 print '--- ', $symbol_marker, "\n"; 970 print '--- ', $symbol_marker, "\n";
951 if (defined($prog)) { 971 if (defined($prog)) {
952 print 'binary=', $prog, "\n"; 972 print 'binary=', $prog, "\n";
953 } 973 }
954 while (my ($pc, $name) = each(%{$symbols})) { 974 while (my ($pc, $name) = each(%{$symbols})) {
955 my $fullname = $name->[2]; 975 my $sep = ' ';
956 print '0x', $pc, ' ', $fullname, "\n"; 976 print '0x', $pc;
977 # We have a list of function names, which include the inlined
978 # calls. They are separated (and terminated) by --, which is
979 # illegal in function names.
980 for (my $j = 2; $j <= $#{$name}; $j += 3) {
981 print $sep, $name->[$j];
982 $sep = '--';
983 }
984 print "\n";
957 } 985 }
958 print '---', "\n"; 986 print '---', "\n";
959 987
988 $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
989 my $profile_marker = $&;
990 print '--- ', $profile_marker, "\n";
960 if (defined($main::collected_profile)) { 991 if (defined($main::collected_profile)) {
961 # if used with remote fetch, simply dump the collected profile to output. 992 # if used with remote fetch, simply dump the collected profile to output.
962 open(SRC, "<$main::collected_profile"); 993 open(SRC, "<$main::collected_profile");
963 while (<SRC>) { 994 while (<SRC>) {
964 print $_; 995 print $_;
965 } 996 }
997 close(SRC);
966 } else { 998 } else {
967 # dump a cpu-format profile to standard out 999 # dump a cpu-format profile to standard out
968 $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
969 my $profile_marker = $&;
970 print '--- ', $profile_marker, "\n";
971 PrintProfileData($profile); 1000 PrintProfileData($profile);
972 } 1001 }
973 } 1002 }
974 1003
975 # Print text output 1004 # Print text output
976 sub PrintText { 1005 sub PrintText {
977 my $symbols = shift; 1006 my $symbols = shift;
978 my $flat = shift; 1007 my $flat = shift;
979 my $cumulative = shift; 1008 my $cumulative = shift;
980 my $total = shift; 1009 my $total = shift;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1062 $start_addr, $end_addr, $total); 1091 $start_addr, $end_addr, $total);
1063 last; 1092 last;
1064 } 1093 }
1065 $addr = AddressInc($addr); 1094 $addr = AddressInc($addr);
1066 } 1095 }
1067 } 1096 }
1068 } 1097 }
1069 } 1098 }
1070 1099
1071 # Return reference to array of tuples of the form: 1100 # Return reference to array of tuples of the form:
1072 # [address, filename, linenumber, instruction] 1101 # [start_address, filename, linenumber, instruction, limit_address]
1073 # E.g., 1102 # E.g.,
1074 # ["0x806c43d", "/foo/bar.cc", 131, "ret"] 1103 # ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"]
1075 sub Disassemble { 1104 sub Disassemble {
1076 my $prog = shift; 1105 my $prog = shift;
1077 my $offset = shift; 1106 my $offset = shift;
1078 my $start_addr = shift; 1107 my $start_addr = shift;
1079 my $end_addr = shift; 1108 my $end_addr = shift;
1080 1109
1081 my $objdump = $obj_tool_map{"objdump"}; 1110 my $objdump = $obj_tool_map{"objdump"};
1082 my $cmd = sprintf("$objdump -C -d -l --no-show-raw-insn " . 1111 my $cmd = sprintf("$objdump -C -d -l --no-show-raw-insn " .
1083 "--start-address=0x$start_addr " . 1112 "--start-address=0x$start_addr " .
1084 "--stop-address=0x$end_addr $prog"); 1113 "--stop-address=0x$end_addr $prog");
1085 open(OBJDUMP, "$cmd |") || error("$objdump: $!\n"); 1114 open(OBJDUMP, "$cmd |") || error("$objdump: $!\n");
1086 my @result = (); 1115 my @result = ();
1087 my $filename = ""; 1116 my $filename = "";
1088 my $linenumber = -1; 1117 my $linenumber = -1;
1118 my $last = ["", "", "", ""];
1089 while (<OBJDUMP>) { 1119 while (<OBJDUMP>) {
1090 s/\r//g; # turn windows-looking lines into unix-looking lines 1120 s/\r//g; # turn windows-looking lines into unix-looking lines
1091 chop; 1121 chop;
1092 if (m|\s*([^:\s]+):(\d+)\s*$|) { 1122 if (m|\s*([^:\s]+):(\d+)\s*$|) {
1093 # Location line of the form: 1123 # Location line of the form:
1094 # <filename>:<linenumber> 1124 # <filename>:<linenumber>
1095 $filename = $1; 1125 $filename = $1;
1096 $linenumber = $2; 1126 $linenumber = $2;
1097 } elsif (m/^ +([0-9a-f]+):\s*(.*)/) { 1127 } elsif (m/^ +([0-9a-f]+):\s*(.*)/) {
1098 # Disassembly line -- zero-extend address to full length 1128 # Disassembly line -- zero-extend address to full length
1099 my $addr = HexExtend($1); 1129 my $addr = HexExtend($1);
1100 my $k = AddressAdd($addr, $offset); 1130 my $k = AddressAdd($addr, $offset);
1101 push(@result, [$k, $filename, $linenumber, $2]); 1131 $last->[4] = $k; # Store ending address for previous instruction
1132 $last = [$k, $filename, $linenumber, $2, $end_addr];
1133 push(@result, $last);
1102 } 1134 }
1103 } 1135 }
1104 close(OBJDUMP); 1136 close(OBJDUMP);
1105 return @result; 1137 return @result;
1106 } 1138 }
1107 1139
1108 # The input file should contain lines of the form /proc/maps-like 1140 # The input file should contain lines of the form /proc/maps-like
1109 # output (same format as expected from the profiles) or that looks 1141 # output (same format as expected from the profiles) or that looks
1110 # like hex addresses (like "0xDEADBEEF"). We will parse all 1142 # like hex addresses (like "0xDEADBEEF"). We will parse all
1111 # /proc/maps output, and for all the hex addresses, we will output 1143 # /proc/maps output, and for all the hex addresses, we will output
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
1267 # Assign all samples to the range $firstline,$lastline, 1299 # Assign all samples to the range $firstline,$lastline,
1268 # Hack 4: If an instruction does not occur in the range, its samples 1300 # Hack 4: If an instruction does not occur in the range, its samples
1269 # are moved to the next instruction that occurs in the range. 1301 # are moved to the next instruction that occurs in the range.
1270 my $samples1 = {}; 1302 my $samples1 = {};
1271 my $samples2 = {}; 1303 my $samples2 = {};
1272 my $running1 = 0; # Unassigned flat counts 1304 my $running1 = 0; # Unassigned flat counts
1273 my $running2 = 0; # Unassigned cumulative counts 1305 my $running2 = 0; # Unassigned cumulative counts
1274 my $total1 = 0; # Total flat counts 1306 my $total1 = 0; # Total flat counts
1275 my $total2 = 0; # Total cumulative counts 1307 my $total2 = 0; # Total cumulative counts
1276 foreach my $e (@instructions) { 1308 foreach my $e (@instructions) {
1277 my $c1 = GetEntry($flat, $e->[0]); 1309 # Add up counts for all address that fall inside this instruction
1278 my $c2 = GetEntry($cumulative, $e->[0]); 1310 my $c1 = 0;
1311 my $c2 = 0;
1312 for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
1313 $c1 += GetEntry($flat, $a);
1314 $c2 += GetEntry($cumulative, $a);
1315 }
1279 $running1 += $c1; 1316 $running1 += $c1;
1280 $running2 += $c2; 1317 $running2 += $c2;
1281 $total1 += $c1; 1318 $total1 += $c1;
1282 $total2 += $c2; 1319 $total2 += $c2;
1283 my $file = $e->[1]; 1320 my $file = $e->[1];
1284 my $line = $e->[2]; 1321 my $line = $e->[2];
1285 if (($file eq $filename) && 1322 if (($file eq $filename) &&
1286 ($line >= $firstline) && 1323 ($line >= $firstline) &&
1287 ($line <= $lastline)) { 1324 ($line <= $lastline)) {
1288 # Assign all accumulated samples to this line 1325 # Assign all accumulated samples to this line
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
1379 1416
1380 # Disassemble all instructions 1417 # Disassemble all instructions
1381 my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr); 1418 my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
1382 1419
1383 # Make array of counts per instruction 1420 # Make array of counts per instruction
1384 my @flat_count = (); 1421 my @flat_count = ();
1385 my @cum_count = (); 1422 my @cum_count = ();
1386 my $flat_total = 0; 1423 my $flat_total = 0;
1387 my $cum_total = 0; 1424 my $cum_total = 0;
1388 foreach my $e (@instructions) { 1425 foreach my $e (@instructions) {
1389 my $c1 = GetEntry($flat, $e->[0]); 1426 # Add up counts for all address that fall inside this instruction
1390 my $c2 = GetEntry($cumulative, $e->[0]); 1427 my $c1 = 0;
1428 my $c2 = 0;
1429 for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
1430 $c1 += GetEntry($flat, $a);
1431 $c2 += GetEntry($cumulative, $a);
1432 }
1391 push(@flat_count, $c1); 1433 push(@flat_count, $c1);
1392 push(@cum_count, $c2); 1434 push(@cum_count, $c2);
1393 $flat_total += $c1; 1435 $flat_total += $c1;
1394 $cum_total += $c2; 1436 $cum_total += $c2;
1395 } 1437 }
1396 1438
1397 # Print header with total counts 1439 # Print header with total counts
1398 printf("ROUTINE ====================== %s\n" . 1440 printf("ROUTINE ====================== %s\n" .
1399 "%6s %6s %s (flat, cumulative) %.1f%% of total\n", 1441 "%6s %6s %s (flat, cumulative) %.1f%% of total\n",
1400 ShortFunctionName($routine), 1442 ShortFunctionName($routine),
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
1608 $style, 1650 $style,
1609 ); 1651 );
1610 } 1652 }
1611 1653
1612 # Get edges and counts per edge 1654 # Get edges and counts per edge
1613 my %edge = (); 1655 my %edge = ();
1614 my $n; 1656 my $n;
1615 foreach my $k (keys(%{$raw})) { 1657 foreach my $k (keys(%{$raw})) {
1616 # TODO: omit low %age edges 1658 # TODO: omit low %age edges
1617 $n = $raw->{$k}; 1659 $n = $raw->{$k};
1618 my @addrs = split(/\n/, $k); 1660 my @translated = TranslateStack($symbols, $k);
1619 for (my $i = 1; $i <= $#addrs; $i++) { 1661 for (my $i = 1; $i <= $#translated; $i++) {
1620 my $src = OutputKey($symbols, $addrs[$i]); 1662 my $src = $translated[$i];
1621 my $dst = OutputKey($symbols, $addrs[$i-1]); 1663 my $dst = $translated[$i-1];
1622 #next if ($src eq $dst); # Avoid self-edges? 1664 #next if ($src eq $dst); # Avoid self-edges?
1623 if (exists($node{$src}) && exists($node{$dst})) { 1665 if (exists($node{$src}) && exists($node{$dst})) {
1624 my $edge_label = "$src\001$dst"; 1666 my $edge_label = "$src\001$dst";
1625 if (!exists($edge{$edge_label})) { 1667 if (!exists($edge{$edge_label})) {
1626 $edge{$edge_label} = 0; 1668 $edge{$edge_label} = 0;
1627 } 1669 }
1628 $edge{$edge_label} += $n; 1670 $edge{$edge_label} += $n;
1629 } 1671 }
1630 } 1672 }
1631 } 1673 }
1632 1674
1633 # Print edges 1675 # Print edges
1634 foreach my $e (keys(%edge)) { 1676 foreach my $e (keys(%edge)) {
1635 my @x = split(/\001/, $e); 1677 my @x = split(/\001/, $e);
1636 $n = $edge{$e}; 1678 $n = $edge{$e};
1637 1679
1638 if (abs($n) > $edgelimit) { 1680 if (abs($n) > $edgelimit) {
1639 # Compute line width based on edge count 1681 # Compute line width based on edge count
1640 my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0); 1682 my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0);
1641 if ($fraction > 1) { $fraction = 1; } 1683 if ($fraction > 1) { $fraction = 1; }
1642 my $w = $fraction * 2; 1684 my $w = $fraction * 2;
1643 #if ($w < 1) { $w = 1; } 1685 #if ($w < 1) { $w = 1; }
1644 1686
1645 # Dot sometimes segfaults if given edge weights that are too large, so 1687 # Dot sometimes segfaults if given edge weights that are too large, so
1646 # we cap the weights at a large value 1688 # we cap the weights at a large value
1647 my $edgeweight = abs($n) ** 0.7; 1689 my $edgeweight = abs($n) ** 0.7;
1648 if ($edgeweight > 100000) { $edgeweight = 100000; } 1690 if ($edgeweight > 100000) { $edgeweight = 100000; }
1649 $edgeweight = int($edgeweight); 1691 $edgeweight = int($edgeweight);
1650 1692
1693 my $style = sprintf("setlinewidth(%f)", $w);
1694 if ($x[1] =~ m/\(inline\)/) {
1695 $style .= ",dashed";
1696 }
1697
1651 # Use a slightly squashed function of the edge count as the weight 1698 # Use a slightly squashed function of the edge count as the weight
1652 printf DOT ("N%s -> N%s [label=%s, weight=%d, " . 1699 printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n",
1653 "style=\"setlinewidth(%f)\"];\n",
1654 $node{$x[0]}, 1700 $node{$x[0]},
1655 $node{$x[1]}, 1701 $node{$x[1]},
1656 Unparse($n), 1702 Unparse($n),
1657 $edgeweight, 1703 $edgeweight,
1658 $w); 1704 $style);
1659 } 1705 }
1660 } 1706 }
1661 1707
1662 print DOT ("}\n"); 1708 print DOT ("}\n");
1663 1709
1664 close(DOT); 1710 close(DOT);
1665 return 1; 1711 return 1;
1666 } 1712 }
1667 1713
1668 # Generate the key under which a given address should be counted 1714 # Translate a stack of addresses into a stack of symbols
1669 # based on the user-specified output granularity. 1715 sub TranslateStack {
1670 sub OutputKey {
1671 my $symbols = shift; 1716 my $symbols = shift;
1672 my $a = shift; 1717 my $k = shift;
1673 1718
1674 # Skip large addresses since they sometimes show up as fake entries on RH9 1719 my @addrs = split(/\n/, $k);
1675 if (length($a) > 8) { 1720 my @result = ();
1676 if ($a gt "7fffffffffffffff") { return ''; } 1721 for (my $i = 0; $i <= $#addrs; $i++) {
1722 my $a = $addrs[$i];
1723
1724 # Skip large addresses since they sometimes show up as fake entries on RH9
1725 if (length($a) > 8 && $a gt "7fffffffffffffff") {
1726 next;
1727 }
1728
1729 if ($main::opt_disasm || $main::opt_list) {
1730 # We want just the address for the key
1731 push(@result, $a);
1732 next;
1733 }
1734
1735 my $symlist = $symbols->{$a};
1736 if (!defined($symlist)) {
1737 $symlist = [$a, "", $a];
1738 }
1739
1740 # We can have a sequence of symbols for a particular entry
1741 # (more than one symbol in the case of inlining). Callers
1742 # come before callees in symlist, so walk backwards since
1743 # the translated stack should contain callees before callers.
1744 for (my $j = $#{$symlist}; $j >= 2; $j -= 3) {
1745 my $func = $symlist->[$j-2];
1746 my $fileline = $symlist->[$j-1];
1747 my $fullfunc = $symlist->[$j];
1748 if ($j > 2) {
1749 $func = "$func (inline)";
1750 }
1751 if ($main::opt_addresses) {
1752 push(@result, "$a $func $fileline");
1753 } elsif ($main::opt_lines) {
1754 if ($func eq '??' && $fileline eq '??:0') {
1755 push(@result, "$a");
1756 } else {
1757 push(@result, "$func $fileline");
1758 }
1759 } elsif ($main::opt_functions) {
1760 if ($func eq '??') {
1761 push(@result, "$a");
1762 } else {
1763 push(@result, $func);
1764 }
1765 } elsif ($main::opt_files) {
1766 if ($fileline eq '??:0' || $fileline eq '') {
1767 push(@result, "$a");
1768 } else {
1769 my $f = $fileline;
1770 $f =~ s/:\d+$//;
1771 push(@result, $f);
1772 }
1773 } else {
1774 push(@result, $a);
1775 last; # Do not print inlined info
1776 }
1777 }
1677 } 1778 }
1678 1779
1679 # Extract symbolic info for address 1780 # print join(",", @addrs), " => ", join(",", @result), "\n";
1680 my $func = $a; 1781 return @result;
1681 my $fullfunc = $a;
1682 my $fileline = "";
1683 if (exists($symbols->{$a})) {
1684 $func = $symbols->{$a}->[0];
1685 $fullfunc = $symbols->{$a}->[2];
1686 $fileline = $symbols->{$a}->[1];
1687 }
1688
1689 if ($main::opt_disasm || $main::opt_list) {
1690 return $a; # We want just the address for the key
1691 } elsif ($main::opt_addresses) {
1692 return "$a $func $fileline";
1693 } elsif ($main::opt_lines) {
1694 return "$func $fileline";
1695 } elsif ($main::opt_functions) {
1696 return $func;
1697 } elsif ($main::opt_files) {
1698 my $f = ($fileline eq '') ? $a : $fileline;
1699 $f =~ s/:\d+$//;
1700 return $f;
1701 } else {
1702 return $a;
1703 }
1704 } 1782 }
1705 1783
1706 # Generate percent string for a number and a total 1784 # Generate percent string for a number and a total
1707 sub Percent { 1785 sub Percent {
1708 my $num = shift; 1786 my $num = shift;
1709 my $tot = shift; 1787 my $tot = shift;
1710 if ($tot != 0) { 1788 if ($tot != 0) {
1711 return sprintf("%.1f%%", $num * 100.0 / $tot); 1789 return sprintf("%.1f%%", $num * 100.0 / $tot);
1712 } else { 1790 } else {
1713 return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf"); 1791 return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf");
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
1883 'tc_valloc', 1961 'tc_valloc',
1884 'tc_realloc', 1962 'tc_realloc',
1885 'tc_new', 1963 'tc_new',
1886 'tc_delete', 1964 'tc_delete',
1887 'tc_newarray', 1965 'tc_newarray',
1888 'tc_deletearray', 1966 'tc_deletearray',
1889 'tc_new_nothrow', 1967 'tc_new_nothrow',
1890 'tc_newarray_nothrow', 1968 'tc_newarray_nothrow',
1891 'do_malloc', 1969 'do_malloc',
1892 '::do_malloc', # new name -- got moved to an unnamed ns 1970 '::do_malloc', # new name -- got moved to an unnamed ns
1971 '::do_malloc_or_cpp_alloc',
1893 'DoSampledAllocation', 1972 'DoSampledAllocation',
1894 'simple_alloc::allocate', 1973 'simple_alloc::allocate',
1895 '__malloc_alloc_template::allocate', 1974 '__malloc_alloc_template::allocate',
1896 '__builtin_delete', 1975 '__builtin_delete',
1897 '__builtin_new', 1976 '__builtin_new',
1898 '__builtin_vec_delete', 1977 '__builtin_vec_delete',
1899 '__builtin_vec_new', 1978 '__builtin_vec_new',
1900 'operator new', 1979 'operator new',
1901 'operator new[]') { 1980 'operator new[]',
1981 » » # These mark the beginning/end of our custom sections
1982 » » '__start_google_malloc',
1983 » » '__stop_google_malloc',
1984 » » '__start_malloc_hook',
1985 » » '__stop_malloc_hook') {
1902 $skip{$name} = 1; 1986 $skip{$name} = 1;
1903 $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything 1987 $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything
1904 } 1988 }
1905 # TODO: Remove TCMalloc once everything has been 1989 # TODO: Remove TCMalloc once everything has been
1906 # moved into the tcmalloc:: namespace and we have flushed 1990 # moved into the tcmalloc:: namespace and we have flushed
1907 # old code out of the system. 1991 # old code out of the system.
1908 $skip_regexp = "TCMalloc|^tcmalloc::"; 1992 $skip_regexp = "TCMalloc|^tcmalloc::";
1909 } elsif ($main::profile_type eq 'contention') { 1993 } elsif ($main::profile_type eq 'contention') {
1910 foreach my $vname ('Mutex::Unlock', 'Mutex::UnlockSlow') { 1994 foreach my $vname ('Mutex::Unlock', 'Mutex::UnlockSlow') {
1911 $skip{$vname} = 1; 1995 $skip{$vname} = 1;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1971 return $result; 2055 return $result;
1972 } 2056 }
1973 2057
1974 # Reduce profile to granularity given by user 2058 # Reduce profile to granularity given by user
1975 sub ReduceProfile { 2059 sub ReduceProfile {
1976 my $symbols = shift; 2060 my $symbols = shift;
1977 my $profile = shift; 2061 my $profile = shift;
1978 my $result = {}; 2062 my $result = {};
1979 foreach my $k (keys(%{$profile})) { 2063 foreach my $k (keys(%{$profile})) {
1980 my $count = $profile->{$k}; 2064 my $count = $profile->{$k};
1981 my @addrs = split(/\n/, $k); 2065 my @translated = TranslateStack($symbols, $k);
1982 my @path = (); 2066 my @path = ();
1983 my %seen = (); 2067 my %seen = ();
1984 $seen{''} = 1; # So that empty keys are skipped 2068 $seen{''} = 1; # So that empty keys are skipped
1985 foreach my $a (@addrs) { 2069 foreach my $e (@translated) {
1986 # To avoid double-counting due to recursion, skip a stack-trace 2070 # To avoid double-counting due to recursion, skip a stack-trace
1987 # entry if it has already been seen 2071 # entry if it has already been seen
1988 my $key = OutputKey($symbols, $a); 2072 if (!$seen{$e}) {
1989 if (!$seen{$key}) { 2073 » $seen{$e} = 1;
1990 » $seen{$key} = 1; 2074 » push(@path, $e);
1991 » push(@path, $key);
1992 } 2075 }
1993 } 2076 }
1994 my $reduced_path = join("\n", @path); 2077 my $reduced_path = join("\n", @path);
1995 AddEntry($result, $reduced_path, $count); 2078 AddEntry($result, $reduced_path, $count);
1996 } 2079 }
1997 return $result; 2080 return $result;
1998 } 2081 }
1999 2082
2083 # Does the specified symbol array match the regexp?
2084 sub SymbolMatches {
2085 my $sym = shift;
2086 my $re = shift;
2087 if (defined($sym)) {
2088 for (my $i = 0; $i < $#{$sym}; $i += 3) {
2089 if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) {
2090 return 1;
2091 }
2092 }
2093 }
2094 return 0;
2095 }
2096
2000 # Focus only on paths involving specified regexps 2097 # Focus only on paths involving specified regexps
2001 sub FocusProfile { 2098 sub FocusProfile {
2002 my $symbols = shift; 2099 my $symbols = shift;
2003 my $profile = shift; 2100 my $profile = shift;
2004 my $focus = shift; 2101 my $focus = shift;
2005 my $result = {}; 2102 my $result = {};
2006 foreach my $k (keys(%{$profile})) { 2103 foreach my $k (keys(%{$profile})) {
2007 my $count = $profile->{$k}; 2104 my $count = $profile->{$k};
2008 my @addrs = split(/\n/, $k); 2105 my @addrs = split(/\n/, $k);
2009 foreach my $a (@addrs) { 2106 foreach my $a (@addrs) {
2010 # Reply if it matches either the address/shortname/fileline 2107 # Reply if it matches either the address/shortname/fileline
2011 if (($a =~ m/$focus/) || 2108 if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) {
2012 (exists($symbols->{$a}) &&
2013 (($symbols->{$a}->[0] =~ m/$focus/) ||
2014 ($symbols->{$a}->[1] =~ m/$focus/)))) {
2015 AddEntry($result, $k, $count); 2109 AddEntry($result, $k, $count);
2016 last; 2110 last;
2017 } 2111 }
2018 } 2112 }
2019 } 2113 }
2020 return $result; 2114 return $result;
2021 } 2115 }
2022 2116
2023 # Focus only on paths not involving specified regexps 2117 # Focus only on paths not involving specified regexps
2024 sub IgnoreProfile { 2118 sub IgnoreProfile {
2025 my $symbols = shift; 2119 my $symbols = shift;
2026 my $profile = shift; 2120 my $profile = shift;
2027 my $ignore = shift; 2121 my $ignore = shift;
2028 my $result = {}; 2122 my $result = {};
2029 foreach my $k (keys(%{$profile})) { 2123 foreach my $k (keys(%{$profile})) {
2030 my $count = $profile->{$k}; 2124 my $count = $profile->{$k};
2031 my @addrs = split(/\n/, $k); 2125 my @addrs = split(/\n/, $k);
2032 my $matched = 0; 2126 my $matched = 0;
2033 foreach my $a (@addrs) { 2127 foreach my $a (@addrs) {
2034 # Reply if it matches either the address/shortname/fileline 2128 # Reply if it matches either the address/shortname/fileline
2035 if (($a =~ m/$ignore/) || 2129 if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) {
2036 (exists($symbols->{$a}) &&
2037 (($symbols->{$a}->[0] =~ m/$ignore/) ||
2038 ($symbols->{$a}->[1] =~ m/$ignore/)))) {
2039 $matched = 1; 2130 $matched = 1;
2040 last; 2131 last;
2041 } 2132 }
2042 } 2133 }
2043 if (!$matched) { 2134 if (!$matched) {
2044 AddEntry($result, $k, $count); 2135 AddEntry($result, $k, $count);
2045 } 2136 }
2046 } 2137 }
2047 return $result; 2138 return $result;
2048 } 2139 }
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
2188 my @lines = <TFILE>; 2279 my @lines = <TFILE>;
2189 my $result = grep(/^--- *$symbol_marker/, @lines); 2280 my $result = grep(/^--- *$symbol_marker/, @lines);
2190 close(TFILE); 2281 close(TFILE);
2191 return $result > 0; 2282 return $result > 0;
2192 } 2283 }
2193 2284
2194 ##### Code to profile a server dynamically ##### 2285 ##### Code to profile a server dynamically #####
2195 2286
2196 sub CheckSymbolPage { 2287 sub CheckSymbolPage {
2197 my $url = SymbolPageURL(); 2288 my $url = SymbolPageURL();
2198 open(SYMBOL, "$WGET -qO- '$url' |"); 2289 open(SYMBOL, "$WGET $WGET_FLAGS -qO- '$url' |");
2199 my $line = <SYMBOL>; 2290 my $line = <SYMBOL>;
2200 $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines 2291 $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
2201 close(SYMBOL); 2292 close(SYMBOL);
2202 unless (defined($line)) { 2293 unless (defined($line)) {
2203 error("$url doesn't exist\n"); 2294 error("$url doesn't exist\n");
2204 } 2295 }
2205 2296
2206 if ($line =~ /^num_symbols:\s+(\d+)$/) { 2297 if ($line =~ /^num_symbols:\s+(\d+)$/) {
2207 if ($1 == 0) { 2298 if ($1 == 0) {
2208 error("Stripped binary. No symbols available.\n"); 2299 error("Stripped binary. No symbols available.\n");
(...skipping 24 matching lines...) Expand all
2233 2324
2234 # We fetch symbols from the first profile argument. 2325 # We fetch symbols from the first profile argument.
2235 sub SymbolPageURL { 2326 sub SymbolPageURL {
2236 my ($host, $port, $path) = ParseProfileURL($main::pfile_args[0]); 2327 my ($host, $port, $path) = ParseProfileURL($main::pfile_args[0]);
2237 return "http://$host:$port$SYMBOL_PAGE"; 2328 return "http://$host:$port$SYMBOL_PAGE";
2238 } 2329 }
2239 2330
2240 sub FetchProgramName() { 2331 sub FetchProgramName() {
2241 my ($host, $port, $path) = ParseProfileURL($main::pfile_args[0]); 2332 my ($host, $port, $path) = ParseProfileURL($main::pfile_args[0]);
2242 my $url = "http://$host:$port$PROGRAM_NAME_PAGE"; 2333 my $url = "http://$host:$port$PROGRAM_NAME_PAGE";
2243 my $command_line = "$WGET -qO- '$url'"; 2334 my $command_line = "$WGET $WGET_FLAGS -qO- '$url'";
2244 open(CMDLINE, "$command_line |") or error($command_line); 2335 open(CMDLINE, "$command_line |") or error($command_line);
2245 my $cmdline = <CMDLINE>; 2336 my $cmdline = <CMDLINE>;
2246 $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines 2337 $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines
2247 close(CMDLINE); 2338 close(CMDLINE);
2248 error("Failed to get program name from $url\n") unless defined($cmdline); 2339 error("Failed to get program name from $url\n") unless defined($cmdline);
2249 $cmdline =~ s/\x00.+//; # Remove argv[1] and latters. 2340 $cmdline =~ s/\x00.+//; # Remove argv[1] and latters.
2250 $cmdline =~ s!\n!!g; # Remove LFs. 2341 $cmdline =~ s!\n!!g; # Remove LFs.
2251 return $cmdline; 2342 return $cmdline;
2252 } 2343 }
2253 2344
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
2339 my $symbols = {}; 2430 my $symbols = {};
2340 foreach my $pc (@pcs) { 2431 foreach my $pc (@pcs) {
2341 my $fullname; 2432 my $fullname;
2342 # For 64 bits binaries, symbols are extracted with 8 leading zeroes. 2433 # For 64 bits binaries, symbols are extracted with 8 leading zeroes.
2343 # Then /symbol reads the long symbols in as uint64, and outputs 2434 # Then /symbol reads the long symbols in as uint64, and outputs
2344 # the result with a "0x%08llx" format which get rid of the zeroes. 2435 # the result with a "0x%08llx" format which get rid of the zeroes.
2345 # By removing all the leading zeroes in both $pc and the symbols from 2436 # By removing all the leading zeroes in both $pc and the symbols from
2346 # /symbol, the symbols match and are retrievable from the map. 2437 # /symbol, the symbols match and are retrievable from the map.
2347 my $shortpc = $pc; 2438 my $shortpc = $pc;
2348 $shortpc =~ s/^0*//; 2439 $shortpc =~ s/^0*//;
2440 # Each line may have a list of names, which includes the function
2441 # and also other functions it has inlined. They are separated
2442 # (in PrintSymbolizedFile), by --, which is illegal in function names.
2443 my $fullnames;
2349 if (defined($symbol_map->{$shortpc})) { 2444 if (defined($symbol_map->{$shortpc})) {
2350 $fullname = $symbol_map->{$shortpc}; 2445 $fullnames = $symbol_map->{$shortpc};
2351 } else { 2446 } else {
2352 $fullname = "0x" . $pc; # Just use addresses 2447 $fullnames = "0x" . $pc; # Just use addresses
2353 } 2448 }
2354 my $name = ShortFunctionName($fullname); 2449 my $sym = [];
2355 $symbols->{$pc} = [$name, "?", $fullname]; 2450 $symbols->{$pc} = $sym;
2451 foreach my $fullname (split("--", $fullnames)) {
2452 my $name = ShortFunctionName($fullname);
2453 push(@{$sym}, $name, "?", $fullname);
2454 }
2356 } 2455 }
2357 return $symbols; 2456 return $symbols;
2358 } 2457 }
2359 2458
2360 sub BaseName { 2459 sub BaseName {
2361 my $file_name = shift; 2460 my $file_name = shift;
2362 $file_name =~ s!^.*/!!; # Remove directory name 2461 $file_name =~ s!^.*/!!; # Remove directory name
2363 return $file_name; 2462 return $file_name;
2364 } 2463 }
2365 2464
(...skipping 19 matching lines...) Expand all
2385 # Missing type specifier defaults to cpu-profile 2484 # Missing type specifier defaults to cpu-profile
2386 $path = $PROFILE_PAGE; 2485 $path = $PROFILE_PAGE;
2387 } 2486 }
2388 2487
2389 my $profile_file = MakeProfileBaseName($binary_name, $profile_name); 2488 my $profile_file = MakeProfileBaseName($binary_name, $profile_name);
2390 2489
2391 my $url; 2490 my $url;
2392 my $wget_timeout; 2491 my $wget_timeout;
2393 if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)) { 2492 if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)) {
2394 if ($path =~ m/$PROFILE_PAGE/) { 2493 if ($path =~ m/$PROFILE_PAGE/) {
2395 $url = sprintf("http://$host:$port$PROFILE_PAGE?seconds=%d", 2494 $url = sprintf("http://$host:$port$path?seconds=%d",
2396 $main::opt_seconds); 2495 $main::opt_seconds);
2397 } else { 2496 } else {
2398 if ($profile_name =~ m/[?]/) { 2497 if ($profile_name =~ m/[?]/) {
2399 $profile_name .= "&" 2498 $profile_name .= "&"
2400 } else { 2499 } else {
2401 $profile_name .= "?" 2500 $profile_name .= "?"
2402 } 2501 }
2403 $url = sprintf("http://$profile_name" . "seconds=%d", 2502 $url = sprintf("http://$profile_name" . "seconds=%d",
2404 $main::opt_seconds); 2503 $main::opt_seconds);
2405 } 2504 }
(...skipping 14 matching lines...) Expand all
2420 mkdir($profile_dir) 2519 mkdir($profile_dir)
2421 || die("Unable to create profile directory $profile_dir: $!\n"); 2520 || die("Unable to create profile directory $profile_dir: $!\n");
2422 } 2521 }
2423 my $tmp_profile = "$profile_dir/.tmp.$profile_file"; 2522 my $tmp_profile = "$profile_dir/.tmp.$profile_file";
2424 my $real_profile = "$profile_dir/$profile_file"; 2523 my $real_profile = "$profile_dir/$profile_file";
2425 2524
2426 if ($fetch_name_only > 0) { 2525 if ($fetch_name_only > 0) {
2427 return $real_profile; 2526 return $real_profile;
2428 } 2527 }
2429 2528
2430 my $cmd = "$WGET $wget_timeout -q -O $tmp_profile '$url'"; 2529 my $cmd = "$WGET $WGET_FLAGS $wget_timeout -q -O $tmp_profile '$url'";
2431 if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)){ 2530 if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)){
2432 print STDERR "Gathering CPU profile from $url for $main::opt_seconds secon ds to\n ${real_profile}\n"; 2531 print STDERR "Gathering CPU profile from $url for $main::opt_seconds secon ds to\n ${real_profile}\n";
2433 if ($encourage_patience) { 2532 if ($encourage_patience) {
2434 print STDERR "Be patient...\n"; 2533 print STDERR "Be patient...\n";
2435 } 2534 }
2436 } else { 2535 } else {
2437 print STDERR "Fetching $path profile from $host:$port to\n ${real_profile }\n"; 2536 print STDERR "Fetching $path profile from $host:$port to\n ${real_profile }\n";
2438 } 2537 }
2439 2538
2440 (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n"); 2539 (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n");
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
2745 error("$fname: stack trace depth >= 2**32\n"); 2844 error("$fname: stack trace depth >= 2**32\n");
2746 } 2845 }
2747 if ($slots->get($i) == 0 && $slots->get($i+1) == 0) { 2846 if ($slots->get($i) == 0 && $slots->get($i+1) == 0) {
2748 # End of profile data marker 2847 # End of profile data marker
2749 $i += 2 * $d; 2848 $i += 2 * $d;
2750 last; 2849 last;
2751 } 2850 }
2752 2851
2753 # Make key out of the stack entries 2852 # Make key out of the stack entries
2754 my @k = (); 2853 my @k = ();
2755 for (my $j = $d; $j--; ) { 2854 for (my $j = 0; $j < $d; $j++) {
2756 my $pclo = $slots->get($i++); 2855 my $pclo = $slots->get($i++);
2757 my $pchi = $slots->get($i++); 2856 my $pchi = $slots->get($i++);
2758 if ($pclo == -1 || $pchi == -1) { 2857 if ($pclo == -1 || $pchi == -1) {
2759 error("$fname: Unexpected EOF when reading stack of depth $d\n"); 2858 error("$fname: Unexpected EOF when reading stack of depth $d\n");
2760 } 2859 }
2860
2861 # Subtract one from caller pc so we map back to call instr.
2862 # However, don't do this if we're reading a symbolized profile
2863 # file, in which case the subtract-one was done when the file
2864 # was written.
2865 if ($j > 0 && !$main::use_symbolized_profile) {
2866 if ($pclo == 0) {
2867 $pchi--;
2868 $pclo = 0xffffffff;
2869 } else {
2870 $pclo--;
2871 }
2872 }
2873
2761 my $pc = sprintf("%08x%08x", $pchi, $pclo); 2874 my $pc = sprintf("%08x%08x", $pchi, $pclo);
2762 $pcs->{$pc} = 1; 2875 $pcs->{$pc} = 1;
2763 push @k, $pc; 2876 push @k, $pc;
2764 } 2877 }
2765 AddEntry($profile, (join "\n", @k), $n); 2878 AddEntry($profile, (join "\n", @k), $n);
2766 } 2879 }
2767 } 2880 }
2768 2881
2769 # Parse map 2882 # Parse map
2770 my $map = ''; 2883 my $map = '';
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after
3249 my $buildvar = ""; 3362 my $buildvar = "";
3250 foreach my $l (split("\n", $map)) { 3363 foreach my $l (split("\n", $map)) {
3251 if ($l =~ m/^\s*build=(.*)$/) { 3364 if ($l =~ m/^\s*build=(.*)$/) {
3252 $buildvar = $1; 3365 $buildvar = $1;
3253 } 3366 }
3254 3367
3255 my $start; 3368 my $start;
3256 my $finish; 3369 my $finish;
3257 my $offset; 3370 my $offset;
3258 my $lib; 3371 my $lib;
3259 if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib)(( \.\d+)+\w*)?)$/i) { 3372 if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bu ndle)((\.\d+)+\w*)?)$/i) {
3260 # Full line from /proc/self/maps. Example: 3373 # Full line from /proc/self/maps. Example:
3261 # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so 3374 # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so
3262 $start = HexExtend($1); 3375 $start = HexExtend($1);
3263 $finish = HexExtend($2); 3376 $finish = HexExtend($2);
3264 $offset = HexExtend($3); 3377 $offset = HexExtend($3);
3265 $lib = $4; 3378 $lib = $4;
3266 $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths 3379 $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths
3267 } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) { 3380 } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) {
3268 # Cooked line from DumpAddressMap. Example: 3381 # Cooked line from DumpAddressMap. Example:
3269 # 40000000-40015000: /lib/ld-2.3.2.so 3382 # 40000000-40015000: /lib/ld-2.3.2.so
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
3509 return $symbols; 3622 return $symbols;
3510 } 3623 }
3511 3624
3512 # Map list of PC values to symbols for a given image 3625 # Map list of PC values to symbols for a given image
3513 sub MapToSymbols { 3626 sub MapToSymbols {
3514 my $image = shift; 3627 my $image = shift;
3515 my $offset = shift; 3628 my $offset = shift;
3516 my $pclist = shift; 3629 my $pclist = shift;
3517 my $symbols = shift; 3630 my $symbols = shift;
3518 3631
3632 my $debug = 0;
3633
3519 # Ignore empty binaries 3634 # Ignore empty binaries
3520 if ($#{$pclist} < 0) { return; } 3635 if ($#{$pclist} < 0) { return; }
3521 3636
3522 my $got_symbols = MapSymbolsWithNM($image, $offset, $pclist, $symbols); 3637 # Figure out the addr2line command to use
3523 if ($main::opt_interactive || 3638 my $addr2line = $obj_tool_map{"addr2line"};
3524 $main::opt_addresses || 3639 my $cmd = "$addr2line -f -C -e $image";
3525 $main::opt_lines || 3640 if (exists $obj_tool_map{"addr2line_pdb"}) {
3526 $main::opt_files || 3641 $addr2line = $obj_tool_map{"addr2line_pdb"};
3527 $main::opt_list || 3642 $cmd = "$addr2line --demangle -f -C -e $image";
3528 $main::opt_callgrind ||
3529 !$got_symbols) {
3530 GetLineNumbers($image, $offset, $pclist, $symbols);
3531 } 3643 }
3532 }
3533 3644
3534 # The file $tmpfile_sym must already have been created before calling this. 3645 # If "addr2line" isn't installed on the system at all, just use
3535 sub GetLineNumbersViaAddr2Line { 3646 # nm to get what info we can (function names, but not line numbers).
3536 my $addr2line_command = shift; 3647 if (system("$addr2line --help >/dev/null 2>&1") != 0) {
3537 my $pclist = shift; 3648 MapSymbolsWithNM($image, $offset, $pclist, $symbols);
3538 my $symbols = shift; 3649 return;
3650 }
3539 3651
3540 open(SYMBOLS, "$addr2line_command <$main::tmpfile_sym |") 3652 # "addr2line -i" can produce a variable number of lines per input
3541 || error("$addr2line_command: $!\n"); 3653 # address, with no separator that allows us to tell when data for
3542 my $count = 0; 3654 # the next address starts. So we find the address for a special
3655 # symbol (_fini) and interleave this address between all real
3656 # addresses passed to addr2line. The name of this special symbol
3657 # can then be used as a separator.
3658 $sep_address = undef; # May be filled in by MapSymbolsWithNM()
3659 my $nm_symbols = {};
3660 MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols);
3661 # TODO(csilvers): only add '-i' if addr2line supports it.
3662 if (defined($sep_address)) {
3663 # Only add " -i" to addr2line if the binary supports it.
3664 # addr2line --help returns 0, but not if it sees an unknown flag first.
3665 if (system("$cmd -i --help >/dev/null 2>&1") == 0) {
3666 $cmd .= " -i";
3667 } else {
3668 $sep_address = undef; # no need for sep_address if we don't support -i
3669 }
3670 }
3671
3672 # Make file with all PC values with intervening 'sep_address' so
3673 # that we can reliably detect the end of inlined function list
3674 open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n");
3675 if ($debug) { print("---- $image ---\n"); }
3676 for (my $i = 0; $i <= $#{$pclist}; $i++) {
3677 # addr2line always reads hex addresses, and does not need '0x' prefix.
3678 if ($debug) { printf("%s\n", $pclist->[$i]); }
3679 printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
3680 if (defined($sep_address)) {
3681 printf ADDRESSES ("%s\n", $sep_address);
3682 }
3683 }
3684 close(ADDRESSES);
3685 if ($debug) {
3686 print("----\n");
3687 system("cat $main::tmpfile_sym");
3688 print("----\n");
3689 system("$cmd <$main::tmpfile_sym");
3690 print("----\n");
3691 }
3692
3693 open(SYMBOLS, "$cmd <$main::tmpfile_sym |") || error("$cmd: $!\n");
3694 my $count = 0; # Index in pclist
3543 while (<SYMBOLS>) { 3695 while (<SYMBOLS>) {
3696 # Read fullfunction and filelineinfo from next pair of lines
3544 s/\r?\n$//g; 3697 s/\r?\n$//g;
3545 my $fullfunction = $_; 3698 my $fullfunction = $_;
3546
3547 $_ = <SYMBOLS>; 3699 $_ = <SYMBOLS>;
3548 s/\r?\n$//g; 3700 s/\r?\n$//g;
3549 my $filelinenum = $_; 3701 my $filelinenum = $_;
3550 $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths 3702
3551 if (!$main::opt_list) { 3703 if (defined($sep_address) && $fullfunction eq $sep_symbol) {
3552 $filelinenum =~ s|^.*/([^/]+:\d+)$|$1|; # Remove directory name 3704 # Terminating marker for data for this address
3705 $count++;
3706 next;
3553 } 3707 }
3554 3708
3709 $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths
3710
3555 my $pcstr = $pclist->[$count]; 3711 my $pcstr = $pclist->[$count];
3556 if (defined($symbols->{$pcstr})) { 3712 my $function = ShortFunctionName($fullfunction);
3557 # Override just the line-number portion. The function name portion 3713 if ($fullfunction eq '??') {
3558 # is less buggy when computed using nm instead of addr2line. But 3714 # See if nm found a symbol
3559 # don't override if addr2line is giving ??'s and nm didn't. (This 3715 my $nms = $nm_symbols->{$pcstr};
3560 # may be seen mostly/entirely on cygwin's addr2line/nm.) 3716 if (defined($nms)) {
3561 if (($filelinenum ne "??:0") || ($symbols->{$pcstr}->[1] eq "?")) { 3717 $function = $nms->[0];
3562 $symbols->{$pcstr}->[1] = $filelinenum; 3718 $fullfunction = $nms->[2];
3563 } 3719 }
3564 } else {
3565 my $function = ShortFunctionName($fullfunction);
3566 $symbols->{$pcstr} = [$function, $filelinenum, $fullfunction];
3567 } 3720 }
3568 $count++; 3721
3722 # Prepend to accumulated symbols for pcstr
3723 # (so that caller comes before callee)
3724 my $sym = $symbols->{$pcstr};
3725 if (!defined($sym)) {
3726 $sym = [];
3727 $symbols->{$pcstr} = $sym;
3728 }
3729 unshift(@{$sym}, $function, $filelinenum, $fullfunction);
3730 if ($debug) { printf("%s => [%s]\n", $pcstr, join(" ", @{$sym})); }
3731 if (!defined($sep_address)) {
3732 # Inlining is off, se this entry ends immediately
3733 $count++;
3734 }
3569 } 3735 }
3570 close(SYMBOLS); 3736 close(SYMBOLS);
3571 return $count;
3572 }
3573
3574 sub GetLineNumbers {
3575 my $image = shift;
3576 my $offset = shift;
3577 my $pclist = shift;
3578 my $symbols = shift;
3579
3580 # Make file with all PC values
3581 open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n");
3582 for (my $i = 0; $i <= $#{$pclist}; $i++) {
3583 # addr2line always reads hex addresses, and does not need '0x' prefix.
3584 printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
3585 }
3586 close(ADDRESSES);
3587
3588 # Pass to addr2line
3589 my $addr2line = $obj_tool_map{"addr2line"};
3590 my @addr2line_commands = ("$addr2line -f -C -e $image");
3591 if (exists $obj_tool_map{"addr2line_pdb"}) {
3592 my $addr2line_pdb = $obj_tool_map{"addr2line_pdb"};
3593 push(@addr2line_commands, "$addr2line_pdb --demangle -f -C -e $image");
3594 }
3595 foreach my $addr2line_command (@addr2line_commands) {
3596 if (GetLineNumbersViaAddr2Line("$addr2line_command", $pclist, $symbols)) {
3597 last;
3598 }
3599 }
3600 } 3737 }
3601 3738
3602 # Use nm to map the list of referenced PCs to symbols. Return true iff we 3739 # Use nm to map the list of referenced PCs to symbols. Return true iff we
3603 # are able to read procedure information via nm. 3740 # are able to read procedure information via nm.
3604 sub MapSymbolsWithNM { 3741 sub MapSymbolsWithNM {
3605 my $image = shift; 3742 my $image = shift;
3606 my $offset = shift; 3743 my $offset = shift;
3607 my $pclist = shift; 3744 my $pclist = shift;
3608 my $symbols = shift; 3745 my $symbols = shift;
3609 3746
(...skipping 29 matching lines...) Expand all
3639 } 3776 }
3640 if ($mpc lt $symbol_table->{$fullname}->[1]) { 3777 if ($mpc lt $symbol_table->{$fullname}->[1]) {
3641 $symbols->{$pc} = [$name, "?", $fullname]; 3778 $symbols->{$pc} = [$name, "?", $fullname];
3642 } else { 3779 } else {
3643 my $pcstr = "0x" . $pc; 3780 my $pcstr = "0x" . $pc;
3644 $symbols->{$pc} = [$pcstr, "?", $pcstr]; 3781 $symbols->{$pc} = [$pcstr, "?", $pcstr];
3645 } 3782 }
3646 } 3783 }
3647 return 1; 3784 return 1;
3648 } 3785 }
3649 3786
3650 sub ShortFunctionName { 3787 sub ShortFunctionName {
3651 my $function = shift; 3788 my $function = shift;
3652 while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types 3789 while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types
3653 while ($function =~ s/<[^<>]*>//g) { } # Remove template arguments 3790 while ($function =~ s/<[^<>]*>//g) { } # Remove template arguments
3654 $function =~ s/^.*\s+(\w+::)/$1/; # Remove leading type 3791 $function =~ s/^.*\s+(\w+::)/$1/; # Remove leading type
3655 return $function; 3792 return $function;
3656 } 3793 }
3657 3794
3658 ##### Miscellaneous ##### 3795 ##### Miscellaneous #####
3659 3796
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
3806 # got touched in the queue), and ignore the others. 3943 # got touched in the queue), and ignore the others.
3807 if ($start_val eq $last_start && $type =~ /t/i) { 3944 if ($start_val eq $last_start && $type =~ /t/i) {
3808 # We are the 'T' symbol at this address, replace previous symbol. 3945 # We are the 'T' symbol at this address, replace previous symbol.
3809 $routine = $this_routine; 3946 $routine = $this_routine;
3810 next; 3947 next;
3811 } elsif ($start_val eq $last_start) { 3948 } elsif ($start_val eq $last_start) {
3812 # We're not the 'T' symbol at this address, so ignore us. 3949 # We're not the 'T' symbol at this address, so ignore us.
3813 next; 3950 next;
3814 } 3951 }
3815 3952
3953 if ($this_routine eq $sep_symbol) {
3954 $sep_address = HexExtend($start_val);
3955 }
3956
3816 # Tag this routine with the starting address in case the image 3957 # Tag this routine with the starting address in case the image
3817 # has multiple occurrences of this routine. We use a syntax 3958 # has multiple occurrences of this routine. We use a syntax
3818 # that resembles template paramters that are automatically 3959 # that resembles template paramters that are automatically
3819 # stripped out by ShortFunctionName() 3960 # stripped out by ShortFunctionName()
3820 $this_routine .= "<$start_val>"; 3961 $this_routine .= "<$start_val>";
3821 3962
3822 if (defined($routine) && $routine =~ m/$regexp/) { 3963 if (defined($routine) && $routine =~ m/$regexp/) {
3823 $symbol_table->{$routine} = [HexExtend($last_start), 3964 $symbol_table->{$routine} = [HexExtend($last_start),
3824 HexExtend($start_val)]; 3965 HexExtend($start_val)];
3825 } 3966 }
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
4116 $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16); 4257 $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16);
4117 $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16); 4258 $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16);
4118 if ($error_count > 0) { 4259 if ($error_count > 0) {
4119 print STDERR $error_count, " errors: FAILED\n"; 4260 print STDERR $error_count, " errors: FAILED\n";
4120 } else { 4261 } else {
4121 print STDERR "PASS\n"; 4262 print STDERR "PASS\n";
4122 } 4263 }
4123 exit ($error_count); 4264 exit ($error_count);
4124 } 4265 }
4125 4266
OLDNEW
« no previous file with comments | « third_party/tcmalloc/chromium/src/pagemap.h ('k') | third_party/tcmalloc/chromium/src/profile-handler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698