Skip to content

Instantly share code, notes, and snippets.

@AshwinJay
Created March 2, 2011 23:05
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AshwinJay/851961 to your computer and use it in GitHub Desktop.
Save AshwinJay/851961 to your computer and use it in GitHub Desktop.
JPMP (Java's Poor Man's Profiler) [corrected]
# Original version: http://blog.tsunanet.net/2010/08/jpmp-javas-poor-mans-profiler.html
# Usage: ./jpmp.sh <pid> <num-samples> <sleep-time-between-samples>
#!/bin/bash
pid=$1
nsamples=$2
sleeptime=$3
for x in $(seq 1 $nsamples)
do
jstack $pid
sleep $sleeptime
done | \
awk 'BEGIN { s = "" } \
/^"/ { if (s) print s; s = "" } \
/^ at / { sub(/\([^)]*\)?$/, "", $2); sub(/^java/, "j", $2); if (s) s = s "," $2; else s = $2 } \
END { if(s) print s }' | \
sort | uniq -c | sort -rnk1
BEGIN { s = "" } \
$1 == "Stack" && $2 =="Trace" { if (s) print s; s = "" } \
$1 == "at" { sub(/\([^)]*\)?$/, "", $2); sub(/^java/, "j", $2); if (s) s = s "," $2; else s = $2 } \
END { if(s) print s }
@REM Get Busybox for Win32 from https://github.com/pclouds/busybox-w32
@ECHO OFF
busybox awk -f jpmp_strace.awk < %1 | busybox sort | busybox uniq -c | busybox sort -rnk1
BEGIN { s = "" } /^"/ { if (s) print s; s = "" } /^ at / { sub(/\([^)]*\)?$/, "", $2); sub(/^java/, "j", $2); if (s) s = s "," $2; else s = $2 } END { if(s) print s }
@AshwinJay
Copy link
Author

@AshwinJay
Copy link
Author

For some JVM versions where the StackTrace format is different like this, you have to fiddle with the awk matchers

@shrijeet
Copy link

shrijeet commented Nov 1, 2011

I was bitten by a setting in my vim, I had all tabs converted to spaces. The jstack output has 'at' symbol preceded by a tab. So the regex '^ at' was not working for me. Thanks Ashwin.

@fuyou001
Copy link

fuyou001 commented Mar 4, 2014

I can't get result :
➜ performance pgrep java
837
3002
➜ performance sh jpmp.sh 3002 5 2
➜ performance
the code is :

!/bin/bash

pid=$1
nsamples=$2
sleeptime=$3

for x in $(seq 1 $nsamples)
do
jstack $pid
sleep $sleeptime
done |
awk 'BEGIN { s = "" }
/^"/ { if (s) print s; s = "" }
/^ at / { sub(/([^)]*)?$/, "", $2); sub(/^java/, "j", $2); if (s) s = s "," $2; else s = $2 }
END { if(s) print s }' |
sort | uniq -c | sort -rnk1

@AshwinJay
Copy link
Author

Works against DropWizard's (0.7.1) admin endpoint

(http://host:adminPort/threads)

# Original version: http://blog.tsunanet.net/2010/08/jpmp-javas-poor-mans-profiler.html

# Usage: ./jpmp.sh <host> <port> <num-samples> <sleep-time-between-samples>

#!/bin/bash
host=$1
port=$2
nsamples=$3
sleeptime=$4

# First line flushes previous accummulated string when it sees beginning of a new stacktrace
# Second removes all lines in the trace not starting with "<space>+at" like "  - locked xx yy"
# Third trims and captures the actual method call

for x in $(seq 1 $nsamples)
  do
    curl -s http://$host:$port/threads
    sleep $sleeptime
  done | \
awk 'BEGIN { s = "" } \
/^[^ ]/ { split($0, a, "state=") ; if (s) print s; s = a[2] } \
/^[ \t]+(\?!at)/ { if (s) print s; s = "" } \
/^[ \t]+at/ { sub(/^[ \t]+/, "", $0); sub(/[ \t]+$/, "", $0); if (s) s = s "#     " $0; else s = $0 } \
END { if(s) print s }' | \
sort | uniq -c | sort -rnk1 | tr '#' '\n'

Variation

curl http://host:adminPort/threads | jpmp.sh

#!/bin/bash

awk 'BEGIN { s = "" } \
/^[^ ]/ { split($0, a, "state=") ; if (s) print s; s = a[2] } \
/^[ \t]+(\?!at)/ { if (s) print s; s = "" } \
/^[ \t]+at/ { sub(/^[ \t]+/, "", $0); sub(/[ \t]+$/, "", $0); if (s) s = s "#     " $0; else s = $0 } \
END { if(s) print s }' | \
sort | uniq -c | sort -rnk1 | tr '#' '\n'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment