mirror of
https://github.com/libgit2/libgit2.git
synced 2026-01-25 11:06:32 +00:00
Introduce `--profile` support to the benchmark helper script, which will invoke `perf` on Linux. Additionally, add a `--flamegraph` output option based on that.
177 lines
5.1 KiB
Perl
Executable File
177 lines
5.1 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
#
|
|
# stackcollapse-jstack.pl collapse jstack samples into single lines.
|
|
#
|
|
# Parses Java stacks generated by jstack(1) and outputs RUNNABLE stacks as
|
|
# single lines, with methods separated by semicolons, and then a space and an
|
|
# occurrence count. This also filters some other "RUNNABLE" states that we
|
|
# know are probably not running, such as epollWait. For use with flamegraph.pl.
|
|
#
|
|
# You want this to process the output of at least 100 jstack(1)s. ie, run it
|
|
# 100 times with a sleep interval, and append to a file. This is really a poor
|
|
# man's Java profiler, due to the overheads of jstack(1), and how it isn't
|
|
# capturing stacks asynchronously. For a better profiler, see:
|
|
# http://www.brendangregg.com/blog/2014-06-12/java-flame-graphs.html
|
|
#
|
|
# USAGE: ./stackcollapse-jstack.pl infile > outfile
|
|
#
|
|
# Example input:
|
|
#
|
|
# "MyProg" #273 daemon prio=9 os_prio=0 tid=0x00007f273c038800 nid=0xe3c runnable [0x00007f28a30f2000]
|
|
# java.lang.Thread.State: RUNNABLE
|
|
# at java.net.SocketInputStream.socketRead0(Native Method)
|
|
# at java.net.SocketInputStream.read(SocketInputStream.java:121)
|
|
# ...
|
|
# at java.lang.Thread.run(Thread.java:744)
|
|
#
|
|
# Example output:
|
|
#
|
|
# MyProg;java.lang.Thread.run;java.net.SocketInputStream.read;java.net.SocketInputStream.socketRead0 1
|
|
#
|
|
# Input may be created and processed using:
|
|
#
|
|
# i=0; while (( i++ < 200 )); do jstack PID >> out.jstacks; sleep 10; done
|
|
# cat out.jstacks | ./stackcollapse-jstack.pl > out.stacks-folded
|
|
#
|
|
# WARNING: jstack(1) incurs overheads. Test before use, or use a real profiler.
|
|
#
|
|
# Copyright 2014 Brendan Gregg. All rights reserved.
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
#
|
|
# (http://www.gnu.org/copyleft/gpl.html)
|
|
#
|
|
# 14-Sep-2014 Brendan Gregg Created this.
|
|
|
|
use strict;
|
|
|
|
use Getopt::Long;
|
|
|
|
# tunables
|
|
my $include_tname = 1; # include thread names in stacks
|
|
my $include_tid = 0; # include thread IDs in stacks
|
|
my $shorten_pkgs = 0; # shorten package names
|
|
my $help = 0;
|
|
|
|
sub usage {
|
|
die <<USAGE_END;
|
|
USAGE: $0 [options] infile > outfile\n
|
|
--include-tname
|
|
--no-include-tname # include/omit thread names in stacks (default: include)
|
|
--include-tid
|
|
--no-include-tid # include/omit thread IDs in stacks (default: omit)
|
|
--shorten-pkgs
|
|
--no-shorten-pkgs # (don't) shorten package names (default: don't shorten)
|
|
|
|
eg,
|
|
$0 --no-include-tname stacks.txt > collapsed.txt
|
|
USAGE_END
|
|
}
|
|
|
|
GetOptions(
|
|
'include-tname!' => \$include_tname,
|
|
'include-tid!' => \$include_tid,
|
|
'shorten-pkgs!' => \$shorten_pkgs,
|
|
'help' => \$help,
|
|
) or usage();
|
|
$help && usage();
|
|
|
|
|
|
# internals
|
|
my %collapsed;
|
|
|
|
sub remember_stack {
|
|
my ($stack, $count) = @_;
|
|
$collapsed{$stack} += $count;
|
|
}
|
|
|
|
my @stack;
|
|
my $tname;
|
|
my $state = "?";
|
|
|
|
foreach (<>) {
|
|
next if m/^#/;
|
|
chomp;
|
|
|
|
if (m/^$/) {
|
|
# only include RUNNABLE states
|
|
goto clear if $state ne "RUNNABLE";
|
|
|
|
# save stack
|
|
if (defined $tname) { unshift @stack, $tname; }
|
|
remember_stack(join(";", @stack), 1) if @stack;
|
|
clear:
|
|
undef @stack;
|
|
undef $tname;
|
|
$state = "?";
|
|
next;
|
|
}
|
|
|
|
#
|
|
# While parsing jstack output, the $state variable may be altered from
|
|
# RUNNABLE to other states. This causes the stacks to be filtered later,
|
|
# since only RUNNABLE stacks are included.
|
|
#
|
|
|
|
if (/^"([^"]*)/) {
|
|
my $name = $1;
|
|
|
|
if ($include_tname) {
|
|
$tname = $name;
|
|
unless ($include_tid) {
|
|
$tname =~ s/-\d+$//;
|
|
}
|
|
}
|
|
|
|
# set state for various background threads
|
|
$state = "BACKGROUND" if $name =~ /C. CompilerThread/;
|
|
$state = "BACKGROUND" if $name =~ /Signal Dispatcher/;
|
|
$state = "BACKGROUND" if $name =~ /Service Thread/;
|
|
$state = "BACKGROUND" if $name =~ /Attach Listener/;
|
|
|
|
} elsif (/java.lang.Thread.State: (\S+)/) {
|
|
$state = $1 if $state eq "?";
|
|
} elsif (/^\s*at ([^\(]*)/) {
|
|
my $func = $1;
|
|
if ($shorten_pkgs) {
|
|
my ($pkgs, $clsFunc) = ( $func =~ m/(.*\.)([^.]+\.[^.]+)$/ );
|
|
$pkgs =~ s/(\w)\w*/$1/g;
|
|
$func = $pkgs . $clsFunc;
|
|
}
|
|
unshift @stack, $func;
|
|
|
|
# fix state for epollWait
|
|
$state = "WAITING" if $func =~ /epollWait/;
|
|
$state = "WAITING" if $func =~ /EPoll\.wait/;
|
|
|
|
|
|
# fix state for various networking functions
|
|
$state = "NETWORK" if $func =~ /socketAccept$/;
|
|
$state = "NETWORK" if $func =~ /Socket.*accept0$/;
|
|
$state = "NETWORK" if $func =~ /socketRead0$/;
|
|
|
|
} elsif (/^\s*-/ or /^2\d\d\d-/ or /^Full thread dump/ or
|
|
/^JNI global references:/) {
|
|
# skip these info lines
|
|
next;
|
|
} else {
|
|
warn "Unrecognized line: $_";
|
|
}
|
|
}
|
|
|
|
foreach my $k (sort { $a cmp $b } keys %collapsed) {
|
|
print "$k $collapsed{$k}\n";
|
|
}
|