stackcollapse-jstack.pl 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #!/usr/bin/perl -w
  2. #
  3. # stackcollapse-jstack.pl collapse jstack samples into single lines.
  4. #
  5. # Parses Java stacks generated by jstack(1) and outputs RUNNABLE stacks as
  6. # single lines, with methods separated by semicolons, and then a space and an
  7. # occurrence count. This also filters some other "RUNNABLE" states that we
  8. # know are probably not running, such as epollWait. For use with flamegraph.pl.
  9. #
  10. # You want this to process the output of at least 100 jstack(1)s. ie, run it
  11. # 100 times with a sleep interval, and append to a file. This is really a poor
  12. # man's Java profiler, due to the overheads of jstack(1), and how it isn't
  13. # capturing stacks asynchronously. For a better profiler, see:
  14. # http://www.brendangregg.com/blog/2014-06-12/java-flame-graphs.html
  15. #
  16. # USAGE: ./stackcollapse-jstack.pl infile > outfile
  17. #
  18. # Example input:
  19. #
  20. # "MyProg" #273 daemon prio=9 os_prio=0 tid=0x00007f273c038800 nid=0xe3c runnable [0x00007f28a30f2000]
  21. # java.lang.Thread.State: RUNNABLE
  22. # at java.net.SocketInputStream.socketRead0(Native Method)
  23. # at java.net.SocketInputStream.read(SocketInputStream.java:121)
  24. # ...
  25. # at java.lang.Thread.run(Thread.java:744)
  26. #
  27. # Example output:
  28. #
  29. # MyProg;java.lang.Thread.run;java.net.SocketInputStream.read;java.net.SocketInputStream.socketRead0 1
  30. #
  31. # Input may be created and processed using:
  32. #
  33. # i=0; while (( i++ < 200 )); do jstack PID >> out.jstacks; sleep 10; done
  34. # cat out.jstacks | ./stackcollapse-jstack.pl > out.stacks-folded
  35. #
  36. # WARNING: jstack(1) incurs overheads. Test before use, or use a real profiler.
  37. #
  38. # Copyright 2014 Brendan Gregg. All rights reserved.
  39. #
  40. # This program is free software; you can redistribute it and/or
  41. # modify it under the terms of the GNU General Public License
  42. # as published by the Free Software Foundation; either version 2
  43. # of the License, or (at your option) any later version.
  44. #
  45. # This program is distributed in the hope that it will be useful,
  46. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  47. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  48. # GNU General Public License for more details.
  49. #
  50. # You should have received a copy of the GNU General Public License
  51. # along with this program; if not, write to the Free Software Foundation,
  52. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  53. #
  54. # (http://www.gnu.org/copyleft/gpl.html)
  55. #
  56. # 14-Sep-2014 Brendan Gregg Created this.
  57. use strict;
  58. use Getopt::Long;
  59. # tunables
  60. my $include_tname = 1; # include thread names in stacks
  61. my $include_tid = 0; # include thread IDs in stacks
  62. my $shorten_pkgs = 0; # shorten package names
  63. my $help = 0;
  64. sub usage {
  65. die <<USAGE_END;
  66. USAGE: $0 [options] infile > outfile\n
  67. --include-tname
  68. --no-include-tname # include/omit thread names in stacks (default: include)
  69. --include-tid
  70. --no-include-tid # include/omit thread IDs in stacks (default: omit)
  71. --shorten-pkgs
  72. --no-shorten-pkgs # (don't) shorten package names (default: don't shorten)
  73. eg,
  74. $0 --no-include-tname stacks.txt > collapsed.txt
  75. USAGE_END
  76. }
  77. GetOptions(
  78. 'include-tname!' => \$include_tname,
  79. 'include-tid!' => \$include_tid,
  80. 'shorten-pkgs!' => \$shorten_pkgs,
  81. 'help' => \$help,
  82. ) or usage();
  83. $help && usage();
  84. # internals
  85. my %collapsed;
  86. sub remember_stack {
  87. my ($stack, $count) = @_;
  88. $collapsed{$stack} += $count;
  89. }
  90. my @stack;
  91. my $tname;
  92. my $state = "?";
  93. foreach (<>) {
  94. next if m/^#/;
  95. chomp;
  96. if (m/^$/) {
  97. # only include RUNNABLE states
  98. goto clear if $state ne "RUNNABLE";
  99. # save stack
  100. if (defined $tname) { unshift @stack, $tname; }
  101. remember_stack(join(";", @stack), 1) if @stack;
  102. clear:
  103. undef @stack;
  104. undef $tname;
  105. $state = "?";
  106. next;
  107. }
  108. #
  109. # While parsing jstack output, the $state variable may be altered from
  110. # RUNNABLE to other states. This causes the stacks to be filtered later,
  111. # since only RUNNABLE stacks are included.
  112. #
  113. if (/^"([^"]*)/) {
  114. my $name = $1;
  115. if ($include_tname) {
  116. $tname = $name;
  117. unless ($include_tid) {
  118. $tname =~ s/-\d+$//;
  119. }
  120. }
  121. # set state for various background threads
  122. $state = "BACKGROUND" if $name =~ /C. CompilerThread/;
  123. $state = "BACKGROUND" if $name =~ /Signal Dispatcher/;
  124. $state = "BACKGROUND" if $name =~ /Service Thread/;
  125. $state = "BACKGROUND" if $name =~ /Attach Listener/;
  126. } elsif (/java.lang.Thread.State: (\S+)/) {
  127. $state = $1 if $state eq "?";
  128. } elsif (/^\s*at ([^\(]*)/) {
  129. my $func = $1;
  130. if ($shorten_pkgs) {
  131. my ($pkgs, $clsFunc) = ( $func =~ m/(.*\.)([^.]+\.[^.]+)$/ );
  132. $pkgs =~ s/(\w)\w*/$1/g;
  133. $func = $pkgs . $clsFunc;
  134. }
  135. unshift @stack, $func;
  136. # fix state for epollWait
  137. $state = "WAITING" if $func =~ /epollWait/;
  138. $state = "WAITING" if $func =~ /EPoll\.wait/;
  139. # fix state for various networking functions
  140. $state = "NETWORK" if $func =~ /socketAccept$/;
  141. $state = "NETWORK" if $func =~ /Socket.*accept0$/;
  142. $state = "NETWORK" if $func =~ /socketRead0$/;
  143. } elsif (/^\s*-/ or /^2\d\d\d-/ or /^Full thread dump/ or
  144. /^JNI global references:/) {
  145. # skip these info lines
  146. next;
  147. } else {
  148. warn "Unrecognized line: $_";
  149. }
  150. }
  151. foreach my $k (sort { $a cmp $b } keys %collapsed) {
  152. print "$k $collapsed{$k}\n";
  153. }