Lines Matching +full:lock +full:- +full:detect +full:- +full:precision +full:- +full:6 +full:ns +full:- +full:enable
3 # Copyright (c) 1998-2007, Google Inc.
32 # ---
38 # This program parses the profile, and generates user-readable
46 # % tools/jeprof --text "program" "profile"
49 # % tools/jeprof --gv "program" "profile"
50 # Generates annotated call-graph and displays via "gv"
52 # % tools/jeprof --gv --focus=Mutex "program" "profile"
55 # % tools/jeprof --gv --focus=Mutex --ignore=string "program" "profile"
59 # % tools/jeprof --list=IBF_CheckDocid "program" "profile"
61 # sample that match the --list=<regexp> pattern. The listing is
64 # % tools/jeprof --disasm=IBF_CheckDocid "program" "profile"
66 # sample that match the --disasm=<regexp> pattern. The listing is
80 # user-specified location using --tools, from the JEPROF_TOOLS
87 ## ConfigureObjTools may add architecture-specific entries:
88 #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables
89 #"addr2line_pdb" => "addr2line-pdb", # ditto
93 my @DOT = ("dot"); # leave non-absolute, since it may be in /usr/local
99 my @URL_FETCHER = ("curl", "-s", "--fail");
103 my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#"
104 my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param
110 my $CENSUSPROFILE_PAGE = "/pprof/censusprofile(?:\\?.*)?"; # must support cgi-param
127 # i.e., nibbles) of an address, distinguishing between 32-bit and
128 # 64-bit profiles. To err on the safe size, default to 64-bit here:
132 if (! -e $dev_null && $^O =~ /MSWin/) { # $^O is the OS perl was built for
140 # Used as separator to parse "addr2line -i" output.
151 jeprof [options] <symbolized-profiles>
152 <symbolized-profiles> is a list of profile files where each file contains
154 with --raw).
159 /path/to/profile - a path to a profile file
160 host:port[/<service>] - a location of a service to get profile from
168 jeprof --symbols <program>
170 list of library mappings, in the same format as is found in the heap-
171 and cpu-profile files (this loosely matches that of /proc/self/maps
175 necessary server-side support code, see this filename (or one like it):
177 /usr/doc/gperftools-$PPROF_VERSION/pprof_remote_servers.html
180 --cum Sort by cumulative data
181 --base=<base> Subtract <base> from <profile> before display
182 --interactive Run in interactive mode (interactive "help" gives help) [default]
183 --seconds=<n> Length of time for dynamic profiles [default=30 secs]
184 --add_lib=<file> Read additional symbols and line info from the given library
185 --lib_prefix=<dir> Comma separated list of library path prefixes
188 --addresses Report at address level
189 --lines Report at source line level
190 --functions Report at function level [default]
191 --files Report at source file level
194 --text Generate text report
195 --callgrind Generate callgrind format to stdout
196 --gv Generate Postscript and display
197 --evince Generate PDF and display
198 --web Generate SVG and display
199 --list=<regexp> Generate source listing of matching routines
200 --disasm=<regexp> Generate disassembly of matching routines
201 --symbols Print demangled symbol names found at given addresses
202 --dot Generate DOT file to stdout
203 --ps Generate Postcript to stdout
204 --pdf Generate PDF to stdout
205 --svg Generate SVG to stdout
206 --gif Generate GIF to stdout
207 --raw Generate symbolized jeprof data (useful with remote fetch)
208 --collapsed Generate collapsed stacks for building flame graphs
211 Heap-Profile Options:
212 --inuse_space Display in-use (mega)bytes [default]
213 --inuse_objects Display in-use objects
214 --alloc_space Display allocated (mega)bytes
215 --alloc_objects Display allocated objects
216 --show_bytes Display space in bytes
217 --drop_negative Ignore negative differences
219 Contention-profile options:
220 --total_delay Display total delay at each region [default]
221 --contentions Display number of delays at each region
222 --mean_delay Display mean delay at each region
224 Call-graph Options:
225 --nodecount=<n> Show at most so many nodes [default=80]
226 --nodefraction=<f> Hide nodes below <f>*total [default=.005]
227 --edgefraction=<f> Hide edges below <f>*total [default=.001]
228 --maxdegree=<n> Max incoming/outgoing edges per node [default=8]
229 --focus=<regexp> Focus on backtraces with nodes matching <regexp>
230 --thread=<n> Show profile for thread <n>
231 --ignore=<regexp> Ignore backtraces with nodes matching <regexp>
232 --scale=<n> Set GV scaling [default=0]
233 --heapcheck Make nodes with non-0 object counts
235 --retain=<regexp> Retain only nodes that match <regexp>
236 --exclude=<regexp> Exclude all nodes that match <regexp>
239 --tools=<prefix or binary:fullpath>[,...] \$PATH for object tool pathnames
240 --test Run unit tests
241 --help This message
242 --version Version information
243 --debug-syms-by-id (Linux only) Find debug symbol files by build ID as well as by name
253 jeprof --text /bin/ls ls.prof
255 jeprof --web /bin/ls ls.prof
256 Displays annotated call-graph in web browser
257 jeprof --gv /bin/ls ls.prof
258 Displays annotated call-graph via 'gv'
259 jeprof --gv --focus=Mutex /bin/ls ls.prof
261 jeprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof
263 jeprof --list=getdir /bin/ls ls.prof
264 (Per-line) annotated source listing for getdir()
265 jeprof --disasm=getdir /bin/ls ls.prof
266 (Per-PC) annotated disassembly for getdir()
270 jeprof --text localhost:1234
272 jeprof --raw localhost:1234 > ./local.raw
273 jeprof --text ./local.raw
284 Copyright 1998-2007 Google Inc.
302 # Setup tmp-file name and handler to clean it up.
438 "debug-syms-by-id!" => \$main::opt_debug_syms_by_id,
443 # Deal with the standard --help and --version
454 # Disassembly/listing/symbols mode requires address-level info
462 # Check heap-profiling flags
467 usage("Specify at most on of --inuse/--alloc options");
507 if (-t STDOUT) { # If STDOUT is a tty, activate interactive mode
536 my %disabled = ('--lines' => $main::opt_lines,
537 '--disasm' => $main::opt_disasm);
544 # --symbols needs a binary-name (to run nm on, etc) but not profiles
553 if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) {
586 # --debug-syms-by-id option).
627 # (only matters when --heapcheck is given but we must be
628 # compatible with old branches that did not pass --heapcheck always):
634 PrintText($symbols, $flat, $cumulative, -1);
692 my $profile = $data->{profile};
693 my $pcs = $data->{pcs};
694 my $libs = $data->{libs}; # Info about main program and shared libraries
695 $symbol_map = MergeSymbols($symbol_map, $data->{symbols});
701 $profile = AddProfile($profile, $data2->{profile});
702 $pcs = AddPcs($pcs, $data2->{pcs});
703 $symbol_map = MergeSymbols($symbol_map, $data2->{symbols});
710 $profile = SubtractProfile($profile, $base->{profile});
711 $pcs = AddPcs($pcs, $base->{pcs});
712 $symbol_map = MergeSymbols($symbol_map, $base->{symbols});
732 if (defined($data->{threads})) {
733 foreach my $thread (sort { $a <=> $b } keys(%{$data->{threads}})) {
736 my $thread_profile = $data->{threads}{$thread};
750 # Temporary code to detect if we're running on a Goobuntu system.
753 # to using the normal stdio code, rather than the fancier readline-based
756 if (-e '/lib/libtermcap.so.2') {
766 if (!system(ShellEscape(@GV, "--version") . " >$dev_null 2>&1")) {
770 # TODO: Maybe we should not pass the --noantialias flag
772 system(ShellEscape(@GV, "--scale=$main::opt_scale", "--noantialias", $fname)
775 # Old gv version - only supports options that use single dash.
776 print STDERR ShellEscape(@GV, "-scale", $main::opt_scale) . "\n";
777 system(ShellEscape(@GV, "-scale", "$main::opt_scale", $fname) . $bg);
801 "/etc/alternatives/gnome-www-browser",
802 "/etc/alternatives/x-www-browser",
803 "google-chrome",
832 if ( -t STDIN &&
836 while ( defined ($_ = $term->readline('(jeprof) '))) {
837 $term->addhistory($_) if /\S/;
847 s/\r//g; # turn windows-looking lines into unix-looking lines
878 # Clear all the mode options -- mode is controlled by "$command"
1041 gv [focus] [-ignore1] [-ignore2]
1049 web [focus] [-ignore1] [-ignore2]
1053 On Linux, set the /etc/alternatives/gnome-www-browser symlink.
1056 list [routine_regexp] [-ignore1] [-ignore2]
1059 weblist [routine_regexp] [-ignore1] [-ignore2]
1064 top [--cum] [-ignore1] [-ignore2]
1065 top20 [--cum] [-ignore1] [-ignore2]
1066 top37 [--cum] [-ignore1] [-ignore2]
1068 if --cum is specified. If a number is present after 'top', the
1071 disasm [routine_regexp] [-ignore1] [-ignore2]
1079 help - This listing
1080 quit or ^D - End jeprof
1082 For commands that accept optional -ignore tags, samples where any routine in
1083 the stack trace matches the regular expression in any of the -ignore
1088 /usr/doc/gperftools-$PPROF_VERSION/cpu_profiler.html
1089 /usr/doc/gperftools-$PPROF_VERSION/heap_profiler.html
1099 if ($a =~ m/^(--|-)lines$/) {
1101 } elsif ($a =~ m/^(--|-)cum$/) {
1103 } elsif ($a =~ m/^-(.*)/) {
1125 # Print profile data in packed binary format (64-bit) to standard out
1129 # print header (64-bit style)
1130 # (zero) (header-size) (version) (sample-period) (zero)
1134 my $count = $profile->{$k};
1139 # 32 bits on both 32- and 64-bit systems.
1150 my $low_addr = substr($addr, -8); # get last 8 hex chars
1151 my $high_addr = substr($addr, -16, 8); # get up to 8 more hex chars
1167 print '--- ', $symbol_marker, "\n";
1175 # calls. They are separated (and terminated) by --, which is
1178 print $sep, $name->[$j];
1179 $sep = '--';
1183 print '---', "\n";
1200 print '--- ', $profile_marker, "\n";
1209 # --raw/http: For everything to work correctly for non-remote profiles, we
1211 # types, re-enable the code that is currently disabled in ReadCPUProfile()
1214 die "--raw/http: jeprof can only dump remote profiles for --raw\n";
1215 # dump a cpu-format profile to standard out
1241 if (exists($symbols->{$k})) {
1242 $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1];
1249 printf("%8s %6s %6s %8s %6s %s\n",
1270 my $idx = $map->{$val};
1279 $map->{$val} = $idx;
1299 foreach my $call ( map { $_->[0] }
1300 sort { $a->[1] cmp $b ->[1] ||
1301 $a->[2] <=> $b->[2] }
1302 map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
1305 my $count = int($calls->{$call});
1306 $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
1309 ( $1, $2, $3, $5, $6, $7 );
1316 if (defined $6) {
1335 my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts);
1336 my $offset = AddressSub($lib->[1], $lib->[3]);
1338 my $start_addr = $symbol_table->{$routine}->[0];
1339 my $end_addr = $symbol_table->{$routine}->[1];
1344 if (defined($cumulative->{$addr})) {
1345 PrintDisassembledFunction($lib->[0], $offset,
1367 my $cmd = ShellEscape($objdump, "-C", "-d", "-l", "--no-show-raw-insn",
1368 "--start-address=0x$start_addr",
1369 "--stop-address=0x$end_addr", $prog);
1373 my $linenumber = -1;
1376 s/\r//g; # turn windows-looking lines into unix-looking lines
1383 } elsif (m/^ +([0-9a-f]+):\s*(.*)/) {
1384 # Disassembly line -- zero-extend address to full length
1387 $last->[4] = $k; # Store ending address for previous instruction
1396 # The input file should contain lines of the form /proc/maps-like
1409 $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
1410 if ($line =~ /\b(0x[0-9a-f]+)\b/i) {
1412 $pcs->{$pclist[-1]} = 1;
1422 # ->[0] is the shortname, ->[2] is the full name
1423 print(($symbols->{$pc}->[0] || "??") . "\n");
1433 # Print source-listing for all all routines that match $list_opts
1461 my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
1462 my $offset = AddressSub($lib->[1], $lib->[3]);
1465 my $start_addr = $symbol_table->{$routine}->[0];
1466 my $end_addr = $symbol_table->{$routine}->[1];
1470 if (defined($cumulative->{$addr})) {
1472 $lib->[0], $offset,
1504 font-family: sans-serif;
1507 font-size: 1.5em;
1508 margin-bottom: 4px;
1511 font-size: 1.25em;
1529 background-color: #eeeeee;
1536 background-color: #eeeeee;
1580 # Returns the indentation of the line, if it has any non-whitespace
1581 # characters. Otherwise, returns -1.
1587 return -1;
1606 # [6] most specific line number (may be different from [2] due to inlining)
1611 push(@{$pcs}, $instructions->[$i]->[0]);
1616 my $e = $instructions->[$i];
1617 push(@{$e}, $e->[1]);
1618 push(@{$e}, $e->[2]);
1619 my $addr = $e->[0];
1620 my $sym = $symbols->{$addr};
1622 if ($#{$sym} >= 2 && $sym->[1] =~ m/^(.*):(\d+)$/) {
1623 $e->[1] = $1; # File name
1624 $e->[2] = $2; # Line number
1630 # Print source-listing for one routine
1650 if ($instructions[$i]->[2] >= 0) {
1651 $filename = $instructions[$i]->[1];
1667 my $f = $instructions[$i]->[1];
1668 my $l = $instructions[$i]->[2];
1678 if ($instructions[$i]->[1] eq $filename) {
1679 $firstline = $instructions[$i]->[2];
1693 my $first_indentation = -1;
1695 s/\r//g; # turn windows-looking lines into unix-looking lines
1726 my $skip_marker = "---\n";
1734 my $last_dis_linenum = -1;
1735 my $last_touched_line = -1; # To detect gaps in disassembly for a line
1740 for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
1746 my $dis = sprintf(" %6s %6s \t\t%8s: %s ",
1749 UnparseAddress($offset, $e->[0]),
1750 CleanDisassembly($e->[3]));
1753 if (length($dis) < 80) { $dis .= (' ' x (80 - length($dis))) };
1755 my $f = $e->[5];
1756 my $l = $e->[6];
1761 # De-emphasize the unchanged file name portion
1766 # De-emphasize the entire location
1780 my $file = $e->[1];
1781 my $line = $e->[2];
1814 "Total:%6s %6s (flat / cumulative %s)\n",
1823 "%6s %6s Total %s (flat / cumulative)\n",
1836 s/\r//g; # turn windows-looking lines into unix-looking lines
1838 if ($l >= $firstline - 5 &&
1847 # livesrc -- has samples
1848 # deadsrc -- has disassembly, but with no samples
1849 # nop -- has no matching disasembly
1861 "<span class=\"%s\">%6s %6s %s</span>%s\n",
1869 "%6s %6s %4d: %s\n",
1905 push(@{$lines}, ""); # So we can use 1-based line numbers as indices
1919 return $lines->[$line];
1946 for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
1958 "%6s %6s %s (flat, cumulative) %.1f%% of total\n",
1971 if ($e->[1] ne $current_file) {
1972 $current_file = $e->[1];
1978 $fname = "..." . substr($fname, -55);
1980 printf("-------------------- %s\n", $fname);
1985 my $first_line = $e->[2];
1997 ($instructions[$i]->[2] >= $first_line) &&
1998 ($instructions[$i]->[2] <= $last_line)) {
2000 $flat_sum{$e->[2]} += $flat_count[$i];
2001 $cum_sum{$e->[2]} += $cum_count[$i];
2004 my $last_inst = $i - 1;
2015 printf("%6s %6s %5d: %s",
2025 printf("%6s %6s %8s: %6s\n",
2028 UnparseAddress($offset, $e->[0]),
2029 CleanDisassembly($e->[3]));
2054 my $last = $nodecount - 1;
2060 $last--;
2079 $output = "| $escaped_dot -Tps2 >$escaped_outfile";
2082 $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - $escaped_outfile";
2084 $output = "| $escaped_dot -Tps2";
2086 $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - -";
2088 # We need to post-process the SVG, so write to a temporary file always.
2090 $output = "| $escaped_dot -Tsvg >$escaped_outfile";
2092 $output = "| $escaped_dot -Tgif";
2139 # Extra cumulative info to print for non-leaves
2149 # make leak-causing nodes more visible (add a background)
2152 # make anti-leak-causing nodes (which almost never occur)
2177 $n = $raw->{$k};
2181 my $dst = $translated[$i-1];
2182 #next if ($src eq $dst); # Avoid self-edges?
2211 # Drop if we are below --edgefraction
2246 printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n",
2309 # --svg: write to standard output.
2323 // http://www.cyberz.org/blog/2009/12/08/svgpan-a-javascript-svg-panzoomdrag-library/
2333 * - Mouse panning
2334 * - Mouse zooming (using the wheel)
2335 * - Object dargging
2339 * - Zooming (while panning) on Safari has still some issues
2354 * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi@itcharm.com>. All rights reserved.
2463 delta = evt.detail / -90; // Mozilla
2474 var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
2498 setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
2503 …setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).mul…
2564 # shortname for all symbols, which is usually fine, but sometimes --
2565 # such as overloaded functions -- two different fullnames can map to
2579 my $shortname = $symlist->[0];
2580 my $fullname = $symlist->[2];
2581 if ($fullname !~ /<[0-9a-fA-F]+>$/) { # fullname doesn't end in an address
2584 if (defined($shortnames_seen_once->{$shortname}) &&
2585 $shortnames_seen_once->{$shortname} ne $fullname) {
2586 $shortnames_seen_more_than_once->{$shortname} = 1;
2588 $shortnames_seen_once->{$shortname} = $fullname;
2593 my $shortname = $symlist->[0];
2594 my $fullname = $symlist->[2];
2596 # store in the map if $symlist->[1] is in that list. Saves space.
2597 next if defined($fullname_to_shortname_map->{$fullname});
2598 if (defined($shortnames_seen_more_than_once->{$shortname})) {
2600 $fullname_to_shortname_map->{$fullname} = "$shortname\@$1";
2641 my $symlist = $symbols->{$a};
2650 for (my $j = $#{$symlist}; $j >= 2; $j -= 3) {
2651 my $func = $symlist->[$j-2];
2652 my $fileline = $symlist->[$j-1];
2653 my $fullfunc = $symlist->[$j];
2654 if (defined($fullname_to_shortname_map->{$fullfunc})) {
2655 $func = $fullname_to_shortname_map->{$fullfunc};
2665 my $caller = ($i > 0) ? $addrs[$i-1] : 0;
2709 return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf");
2713 # Generate pretty-printed form of number
2733 # Alternate pretty-printed form: 0 maps to "."
2743 # Alternate pretty-printed form: 0 maps to ""
2781 my $count = $profile->{$k};
2797 my $count = $profile->{$k};
2806 # If the second-youngest PC on the stack is always the same, returns
2834 if (exists $symbols->{$address}) {
2835 my @localinlinestack = @{$symbols->{$address}};
2836 for (my $i = $#localinlinestack; $i > 0; $i-=3) {
2837 my $file = $localinlinestack[$i-1];
2838 my $fn = $localinlinestack[$i-0];
2868 if (exists $symbols->{$address}) {
2869 my $file = $symbols->{$address}->[1];
2873 $location = $file . ":" . $symbols->{$address}->[0];
2890 my $call = "$source -> $destination";
2909 my $count = $profile->{$k};
2914 if (exists($symbols->{$a})) {
2915 $sym = $symbols->{$a}->[0];
2989 '::do_malloc', # new name -- got moved to an unnamed ns
3000 # The entry to our memory-allocation routines on OS X
3035 # care of by the general 2nd-pc mechanism below.
3049 # If all the second-youngest program counters are the same,
3058 if (exists($symbols->{$second_pc})) {
3059 $second_pc = $symbols->{$second_pc}->[0];
3063 my $count = $profile->{$k};
3075 my $count = $profile->{$k};
3079 if (exists($symbols->{$a})) {
3080 my $func = $symbols->{$a}->[0];
3108 my $count = $profile->{$k};
3114 # To avoid double-counting due to recursion, skip a stack-trace
3133 if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) {
3148 my $count = $profile->{$k};
3152 if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) {
3168 my $count = $profile->{$k};
3173 if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) {
3190 $result += $profile->{$k};
3203 my $v = $A->{$k};
3208 my $v = $B->{$k};
3221 $R->{$k} = $A->{$k};
3225 $R->{$k} = $B->{$k};
3240 $R->{$k} = 1
3244 $R->{$k} = 1
3256 my $v = $A->{$k} - GetEntry($B, $k);
3265 if (!exists($A->{$k})) {
3266 AddEntry($R, $k, 0 - $B->{$k});
3277 if (exists($profile->{$k})) {
3278 return $profile->{$k};
3289 if (!exists($profile->{$k})) {
3290 $profile->{$k} = 0;
3292 $profile->{$k} += $n;
3306 $pcs->{$pc} = 1;
3319 $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
3336 if (-f $profile_name) {
3350 # Split profile URL - matches all non-empty strings, so no test.
3377 $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines
3385 # Gee, curl's -L (--location) option isn't reliable at least
3391 my $command_line = ShellEscape(@URL_FETCHER, "--head", $url);
3394 s/\r//g; # turn windows-looking lines into unix-looking lines
3408 if (join(" ", @fetcher) =~ m/\bcurl -s/) {
3409 push(@fetcher, "--max-time", sprintf("%d", $timeout));
3411 push(@fetcher, sprintf("--deadline=%d", $timeout));
3425 s/\r//g; # turn windows-looking lines into unix-looking lines
3427 if (m/^0x0*([0-9a-f]+)\s+(.+)/) {
3428 $map->{$1} = $2;
3429 } elsif (m/^---/) {
3431 } elsif (m/^([a-z][^=]*)=(.*)$/ ) {
3454 $str =~ s/([^A-Za-z0-9\-_.!~*'()])/ sprintf "%%%02x", ord $1 /eg;
3495 if (join(" ", @URL_FETCHER) =~ m/\bcurl -s/) {
3498 $command_line = ShellEscape(@URL_FETCHER, "-d", "\@$main::tmpfile_sym",
3502 $command_line = (ShellEscape(@URL_FETCHER, "--post", $url)
3524 # PrintSymbolizedProfile), by --, which is illegal in function names.
3526 if (defined($symbol_map->{$shortpc})) {
3527 $fullnames = $symbol_map->{$shortpc};
3532 $symbols->{$pc} = $sym;
3533 foreach my $fullname (split("--", $fullnames)) {
3566 # Missing type specifier defaults to cpu-profile
3585 # For non-CPU profiles, we add a type-extension to
3601 if (! -d $profile_dir) {
3678 if ($level >= ($maxlevel - 1)) {
3689 # Provide a small streaming-read module to handle very large
3690 # cpu-profile files. Stream in chunks along a sliding window.
3692 # endian-ness differences. A slot is one 32-bit or 64-bit word
3693 # (depending on the input profile). We tell endianness and bit-size
3705 unpack_code => "", # N for big-endian, V for little
3706 perl_is_64bit => 1, # matters if profile is 64-bit
3711 $self->{stride} = $main::opt_test_stride;
3714 my $slots = $self->{slots};
3716 read($self->{file}, $str, 8);
3718 # 8 is 32-bit (8 hexadecimal chars); 16 is 64-bit (16 hexadecimal chars).
3721 if (substr($str, 6, 2) eq chr(0)x2) {
3722 $self->{unpack_code} = 'V'; # Little-endian.
3724 $self->{unpack_code} = 'N'; # Big-endian
3728 @$slots = unpack($self->{unpack_code} . "*", $str);
3730 # If we're a 64-bit profile, check if we're a 64-bit-capable
3732 # instead of an int64, losing precision and making all the
3733 # 64-bit addresses wrong. We won't complain yet, but will
3738 $self->{perl_is_64bit} = 0;
3740 read($self->{file}, $str, 8);
3742 # We'd love to use 'Q', but it's a) not universal, b) not endian-proof.
3743 $self->{unpack_code} = 'V'; # Little-endian.
3745 $self->{unpack_code} = 'N'; # Big-endian
3749 my @pair = unpack($self->{unpack_code} . "*", $str);
3756 # Load more data when we access slots->get(X) which is not yet in memory.
3759 my $slots = $self->{slots};
3760 $self->{base} += $#$slots + 1; # skip over data we're replacing
3762 read($self->{file}, $str, $self->{stride});
3763 if ($address_length == 8) { # the 32-bit case
3764 # This is the easy case: unpack provides 32-bit unpacking primitives.
3765 @$slots = unpack($self->{unpack_code} . "*", $str);
3768 my @b32_values = unpack($self->{unpack_code} . "*", $str);
3771 # TODO(csilvers): if this is a 32-bit perl, the math below
3772 # could end up in a too-large int, which perl will promote
3773 # to a double, losing necessary precision. Deal with that.
3776 if ($self->{unpack_code} eq 'N') { # big-endian
3780 if (!$self->{perl_is_64bit} && # check value is exactly represented
3782 ::error("Need a 64-bit perl to process this 64-bit profile.\n");
3790 # Access the i-th long in the file (logically), or -1 at EOF.
3793 my $slots = $self->{slots};
3795 if ($idx < $self->{base}) {
3796 # The only time we expect a reference to $slots[$i - something]
3800 print STDERR "Unexpected look-back reading CPU profile";
3801 return -1; # shrug, don't know what better to return
3802 } elsif ($idx > $self->{base} + $#$slots) {
3803 $self->overflow();
3805 return $slots->[$idx - $self->{base}];
3809 return -1; # unique since slots is supposed to hold unsigned numbers
3818 # lines is the 'header line', which is a profile-specific line that
3823 # For historical reasons, the CPU profile does not contain a text-
3829 # %warn -- emit the rest of this line to stderr, prefixed by 'WARNING:'
3837 seek(PROFILE, -1, 1); # unread the firstchar
3842 $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
3858 if (!(-e $file_name) || !(-r $file_name)) {
3861 # Check if the file contains a symbol-section marker.
3871 return $firstline =~ /^--- *$symbol_marker/;
3876 # $result->{version} Version number of profile file
3877 # $result->{period} Sampling period (in microseconds)
3878 # $result->{profile} Profile object
3879 # $result->{threads} Map of thread IDs to profile objects
3880 # $result->{map} Memory map info from profile
3881 # $result->{pcs} Hash of all PC values seen, key is hex address
3900 # (starting with \0\0\0\0) -- in that case, don't try to read the
3903 binmode PROFILE; # New perls do UTF-8 processing
3910 if ($header =~ m/^--- *$symbol_marker/o) {
3923 if ($header =~ m/^--- *($heap_marker|$growth_marker)/o) {
3924 # Skip "--- ..." line for profile types that have their own headers.
3939 } elsif ($header =~ m/^--- *$contention_marker/o) {
3942 } elsif ($header =~ m/^--- *Stacks:/) {
3945 "condition variable signals as lock contentions.\n";
3948 } elsif ($header =~ m/^--- *$profile_marker/) {
3957 # no ascii header present -- must be a CPU profile
3966 $result->{symbols} = $symbols;
3974 # file, in which case the subtract-one was done when the file
3981 # --raw/http: Always subtract one from pc's, because PrintSymbolizedProfile()
4011 my $slots = CpuProfileStream->new(*PROFILE, $fname);
4013 # Read header. The current header version is a 5-element structure
4020 if ($slots->get(0) != 0 ) {
4023 $i = 2 + $slots->get(1);
4024 $version = $slots->get(2);
4025 $period = $slots->get(3);
4032 while ($slots->get($i) != -1) {
4033 my $n = $slots->get($i++);
4034 my $d = $slots->get($i++);
4035 if ($d > (2**16)) { # TODO(csilvers): what's a reasonable max-stack-depth?
4040 if ($slots->get($i) == 0) {
4049 my $pc = $slots->get($i+$j);
4051 $pc--;
4053 $pcs->{$pc} = 1;
4067 $r->{version} = $version;
4068 $r->{period} = $period;
4069 $r->{profile} = $profile;
4070 $r->{libs} = ParseLibraries($prog, $map, $pcs);
4071 $r->{pcs} = $pcs;
4095 s/\r//g; # turn windows-looking lines into unix-looking lines
4107 s/\r//g; # turn windows-looking lines into unix-looking lines
4125 # Remote-heap version 2
4128 # size X with sampling rate Y is 1 - exp(-X/Y)
4131 my $scale_factor = 1/(1 - exp(-$ratio));
4137 my $scale_factor = 1/(1 - exp(-$ratio));
4142 # Remote-heap version 1
4167 # heap profile: 1246: 8800744 [ 1246: 8800744] @ <heap-url>/266053
4177 # interval is 128KB. Only remote-heap-page profiles are adjusted for
4182 # is 1 - exp(-X/Y)
4184 # heap profile: 1922: 127792360 [ 1922: 127792360] @ <heap-url>_v2/524288
4192 if (defined($6) && ($6 ne '')) {
4193 $type = $6;
4196 # heap-profiler, and either "heap" or "heap_v2" for profiles
4198 # be "growth" for heap-growth profiles. The first is typically
4202 # No need to adjust for the sampling rate with heap-profiler-derived data
4216 # We detect whether or not this is a remote-heap profile by checking
4217 # that the total-allocated stats ($n2,$s2) are exactly the
4218 # same as the in-use stats ($n1,$s1). It is remotely conceivable
4219 # that a non-remote-heap profile may pass this check, but it is hard
4221 # In this case it's so old it's guaranteed to be remote-heap version 1.
4224 # This is likely to be a remote-heap based sample profile
4231 # For remote-heap generated profiles, adjust the counts and sizes to
4236 print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n";
4238 printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n",
4252 s/\r//g; # turn windows-looking lines into unix-looking lines
4258 if (/^--- Memory map:/) {
4277 $r->{version} = "heap";
4278 $r->{period} = 1;
4279 $r->{profile} = $profile;
4280 $r->{libs} = ParseLibraries($prog, $map, $pcs);
4281 $r->{pcs} = $pcs;
4316 if (/^--- Memory map:/) {
4333 # Still in the header, so this is just a per-thread summary.
4337 my ($n1, $s1, $n2, $s2) = ($3, $4, $5, $6);
4343 if (!exists($thread_profiles->{$thread})) {
4344 $thread_profiles->{$thread} = {};
4346 AddEntries($thread_profiles->{$thread}, $pcs,
4353 $r->{version} = "heap";
4354 $r->{period} = 1;
4355 $r->{profile} = $profile;
4356 $r->{threads} = $thread_profiles;
4357 $r->{libs} = ParseLibraries($prog, $map, $pcs);
4358 $r->{pcs} = $pcs;
4385 $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
4414 } elsif ( $line =~ m/^([a-z][^=]*)=(.*)$/ ) {
4447 $r->{version} = 0;
4448 $r->{period} = $sampling_period;
4449 $r->{profile} = $profile;
4450 $r->{libs} = ParseLibraries($prog, $map, $pcs);
4451 $r->{pcs} = $pcs;
4462 my $zeros_needed = $address_length - length($addr);
4491 if (-e $fullpath) {
4510 if (-f "/usr/lib/debug$file") {
4513 } elsif (-f "/usr/lib/debug$file.debug") {
4527 $readelf = qx/eu-readelf -n ${file}/;
4529 …print STDERR "Cannot run eu-readelf. To use --debug-syms-by-id you must be on Linux, with elfutils…
4533 my $buildID = $1 if $readelf =~ /Build ID: ([A-Fa-f0-9]+)/s;
4535 …my $symbolFile = '/usr/lib/debug/.build-id/' . substr($buildID, 0, 2) . '/' . substr($buildID, 2) …
4536 if (-e $symbolFile) {
4560 my $cmd = ShellEscape($obj_tool_map{"objdump"}, "-h", $lib);
4563 s/\r//g; # turn windows-looking lines into unix-looking lines
4566 # For 64-bit objects, VMA and LMA will be 16 hex digits, size and file
4569 if (($#x >= 6) && ($x[1] eq '.text')) {
4583 $r->{size} = $size;
4584 $r->{vma} = $vma;
4585 $r->{file_offset} = $file_offset;
4599 my $command = ShellEscape($obj_tool_map{"otool"}, "-l", $lib);
4605 $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
4635 } elsif ($line =~ /\baddr 0x([0-9a-fA-F]+)/) {
4637 } elsif ($line =~ /\bsize 0x([0-9a-fA-F]+)/) {
4639 } elsif ($line =~ /\boffset ([0-9]+)/) {
4653 $r->{size} = $size;
4654 $r->{vma} = $vma;
4655 $r->{file_offset} = $file_offset;
4661 # obj_tool_map("otool") is only defined if we're in a Mach-O environment
4680 my $h = "[a-f0-9]+";
4693 …if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d…
4695 # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so
4700 $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths
4701 } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) {
4703 # 40000000-40015000: /lib/ld-2.3.2.so
4708 } elsif (($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+)$/i) && ($4 eq $prog)) {
4717 $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths
4723 … # 0x800600000 0x80061a000 26 0 0xfffff800035a0000 r-x 75 33 0x1004 COW NC vnode /libexec/ld-elf.s
4724 # o.1 NCH -1
4725 …elsif ($l =~ /^(0x$h)\s(0x$h)\s\d+\s\d+\s0x$h\sr-x\s\d+\s\d+\s0x\d+\s(COW|NCO)\s(NC|NNC)\svnode\s(…
4740 # Check for pre-relocated libraries, which use pre-relocated symbol tables
4748 my $vma_offset = AddressSub($text->{vma}, $text->{file_offset});
4761 my $start = $text->{vma};
4762 my $finish = AddressAdd($start, $text->{size});
4783 # Run jeprof --test for unit test if this is changed.
4795 # Do the addition in 7-nibble chunks to trivialize carry handling.
4801 my $a1 = substr($addr1,-7);
4802 $addr1 = substr($addr1,0,-7);
4803 my $a2 = substr($addr2,-7);
4804 $addr2 = substr($addr2,0,-7);
4809 $sum -= 0x10000000;
4813 $a1 = substr($addr1,-7);
4814 $addr1 = substr($addr1,0,-7);
4815 $a2 = substr($addr2,-7);
4816 $addr2 = substr($addr2,0,-7);
4821 $sum -= 0x10000000;
4826 if ($sum > 0xff) { $sum -= 0x100; }
4837 # Run jeprof --test for unit test if this is changed.
4845 $diff = (hex($addr1)-hex($addr2)) % (0x10000000 * 16);
4849 # Do the addition in 7-nibble chunks to trivialize borrow handling.
4850 # if ($main::opt_debug) { print STDERR "AddressSub $addr1 - $addr2 = "; }
4852 my $a1 = hex(substr($addr1,-7));
4853 $addr1 = substr($addr1,0,-7);
4854 my $a2 = hex(substr($addr2,-7));
4855 $addr2 = substr($addr2,0,-7);
4861 $diff = $a1 - $a2;
4864 $a1 = hex(substr($addr1,-7));
4865 $addr1 = substr($addr1,0,-7);
4866 $a2 = hex(substr($addr2,-7)) + $b;
4867 $addr2 = substr($addr2,0,-7);
4873 $diff = $a1 - $a2;
4879 $diff = $a1 - $a2;
4889 # Run jeprof --test for unit test if this is changed.
4900 # Do the addition in 7-nibble chunks to trivialize carry handling.
4907 my $a1 = substr($addr,-7);
4908 $addr = substr($addr,0,-7);
4919 $a1 = substr($addr,-7);
4920 $addr = substr($addr,0,-7);
4932 if ($sum > 0xff) { $sum -= 0x100; }
4954 my @pcs = (sort { $a cmp $b } keys(%{$pcset})); # pcset is 0-extended strings
4955 foreach my $lib (sort {$b->[1] cmp $a->[1]} @{$libs}) {
4956 my $libname = $lib->[0];
4957 my $start = $lib->[1];
4958 my $finish = $lib->[2];
4959 my $offset = $lib->[3];
4972 $finish_pc_index--) {
4973 last if $pcs[$finish_pc_index - 1] le $finish;
4977 $start_pc_index--) {
4978 last if $pcs[$start_pc_index - 1] lt $start;
4983 $finish_pc_index - $start_pc_index);
5005 my $cmd = ShellEscape($addr2line, "-f", "-C", "-e", $image);
5008 $cmd = ShellEscape($addr2line, "--demangle", "-f", "-C", "-e", $image);
5013 if (system(ShellEscape($addr2line, "--help") . " >$dev_null 2>&1") != 0) {
5018 # "addr2line -i" can produce a variable number of lines per input
5028 # Only add " -i" to addr2line if the binary supports it.
5029 # addr2line --help returns 0, but not if it sees an unknown flag first.
5030 if (system("$cmd -i --help >$dev_null 2>&1") == 0) {
5031 $cmd .= " -i";
5033 $sep_address = undef; # no need for sep_address if we don't support -i
5038 # that we can reliably detect the end of inlined function list
5040 if ($debug) { print("---- $image ---\n"); }
5043 if ($debug) { printf STDERR ("%s\n", $pclist->[$i]); }
5044 printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
5051 print("----\n");
5053 print("----\n");
5055 print("----\n");
5075 $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths
5077 my $pcstr = $pclist->[$count];
5079 my $nms = $nm_symbols->{$pcstr};
5083 $function = $nms->[0];
5084 $fullfunction = $nms->[2];
5092 # (nm) version of the routine-name. TODO(csilvers): this won't
5095 if ($nms->[2] =~ m/^\Q$function\E/) { # sanity check it's the right fn
5096 $function = $nms->[0];
5097 $fullfunction = $nms->[2];
5104 my $sym = $symbols->{$pcstr};
5107 $symbols->{$pcstr} = $sym;
5133 my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] }
5140 $symbols->{$pc} = [$pcstr, "?", $pcstr];
5152 while (($index < $#names) && ($mpc ge $symbol_table->{$fullname}->[1])){
5157 if ($mpc lt $symbol_table->{$fullname}->[1]) {
5158 $symbols->{$pc} = [$name, "?", $fullname];
5161 $symbols->{$pc} = [$pcstr, "?", $pcstr];
5204 # 32-bit or ELF 64-bit executable file. The location of the tools
5206 # 1) --tools option, if set
5214 (-e $prog_file) || error("$prog_file does not exist.\n");
5217 if (-e "/usr/bin/file") {
5220 $file_type = `/usr/bin/file -L $escaped_prog_file 2>$dev_null ||
5228 if ($file_type =~ /64-bit/) {
5229 # Change $address_length to 16 if the program file is ELF 64-bit.
5230 # We can't detect this from many (most?) heap or lock contention
5232 # memory even for 64-bit programs.
5239 # Windows-style PDB executables. It should live in the path, or
5241 $obj_tool_map{"nm_pdb"} = "nm-pdb";
5242 $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb";
5245 if ($file_type =~ /Mach-O/) {
5246 # OS X uses otool to examine Mach-O files, rather than objdump.
5258 # Returns the path of a caller-specified object tool. If --tools or
5266 # --tools (or $JEPROF_TOOLS) is a comma separated list, where each
5275 # TODO(csilvers): sanity-check that $path exists? Hard if it's relative.
5279 if (-x $prefix . $tool) {
5286 "--tools (or \$JEPROF_TOOLS) '$tools'\n");
5293 if (-x "$dirname$tool") {
5307 if ($word =~ m![^a-zA-Z0-9/.,_=-]!) { # check for anything not in whitelist
5351 # procedure name to a two-element vector of [start address, end address]
5353 my $escaped_nm_command = shift; # shell-escaped
5361 s/\r//g; # turn windows-looking lines into unix-looking lines
5362 if (m/^\s*([0-9a-f]+) (.) (..*)/) {
5368 # one is a zero-length variable (like __start_google_malloc) or
5371 # actual symbol, which in nm-speak has type "T". The logic
5378 # item in the queue, which we do whenever we see a 'T' entry --
5402 $symbol_table->{$routine} = [HexExtend($last_start),
5421 $symbol_table->{$routine} = [HexExtend($last_start),
5429 # name to a two-element vector of [start address, end address].
5436 # around an obnoxious bug in our probing of nm -f behavior.
5437 # "nm -f $image" is supposed to fail on GNU nm, but if:
5442 # then "nm -f $image" succeeds because -f only looks at the first letter of
5446 # This regex makes sure that $image starts with . or /, forcing the -f
5460 # binary doesn't support --demangle. In addition, for OS X we need
5461 # to use the -f flag to get 'flat' nm output (otherwise we don't sort
5462 # properly and get incorrect results). Unfortunately, GNU nm uses -f
5464 # --demangle and -f.
5468 if (system(ShellEscape($nm, "--demangle", $image) . $to_devnull) == 0) {
5469 # In this mode, we do "nm --demangle <foo>"
5470 $demangle_flag = "--demangle";
5477 if (system(ShellEscape($nm, "-f", $image) . $to_devnull) == 0) {
5478 $flatten_flag = "-f";
5482 # -D to at least get *exported* symbols. If we can't use --demangle,
5484 my @nm_commands = (ShellEscape($nm, "-n", $flatten_flag, $demangle_flag,
5486 ShellEscape($nm, "-D", "-n", $flatten_flag, $demangle_flag,
5488 # 6nm is for Go binaries
5489 ShellEscape("6nm", "$image") . " 2>$dev_null | sort",
5492 # If the executable is an MS Windows PDB-format executable, we'll
5494 # want to use both unix nm and windows-specific nm_pdb, since
5495 # PDB-format executables can apparently include dwarf .o files.
5498 ShellEscape($obj_tool_map{"nm_pdb"}, "--demangle", $image)
5511 # The test vectors for AddressAdd/Sub/Inc are 8-16-nibble hex strings.
5530 # First a few 8-nibble addresses. Note that this implementation uses
5536 my $sum = AddressAdd ($row->[0], $row->[1]);
5537 if ($sum ne $row->[2]) {
5539 $row->[0], $row->[1], $row->[2];
5545 printf STDERR "AddressAdd 32-bit tests: %d passes, %d failures\n",
5551 # Now 16-nibble addresses.
5555 my $sum = AddressAdd (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
5556 my $expected = join '', (split '_',$row->[2]);
5557 if ($sum ne CanonicalHex($row->[2])) {
5559 $row->[0], $row->[1], $row->[2];
5565 printf STDERR "AddressAdd 64-bit tests: %d passes, %d failures\n",
5582 # First a few 8-nibble addresses. Note that this implementation uses
5588 my $sum = AddressSub ($row->[0], $row->[1]);
5589 if ($sum ne $row->[3]) {
5590 printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
5591 $row->[0], $row->[1], $row->[3];
5597 printf STDERR "AddressSub 32-bit tests: %d passes, %d failures\n",
5603 # Now 16-nibble addresses.
5607 my $sum = AddressSub (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
5608 if ($sum ne CanonicalHex($row->[3])) {
5609 printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
5610 $row->[0], $row->[1], $row->[3];
5616 printf STDERR "AddressSub 64-bit tests: %d passes, %d failures\n",
5633 # First a few 8-nibble addresses. Note that this implementation uses
5639 my $sum = AddressInc ($row->[0]);
5640 if ($sum ne $row->[4]) {
5642 $row->[0], $row->[4];
5648 printf STDERR "AddressInc 32-bit tests: %d passes, %d failures\n",
5654 # Now 16-nibble addresses.
5658 my $sum = AddressInc (CanonicalHex($row->[0]));
5659 if ($sum ne CanonicalHex($row->[4])) {
5661 $row->[0], $row->[4];
5667 printf STDERR "AddressInc 64-bit tests: %d passes, %d failures\n",
5676 # Currently just the address add/subtract/increment routines for 64-bit.
5680 # This is a list of tuples [a, b, a+b, a-b, a+1]
5689 # The implementation handles data in 7-nibble chunks, so those are the