@@ -102,6 +102,20 @@ logAndCat() {
102102 cat
103103}
104104
105+ # Bash RegEx to check floating point numbers from user input
106+ # https://stackoverflow.com/questions/13790763
107+ isNonNegativeFloatNumber () {
108+ [[ " $1 " =~ ^[+]? [0-9]+\. ? [0-9]* $ ]]
109+ }
110+
111+ isNaturalNumber () {
112+ [[ " $1 " =~ ^[+]? [0-9]+$ ]]
113+ }
114+
115+ isNaturalNumberList () {
116+ [[ " $1 " =~ ^([0-9]+)(,[0-9]+)* $ ]]
117+ }
118+
105119# print calling(quoted) command line which is able to copy and paste to rerun safely
106120#
107121# How to get the complete calling command of a BASH script from inside the script (not just the arguments)
@@ -139,7 +153,8 @@ Example:
139153
140154Output control:
141155 -p, --pid <java pid(s)> find out the highest cpu consumed threads from
142- the specified java process. support pid list(eg: 42,47).
156+ the specified java process.
157+ support pid list(eg: 42,47).
143158 default from all java process.
144159 -c, --count <num> set the thread count to show, default is 5.
145160 set count 0 to show all threads.
@@ -156,24 +171,19 @@ Output control:
156171
157172jstack control:
158173 -s, --jstack-path <path> specifies the path of jstack command.
159- -F, --force set jstack to force a thread dump. use when jstack
160- does not respond (process is hung).
161- -m, --mix-native-frames set jstack to print both java and native frames
162- (mixed mode).
174+ -F, --force set jstack to force a thread dump.
175+ use when jstack does not respond (process is hung).
176+ -m, --mix-native-frames set jstack to print both java and
177+ native frames (mixed mode).
163178 -l, --lock-info set jstack with long listing.
164179 prints additional information about locks.
165180
166181CPU usage calculation control:
167- -d, --top-delay specifies the delay between top samples.
168- default is 0.5 (second). get thread cpu percentage
169- during this delay interval.
170- more info see top -d option. eg: -d 1 (1 second).
171- -P, --use-ps use ps command to find busy thread(cpu usage)
172- instead of top command.
173- default use top command, because cpu usage of
174- ps command is expressed as the percentage of
175- time spent running during the *entire lifetime*
176- of a process, this is not ideal in general.
182+ -i, --cpu-sample-interval specifies the delay between cpu samples to get
183+ thread cpu usage percentage during this interval.
184+ default is 0.5 (second).
185+ set interval 0 to get the percentage of time spent
186+ running during the *entire lifetime* of a process.
177187
178188Miscellaneous:
179189 -h, --help display this help and exit.
@@ -202,8 +212,8 @@ uname | grep '^Linux' -q || die "$PROG only support Linux, not support $(uname)
202212# readonly declaration make exit code of assignment to be always 0, aka. the exit code of `getopt` in subshell is discarded.
203213# tested on bash 4.2.46
204214ARGS=$(
205- getopt -n " $PROG " -a -o c:p:a:s:S:Pd:FmlhV \
206- -l count:,pid:,append-file:,jstack-path:,store-dir:,use-ps,top-delay:,force,mix-native-frames,lock-info,help,version \
215+ getopt -n " $PROG " -a -o c:p:a:s:S:i: Pd:FmlhV \
216+ -l count:,pid:,append-file:,jstack-path:,store-dir:,cpu-sample-interval:, use-ps,top-delay:,force,mix-native-frames,lock-info,help,version \
207217 -- " $@ "
208218) || {
209219 echo
@@ -212,8 +222,7 @@ ARGS=$(
212222eval set -- " ${ARGS} "
213223
214224count=5
215- use_ps=false
216- top_delay=0.5
225+ cpu_sample_interval=0.5
217226
218227while true ; do
219228 case " $1 " in
@@ -237,12 +246,14 @@ while true; do
237246 store_dir=" $2 "
238247 shift 2
239248 ;;
249+ # support the option name -P,--use-ps for compatibility
240250 -P | --use-ps)
241- use_ps=true
251+ cpu_sample_interval=0
242252 shift
243253 ;;
244- -d | --top-delay)
245- top_delay=" $2 "
254+ # support the option name -d,--top-delay for compatibility
255+ -i | --cpu-sample-interval | -d | --top-delay)
256+ cpu_sample_interval=" $2 "
246257 shift 2
247258 ;;
248259 -F | --force)
@@ -271,16 +282,14 @@ while true; do
271282done
272283
273284update_delay=${1:- 0}
274- # Bash RegEx to check floating point numbers from user input
275- # https://stackoverflow.com/questions/13790763
276- [[ " $update_delay " =~ ^[+]? [0-9]+\. ? [0-9]* $ ]] || die " update delay($update_delay ) is not a positive float number!"
285+ isNonNegativeFloatNumber " $update_delay " || die " update delay($update_delay ) is not a non-negative float number!"
277286
278287[ -z " $1 " ] && update_count=1 || update_count=${2:- 0}
279- [[ " $update_count " =~ ^[+] ? [0-9]+$ ]] || die " update count($update_count ) is not a natural number!"
288+ isNaturalNumber " $update_count " || die " update count($update_count ) is not a natural number!"
280289
281290if [ -n " $pid_list " ]; then
282291 pid_list=" ${pid_list// [[:space:]]/ } " # delete white space
283- [[ " $pid_list " =~ ^([0-9]+)(,[0-9]+) * $ ]] || die " pid(s)($pid_list ) is illegal! example: 42 or 42,99,67"
292+ isNaturalNumberList " $pid_list " || die " pid(s)($pid_list ) is illegal! example: 42 or 42,99,67"
284293fi
285294
286295# check the directory of append-file(-a) mode, create if not exist.
@@ -309,6 +318,8 @@ if [ -n "$store_dir" ]; then
309318 fi
310319fi
311320
321+ isNonNegativeFloatNumber " $cpu_sample_interval " || die " cpu sample interval($cpu_sample_interval ) is not a non-negative float number!"
322+
312323# ###############################################################################
313324# search/check the existence of jstack command
314325#
@@ -383,6 +394,12 @@ __die_when_no_java_process_found() {
383394
384395# output field: pid, thread id(lwp), pcpu, user
385396# order by pcpu(percentage of cpu usage)
397+ #
398+ # NOTE:
399+ # use ps command to find busy thread(cpu usage)
400+ # cpu usage of ps command is expressed as
401+ # the percentage of time spent running during the *entire lifetime* of a process,
402+ # this is not ideal in general.
386403findBusyJavaThreadsByPs () {
387404 # 1. sort by %cpu by ps option `--sort -pcpu`
388405 # 2. use wide output(unlimited width) by ps option `-ww`
@@ -430,7 +447,7 @@ __top_threadId_cpu() {
430447 # and use second time update data to get cpu percentage of thread in 0.5 second interval
431448 # 4. top v3.3, there is 1 black line between 2 update;
432449 # but top v3.2, there is 2 blank lines between 2 update!
433- local -a top_cmd_line=(top -H -b -d " $top_delay " -n 2 -p " $java_pid_list " )
450+ local -a top_cmd_line=(top -H -b -d " $cpu_sample_interval " -n 2 -p " $java_pid_list " )
434451 # DO NOT combine var ps_out declaration and assignment, because its value is supplied by subshell.
435452 local top_out
436453 top_out=$( HOME=" $tmp_store_dir " " ${top_cmd_line[@]} " )
@@ -556,7 +573,7 @@ main() {
556573 tee ${append_file: +-a " $append_file " } ${store_dir: +-a " ${store_file_prefix} $PROG " } > /dev/null
557574 (( update_count != 1 )) && headInfo
558575
559- if $use_ps ; then
576+ if [ " $cpu_sample_interval " == 0 ] ; then
560577 findBusyJavaThreadsByPs
561578 else
562579 findBusyJavaThreadsByTop
0 commit comments