forked from giltene/jHiccup
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jHiccup
executable file
·359 lines (334 loc) · 12.6 KB
/
jHiccup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
#!/bin/bash
#
# jHiccup
#
# Written by Gil Tene, and released to the public domain, as explained at
# http://creativecommons.org/publicdomain/zero/1.0/
#
JHICCUP_Version=2.0.5
#
# jHiccup is a platform pause measurement tool, it is meant to observe the
# underlying platform (JVM, OS, HW, etc.) responsiveness while under an
# unrelated application load, and establish a lower bound for the stalls
# the application would experience. It is run as a wrapper around
# other applications so that measurements can be done without any changes
# to application code.
#
# The purpose of jHiccup is to aid application operators and testers in
# characterizing the inherent "platform hiccups" (execution stalls)
# that a Java platform will display when running under load. The hiccups
# measured are NOT stalls caused by the application's code. They are stalls
# caused by the platform (JVM, OS, HW, etc.) that would be visible to and
# affect any application thread running on the platform at the time of the
# stall.It is generally safe to assume that if jHiccup experiences and
# records a certain level of measured platform hiccups, the application
# running on the same JVM platform during that time had experienced
# hiccup/stall effects that are at least as large as the measured level.
#
# jHiccup's measurement works on the simple basis of measuring the time it
# takes an effectively empty workload to perform work (while running alongside
# whatever load the platform is carrying). Hiccup measurements are performed
# by a thread that repeatedly sleeps for a given interval (-r for resolutionMs,
# defaults to 1 msec), and logs the amount of time it took to actually wake up
# each time in a detailed internal hiccup histogram. The assumption is that
# if the measuring thread experienced some delay in waking up, any other thread
# in the system could/would have experienced a similar delay, resulting in
# application stalls.
#
# jHiccup produces a single log file (hiccup.YYMMDD.HHMM.pid.hlog) in Histogram
# log format (see HdrHistogram documentaton for HistogramLogReader for details).
# This log file captures histograms for each logging interval (set
# with -i <reportingIntervalMs>, defaults to 5000 msec)., which can later
# be processed to reconstruct hiccup behavior over an arbitrary portion of the
# log. The -l <logname> can be used to override the log file name.
#
# An associated utlity, jHiccupLogProcessor, generates two log files from this
# log file: a sequential interval log file and a histogram log file.
# The sequential interval log file logs a single %'ile stats line for each
# reporting interval. The histogram log file includes a detailed %'ile histogram
# of the run so far.
# See documentation or help for jHiccupLogProcessor for details.
#
#
# jHiccup can be configured to delay the start of measurement
# (using the -d <startDelayMs> flag, defaults to 30000 msec).
#
# jHiccup will continue to run until the application it is wrapping exists.
#
# Using the -c option (off by default), jHiccup can be configured to launch
# a concurrently executing "control process" that will separately log hiccup
# information of an idle workload running on a separate jvm for the duration
# of the instrumented application run. When selected, the control process log
# file name will match the one used for the preceded application, preceded
# with a "c.".
#
# For convenience in testing, jHiccup can be executed as a simple wrapper for
# java program execution. All it takes is adding the word "jHiccup" in front
# of whatever the java invocation command line is.
#
# For example, if your program were normally executed as:
#
# java <Java args> UsefulProgram -a -b -c
#
# The launch line would become:
#
# jHiccup java <Java args> UsefulProgram -a -b -c
#
# or, for a program that is launch like this:
#
# /usr/bin/java <Java args> -jar UsefulProgram.jar -a -b -c
#
# The launch line would become:
#
# jHiccup /usr/bin/java <Java args> -jar UsefulProgram.jar -a -b -c
#
# or, to override the defaults by making the recording start delay 60 seconds
# and log to hlog, it would become:
#
# jHiccup -d 60000 -l hlog /usr/bin/java <Java args> -jar UsefulProgram.jar -a -b -c
#
# Figure out installed path:
# On Linux, we'd do the following:
# PARSED_SCRIPT=`readlink -f $0`
# INSTALLED_PATH=`dirname $PARSED_SCRIPT`
# But readlink -f doesn't work the same everywhere (e.g. Mac OS). We use this instead:
function readlink_f () { _=`pwd`; cd `dirname $1` && echo `pwd` && cd $_; }
INSTALLED_PATH=$(readlink_f $0)
# Check if running from unpacked distribution archive by assuming jHiccup.jar
# in the same directory as this script. If not, try to search in target/ directory
# (running from the source repository build).
JHICCUP_JAR_FILE=$INSTALLED_PATH/jHiccup.jar
if [ ! -f $JHICCUP_JAR_FILE ] ; then
JHICCUP_JAR_FILE=$INSTALLED_PATH/target/jHiccup.jar
fi
DATE=`date +%y%m%d.%H%M`
#
# Parse original java execution arguments:
#
count=0
JHiccupArgs=
readingJHiccupArgs=0
PARSED_BinJava=
readingJavaBin=1
readingJavaArgs=0
PARSED_JavaArgs=
PARSED_AppArgs=
for var in $@; do
# echo $count: "$var"
if [ $readingJavaBin -eq 1 ] ; then
# Looking for JavaBin. Identify and parse jHiccup args
if [ $readingJHiccupArgs -eq 1 ]; then
# This was marked as an arg to jHiccup
JHiccupArgs="$JHiccupArgs $var"
readingJHiccupArgs=0
elif [ $var = "-v" ]; then
# -v is a flag arg to jHiccup
JHiccupArgs="$JHiccupArgs $var"
elif [ $var = "-0" ]; then
# -0 is a flag arg to jHiccup
JHiccupArgs="$JHiccupArgs $var"
elif [ $var = "-c" ]; then
# -c is a flag arg to jHiccup
JHiccupArgs="$JHiccupArgs $var"
elif [ $var = "-o" ]; then
# -o is a flag arg to jHiccup
JHiccupArgs="$JHiccupArgs $var"
elif [ ${var:0:1} = "-" ]; then
# This is a parameter arg to jHiccup
JHiccupArgs="$JHiccupArgs $var"
readingJHiccupArgs=1
else
# Found JavaBin
PARSED_BinJava="$var"
readingJavaBin=0
readingJavaArgs=1
fi
elif [ $readingJavaArgs -eq 1 ]; then
# Parsing Java args
if [ ${var:0:1} = "-" ]; then
PARSED_JavaArgs="$PARSED_JavaArgs $var"
else
readingJavaArgs=0
PARSED_AppArgs="$var"
fi
else
# Parsing app args
PARSED_AppArgs="$PARSED_AppArgs $var"
fi
let "count = $count + 1"
done
# At this point, we should have valid $PARSED_BinJava, $PARSED_JavaArgs, $PARSED_AppArgs:
#echo PARSED_BinJava = "$PARSED_BinJava"
#echo PARSED_JavaArgs = "$PARSED_JavaArgs"
#echo PARSED_AppArgs = "$PARSED_AppArgs"
#
# Parse jHiccup arguments:
#
JHICCUP_DelayArg=
readingDelayArg=0
JHICCUP_RunTimeArg=
readingRunTimeArg=0
JHICCUP_IntervalArg=
readingIntervalArg=0
JHICCUP_ResolutionArg=
readingResolutionArg=0
JHICCUP_LognameArg=
readingLognnameArg=0
JHICCUP_PidOfProcessToAttacheToArg=
readingPidOfProcessToAttacheToArg=0
verboseOutput=
logFormatCsv=
startTimeAtZero=
JHiccupArgs_parse_error=
JHICCUP_ControlProcessFlag=
for var in $JHiccupArgs; do
if [ $readingDelayArg -eq 1 ]; then
JHICCUP_DelayArg=$var
readingDelayArg=0
elif [ $readingRunTimeArg -eq 1 ]; then
JHICCUP_RunTimeArg=$var
readingRunTimeArg=0
elif [ $readingIntervalArg -eq 1 ]; then
JHICCUP_IntervalArg=$var
readingIntervalArg=0
elif [ $readingResolutionArg -eq 1 ]; then
JHICCUP_ResolutionArg=$var
readingResolutionArg=0
elif [ $readingLognnameArg -eq 1 ]; then
JHICCUP_LognameArg=$var
readingLognnameArg=0
elif [ $readingPidOfProcessToAttacheToArg -eq 1 ]; then
JHICCUP_PidOfProcessToAttacheToArg=$var
readingPidOfProcessToAttacheToArg=0
elif [ $var = "-d" ]; then
readingDelayArg=1
elif [ $var = "-t" ]; then
readingRunTimeArg=1
elif [ $var = "-i" ]; then
readingIntervalArg=1
elif [ $var = "-r" ]; then
readingResolutionArg=1
elif [ $var = "-l" ]; then
readingLognnameArg=1
elif [ $var = "-p" ]; then
readingPidOfProcessToAttacheToArg=1
elif [ $var = "-c" ]; then
JHICCUP_ControlProcessFlag=1
elif [ $var = "-0" ]; then
startTimeAtZero=1
elif [ $var = "-o" ]; then
logFormatCsv=1
elif [ $var = "-v" ]; then
verboseOutput=1
echo jHiccup version $JHICCUP_Version
else
JHiccupArgs_parse_error=1
fi
done
if [ $readingDelayArg -eq 1 ]; then
JHiccupArgs_parse_error=1
elif [ $readingRunTimeArg -eq 1 ]; then
JHiccupArgs_parse_error=1
elif [ $readingIntervalArg -eq 1 ]; then
JHiccupArgs_parse_error=1
elif [ $readingResolutionArg -eq 1 ]; then
JHiccupArgs_parse_error=1
elif [ $readingLognnameArg -eq 1 ]; then
JHiccupArgs_parse_error=1
elif [ $readingPidOfProcessToAttacheToArg -eq 1 ]; then
JHiccupArgs_parse_error=1
fi
# Should not have both a java command and a -p option:
if [ $PARSED_BinJava ]; then
if [ $JHICCUP_PidOfProcessToAttacheToArg ]; then
JHiccupArgs_parse_error=1
fi
fi
if [ $JHiccupArgs_parse_error ]; then
echo $PARSED_SCRIPT $@
echo jHiccup version $JHICCUP_Version
echo "Usage:"
echo " jHiccup [-d startupDelayMsec] [-t runTimeMsec] [-i recordingIntervalMsec] [-l logname]"
echo " [-r sampleResolutionMsec] [-c] [-p pidOfProcessToAttachTo]"
echo " or:"
echo " jHiccup [-d startupDelayMsec] [-t runTimeMsec] [-i recordingIntervalMsec] [-l logname]"
echo " [-r sampleResolutionMsec] [-c] <java command line>"
echo "Where:"
echo " -l logname Sets the log files to <logname> and <logname>.hgrm"
echo " (default <logname> is \"hiccup.yymmdd.hhmm.pid\") "
echo " (replaces occurrences of %pid and %date with appropriate info)"
echo " -o Output log files in CSV format"
echo " -c Concurrently start a control process to record hiccups"
echo " experienced by an Idle load running on a separate jvm"
echo " in log files <logname>.c and <logname>.c.hgrm"
echo " -p pidOfProcessToAttachTo Attach to the process with given pid and inject jHiccup as an agent"
echo " (no default)"
echo " -d startupDelayMsec Sets the delay, in milliseconds before sampling starts"
echo " (default 30000 for non-attach (-p) runs, 0 for attach (-p) runs)"
echo " -t runTimeMsec Limit measurement and logging time"
echo " (default 0, for infinite)"
echo " -0 Start logfile timestamps at 0 (as opposed to JVM uptime at start point)"
echo " (default off)"
echo " -i recordingIntervalMsec Sets the reporting interval in milliseconds"
echo " (default 5000)"
echo " -r sampleResolutionMsec Sets the sampling resolution in milliseconds"
echo " (default 1)"
echo " -v Verbose output"
exit -1
fi
JHICCUP_Options=""
if [ $JHICCUP_DelayArg ]; then
JHICCUP_Options="${JHICCUP_Options}-d $JHICCUP_DelayArg "
fi
if [ $JHICCUP_RunTimeArg ]; then
JHICCUP_Options="${JHICCUP_Options}-t $JHICCUP_RunTimeArg "
fi
if [ $JHICCUP_IntervalArg ]; then
JHICCUP_Options="${JHICCUP_Options}-i $JHICCUP_IntervalArg "
fi
if [ $JHICCUP_ResolutionArg ]; then
JHICCUP_Options="${JHICCUP_Options}-r $JHICCUP_ResolutionArg "
fi
if [ $JHICCUP_LognameArg ]; then
JHICCUP_Options="${JHICCUP_Options}-l $JHICCUP_LognameArg "
fi
if [ $startTimeAtZero ]; then
JHICCUP_Options="${JHICCUP_Options}-0 "
fi
if [ $logFormatCsv ]; then
JHICCUP_Options="${JHICCUP_Options}-o "
fi
if [ $JHICCUP_ControlProcessFlag ]; then
JHICCUP_Options="${JHICCUP_Options}-c "
fi
if [ $verboseOutput ]; then
JHICCUP_Options="${JHICCUP_Options}-v "
fi
# Deal with Windows/cygwin path normalization syntax needs:
# Key Assumption: only cygwin/Windows installations will have a cygpath command...
cygpath -w $JHICCUP_JAR_FILE &> /dev/null
if [ $? -eq 0 ] ; then
# if using cygwin, use valid windows-style classpath
JHICCUP_JAR_FILE=`cygpath -w $JHICCUP_JAR_FILE`
echo Windows path for hiccup jar file is $JHICCUP_JAR_FILE
fi
if [ $JHICCUP_PidOfProcessToAttacheToArg ]; then
JHICCUP_Options="${JHICCUP_Options}-j $JHICCUP_JAR_FILE -p $JHICCUP_PidOfProcessToAttacheToArg "
#
# Prepare and execute attach command:
#
CMD="$JAVA_HOME/bin/java -cp $JAVA_HOME/lib/tools.jar:$JHICCUP_JAR_FILE org.jhiccup.HiccupMeterAttacher $JHICCUP_Options"
if [ $verboseOutput ]; then
echo jHiccup executing: $CMD
fi
exec $JAVA_HOME/bin/java -cp $JAVA_HOME/lib/tools.jar:$JHICCUP_JAR_FILE org.jhiccup.HiccupMeterAttacher $JHICCUP_Options
fi
#
# Prepare and execute command:
#
CMD="$PARSED_BinJava -javaagent:$JHICCUP_JAR_FILE=\"$JHICCUP_Options\" $PARSED_JavaArgs $PARSED_AppArgs"
if [ $verboseOutput ]; then
echo jHiccup executing: $CMD
fi
exec $PARSED_BinJava -javaagent:$JHICCUP_JAR_FILE="$JHICCUP_Options" $PARSED_JavaArgs $PARSED_AppArgs
#exec $CMD