├── .github
└── workflows
│ └── maven.yml
├── .gitignore
├── .travis.yml
├── COPYING.txt
├── Dockerfile
├── LICENSE.txt
├── README.md
├── examplePlot.png
├── jHiccup
├── jHiccupLogProcessor
├── jHiccupPlotter.xls
├── pom.xml
└── src
├── main
├── assembly
│ └── dist.xml
└── java
│ └── org
│ └── jhiccup
│ ├── HiccupMeter.java
│ ├── HiccupMeterAttacher.java
│ ├── Idle.java
│ └── Version.java.template
└── test
└── java
└── org
└── jhiccup
├── HiccupConfigurationTest.java
└── HiccupMeterTest.java
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: Java CI
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: Set up JDK 1.8
13 | uses: actions/setup-java@v1
14 | with:
15 | java-version: 1.8
16 | - name: Build with Maven
17 | run: mvn package -B --file pom.xml
18 |
19 | test:
20 |
21 | runs-on: ${{ matrix.os }}
22 | strategy:
23 | matrix:
24 | os: [ubuntu-18.04, macOS-latest, windows-2016]
25 | # test on both latest and specific update of each major version:
26 | java: [7, 7.0.181, 8, 8.0.192, 9, 10, 11, 11.0.3, 12, 13, 13.0.4, 14, 15, 16, 17, 18-ea]
27 | fail-fast: false
28 | max-parallel: 5
29 | name: Test JDK ${{ matrix.java }}, ${{ matrix.os }}
30 |
31 | steps:
32 | - uses: actions/checkout@v1
33 | - name: Set up JDK
34 | uses: actions/setup-java@v1
35 | with:
36 | java-version: ${{ matrix.java }}
37 | - name: Test with Maven
38 | run: mvn test -B --file pom.xml
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | .idea
3 | out
4 | gh-pages
5 | jHiccup.iml
6 | jHiccup.jar
7 | .classpath
8 | .project
9 | .settings
10 | release.properties
11 | pom.xml.releaseBackup
12 | src/main/java/org/jhiccup/Version.java
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | git:
3 | depth: 3
4 | sudo: required
5 | services:
6 | - docker
7 | before_script:
8 | - docker build -t zulu-mvn-git .
9 | script:
10 | - docker run -v `pwd`:/jHiccup zulu-mvn-git /bin/sh -c "mvn -f /jHiccup/pom.xml test"
--------------------------------------------------------------------------------
/COPYING.txt:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM azul/zulu-openjdk:8
2 |
3 | RUN apt-get update
4 | RUN apt-get -qqy install maven
5 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | * This code was Written by Gil Tene of Azul Systems, and released to the
2 | * public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/
3 |
4 | For users of this code who wish to consume it under the "BSD" license
5 | rather than under the public domain or CC0 contribution text mentioned
6 | above, the code found under this directory is *also* provided under the
7 | following license (commonly referred to as the BSD 2-Clause License). This
8 | license does not detract from the above stated release of the code into
9 | the public domain, and simply represents an additional license granted by
10 | the Author.
11 |
12 | -----------------------------------------------------------------------------
13 | ** Beginning of "BSD 2-Clause License" text. **
14 |
15 | Copyright (c) 2012, 2013, 2014, 2015, 2016 Gil Tene
16 | All rights reserved.
17 |
18 | Redistribution and use in source and binary forms, with or without
19 | modification, are permitted provided that the following conditions are met:
20 |
21 | 1. Redistributions of source code must retain the above copyright notice,
22 | this list of conditions and the following disclaimer.
23 |
24 | 2. Redistributions in binary form must reproduce the above copyright notice,
25 | this list of conditions and the following disclaimer in the documentation
26 | and/or other materials provided with the distribution.
27 |
28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
32 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
38 | THE POSSIBILITY OF SUCH DAMAGE.
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # jHiccup
4 | [](https://travis-ci.org/giltene/jHiccup)
5 | [](https://github.com/giltene/jHiccup/actions)
6 | [](https://gitter.im/giltene/jHiccup?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
7 |
8 | ----------------------------------------------------------------------------
9 |
10 | Written by Gil Tene of Azul Systems, and released to the public domain
11 | as explained at http://creativecommons.org/publicdomain/zero/1.0
12 |
13 | ----------------------------------------------------------------------------
14 |
15 | Version: 2.0.10
16 | ----------------------------------------------------------------------------
17 |
18 | jHiccup is a non-intrusive instrumentation tool that logs and records
19 | platform "hiccups" - including the JVM stalls that often happen when
20 | Java applications are executed and/or any OS or hardware platform noise
21 | that may cause the running application to not be continuously runnable.
22 |
23 | jHiccup can be executed in one of three main ways:
24 |
25 | 1. It can be run as a Java agent (using: `java -javaagent:jHiccup.jar`)
26 |
27 | 2. It can be injected into a running application (using: `jHiccup -p `)
28 |
29 | 3. It can also be run using a convenient wrapper command for your
30 | existing Java application (using: `jHiccup java myProg ...`)
31 |
32 | ----------------------------------------------------------------------------
33 |
34 | ### Example jHiccup plot
35 | ![example plot]
36 |
37 | ----------------------------------------------------------------------------
38 | # Using jHiccup as a Java agent:
39 |
40 | jHiccup is most often used as a Java agent. This is useful for platforms and
41 | environments where a Java agent is simpler to integrate into launch scripts,
42 | or in environments where using the bash jHiccup wrapper script is not practical
43 | (e.g. Windows, and environments where java is not directly launched from
44 | the command line).
45 |
46 | jHiccup.jar can be used as a Java agent using the following launch syntax:
47 |
48 | % java -javaagent:jHiccup.jar MyProgram
49 |
50 | or
51 |
52 | % java -javaagent:jHiccup.jar="" MyProgram.jar -a -b -c
53 |
54 | You can find the available options for the Java agent mode by running:
55 |
56 | % java -javaagent:jHiccup.jar="-h"
57 |
58 | Here is a Java agent usage example with explicit parameters:
59 |
60 | % java -javaagent:jHiccup.jar="-d 2000 -i 1000 -l hiccuplog -c" MyProgram.jar -a -b -c
61 |
62 | This example will record hiccups experienced during the running of `MyProgram.jar`
63 | in log file `hiccuplog`, while at the same time recording the hiccups experienced by
64 | a control process running in a separate JVM in the log file `c.hiccuplog`.
65 | Measurement will start 2 seconds after startup (rather than immediately),
66 | and interval data will be recorded every 1 second (rather than the default 5 seconds).
67 |
68 | Useful Java agent related notes:
69 |
70 | Note 1: When used as a java agent, jHiccup will treat spaces, commas, and
71 | semicolons as delimiting characters (`[ ,;]+`). For example, the option string
72 | `-d 0 -i 1000` is equivalent to the option string `-d,0,-i,1000`. This is
73 | useful for environments where placing space delimiters into quoted strings
74 | is difficult or confusing.
75 |
76 | Note 2: I find that a common way people add jHiccup as a Java agent is by using
77 | the `_JAVA_OPTIONS` environment variable. This often allows one to add the jHiccup
78 | Java agent without significant launch script surgery. For example:
79 |
80 | export _JAVA_OPTIONS='-javaagent:/path/to/jHiccup/target/jHiccup.jar="-d 20000 -i 1000"'
81 |
82 | ----------------------------------------------------------------------------
83 |
84 | # Reading and processing the jHiccup log with jHiccupLogProcessor:
85 |
86 | jHiccup logs hiccup information in a histogram log (see
87 | [HdrHistogram.org](http://hdrhistogram.org/)). This histogram log contains a full, high fidelity
88 | histogram of all collected results in each interval, in a highly compressed
89 | form (typically using only ~200-400 bytes per interval). However, other than
90 | the timestamp and maximum hiccup magnitude found in the given interval, the
91 | rest of the log line for each interval is not human readable (it is a base64
92 | encoding of a compressed HdrHistogram).
93 |
94 | To translate the jHiccup log file to a more human-readable form, the jHiccupLogProcessor
95 | utility is provided. In it's simplest form, this utility can be used as such
96 |
97 | % jHiccupLogProcessor -i mylog.hlog -o mylog
98 |
99 | Which will produce log files `mylog` and `mylog.hgrm` containing a human readable
100 | interval log (with selected percentiles in each interval), as well as a human
101 | readable histogram percentile distribution log.
102 |
103 | jHiccupLogProcessor can also be used to produce log files for an arbitrary
104 | section of the jHiccup log, by using the optional `-start` and `-end` parameters.
105 |
106 | See `jHiccupLogProcessor -h` for more details.
107 |
108 | ----------------------------------------------------------------------------
109 |
110 | # Hiccup Charts: Plotting jHiccup results
111 |
112 | Since jHiccup uses [HdrHistogram](http://hdrhistogram.org/) and produces
113 | HdrHistogram logs, various tools that plot and view histogram logs can be
114 | used to analyze jhiccup data. Some common tools include
115 | [HistggramLogAnalyzer](https://github.com/HdrHistogram/HistogramLogAnalyzer)
116 | , [HdrHistogramVisualizer](https://github.com/ennerf/HdrHistogramVisualizer)
117 | , and a javascript-based in-browser [histogram log parser](https://hdrhistogram.github.io/HdrHistogramJSDemo/logparser.html)
118 |
119 | ----------------------------------------------------------------------------
120 |
121 | # Launching jHiccup by attaching it to existing, running application:
122 |
123 | The jHiccup agent can be injected into a live, running Java application
124 | if the environment supports the java attach API (which is typically available
125 | in java environments running Java SE 6 or later).
126 |
127 | $ jHiccup -p
128 |
129 | NOTE: In order to attach to a running java application, the running
130 | application needs to have `${JAVA_HOME}/lib/tools.jar` in it's classpath.
131 | While this is commonly the case already for many IDE and desktop environments,
132 | and for environments that involve or enable other attachable agents (such as
133 | profilers), you may find that it is not included in your application's
134 | classpath, and that it needs to be added if attaching jHiccup at runtime
135 | is needed (launching jHiccup as a Java agent per the below may be a good
136 | alternative).
137 |
138 | ----------------------------------------------------------------------------
139 |
140 | # Running jHiccup using the Wrapper Script form:
141 |
142 | In the wrapper script form, all it takes is adding the word "jHiccup" in
143 | front of whatever the java invocation command line is.
144 |
145 | For example, if your program were normally executed as:
146 |
147 | java MyProgram -a -b -c
148 |
149 | The launch line would become:
150 |
151 | jHiccup java MyProgram -a -b -c
152 |
153 | or, for a program launched with:
154 |
155 | /usr/bin/java -jar MyProgram.jar -a -b -c
156 |
157 | The launch line would become:
158 |
159 | jHiccup /usr/bin/java -jar MyProgram.jar -a -b -c
160 |
161 | or, to override the defaults by making the recording start delay 60 seconds
162 | and log to hlog, it would become:
163 |
164 | jHiccup -d 60000 -l hlog /usr/bin/java -jar MyProgram.jar -a -b -c
165 |
166 | The jar file also includes a simple "Idle" class to facilitate sanity checks
167 | without an external program. Here is a simple sanity test example: jHiccup
168 | with a 4 sec delay on recording start, wrapping an Idle run that does nothing
169 | for 30 seconds and exits:
170 |
171 | % jHiccup -d 4000 /usr/bin/java org.jhiccup.Idle -t 30000
172 |
173 | [Run `jHiccup -h`, or see comment in jHiccup script for more details.]
174 |
175 | ----------------------------------------------------------------------------
176 |
177 | # Supported/Tested platforms:
178 |
179 | The jHiccup command is expected to work and has been tested on the following
180 | platforms:
181 | - Various Linux flavors (Tested on RHEL/CentOS 5.x and 6.x)
182 | - Mac OS X (tested on Lion, 10.7)
183 | - Windows with a Cygwin environment installed (tested on Windows 7)
184 | - Solaris (tested on both SPARC and x86)
185 |
186 | jHiccup.jar is expected to work as a java agent and has been tested on the
187 | following platforms:
188 | - Various Linux flavors (Tested on RHEL/CentOS 5.x and 6.x)
189 | - Mac OS X (tested on Lion, 10.7)
190 | - Windows standard command shell (tested on Windows 7)
191 | - Solaris (tested on both SPARC and x86)
192 |
193 | If you use jHiccup on other operating systems and setups, please report back
194 | on your experience so that we can expand the list.
195 |
196 | ----------------------------------------------------------------------------
197 |
198 | # Using a control process to concurrently record baseline idle load hiccups:
199 |
200 | It is often useful to compare the hiccup behavior experienced by a running
201 | application with a "control" hiccup level of an idle workload, running on
202 | the same system and at the same time as the observed application. To make
203 | such control measurement convenient, jHiccup supports a `-c` option that will
204 | launch a concurrently executing "control process" and will separately log
205 | hiccup information of an idle workload running on a separate jvm for the
206 | duration of the instrumented application run. When selected, the control
207 | process log file name will match those used for the launching application,
208 | followed with a `.c`.
209 |
210 | For example:
211 |
212 | % jHiccup -l mylog -c /usr/bin/java -jar MyProgram.jar -a -b -c
213 |
214 | Will produce log file `mylog` detailing the hiccup behavior during the
215 | execution of `MyProgram.jar`, as well as a log file `c.mylog` detailing
216 | the hiccup behavior of an idle workload running on a separate jvm at
217 | the same time.
218 |
219 | ----------------------------------------------------------------------------
220 |
221 | # Log file name recognizes and fills in %pid , %date , and %host terms
222 |
223 | When a log file name is specified with the `-l` option, the terms `%pid`,
224 | `%date`, and `%host` will be filled in with the appropriate information.
225 | The default log file name setting is simply `hiccup.%date.%pid`.
226 |
227 | ----------------------------------------------------------------------------
228 |
229 | # Using jHiccup to process latency log files:
230 |
231 | jHiccup's main HiccupMeter class supports a mode `-f` that will take latency
232 | input from a file instead of recording it. This is useful for producing
233 | jHiccup-style text and graphical output for recorded latency data collected
234 | by some other means.
235 |
236 | When provided to the `-f` option, an input file is expected to contain two
237 | white-space delimited values per line (in either integer or real number format),
238 | representing a time stamp and a measured latency, both in millisecond units.
239 |
240 | It's important to note that the default "expected interval between samples"
241 | resolution in jHiccup and HiccupMeter is 1 millisecond. When processing
242 | input files, it is imperative that an appropriate value be supplied to
243 | the `-r` option, and that this value correctly represent the expected interval
244 | between samples in the provided input file. HiccupMeter will use this
245 | parameter to determine whether additional, artificial values should be added
246 | to the histogram recording, between input samples that are farther apart in
247 | time than the expected interval specified to the `-r` option. This behavior
248 | corrects for "coordinated omission" situations (where long response times
249 | lead to "skipped" requests that would have typically correlated with "bad"
250 | response times). A "large" value (e.g. `-r 100000`) can easily be specified
251 | to avoid any correction of this situation.
252 |
253 | Example:
254 |
255 | % java -jar jHiccup.jar -i 1000 -f inputLatenies -l latencies.hlog
256 |
257 | ----------------------------------------------------------------------------
258 |
259 | # Using jHiccup to process pause logs from e.g. gc log files:
260 |
261 | When run in the file injection mode (`-f`), jHiccup's main HiccupMeter
262 | class supports an optional "fill zeros" (`-fz`) mode. This mode is
263 | useful for processing input that represent pause events rather than
264 | latencies.
265 |
266 | A common use case for this feature is producing hiccup logs from GC logs.
267 | GC logs will generally include pause information, which can be parsed out
268 | to a "pauses log". jHiccup can takes a "pauses logs" as input
269 |
270 |
271 | When provided to the `-f` option, in conjunction with a `-fz` option, an
272 | input file is expected to contain two white-space delimited values per
273 | line (in either integer or real number format), representing a time stamp
274 | and a measured length of a pause, both in millisecond units.
275 |
276 | Example (parsing gc log with +PrintGCTimeStamps):
277 |
278 | % java ... -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCTimeStamps -Xloggc:gc.log ...
279 |
280 | % awk -F": " '/Total time for which application threads were stopped/ {printf "%4.0f %4.3f\n", $1*1000.0, $3*1000.0;}' gc.log > gcPauses.log
281 |
282 | % java -jar jHiccup.jar -i 1000 -f gcPauses.log -fz -l pauses.hlog
283 |
284 | Example (with both +PrintGCTimeStamps and +PrintGCDateStamps):
285 |
286 | % java ... -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:gc.log ...
287 |
288 | % awk -F": " '/Total time for which application threads were stopped/ {printf "%4.0f %4.3f\n", $2*1000.0, $4*1000.0;}' gc.log > gcPauses.log
289 |
290 | % java -jar jHiccup.jar -i 1000 -f gcPauses.log -fz -l pauses.hlog
291 |
292 |
293 | ----------------------------------------------------------------------------
294 |
295 | # Example: adding jHiccup to Tomcat runs:
296 |
297 | In Tomcat's `catalina.sh` script, replace the following line:
298 |
299 | exec "$_RUNJAVA" "$LOGGING_CONFIG" $JAVA_OPTS $CATALINA_OPTS
300 |
301 | with:
302 |
303 | exec "$JHICCUP_HOME/jHiccup" "$_RUNJAVA" "$LOGGING_CONFIG" $JAVA_OPTS $CATALINA_OPTS
304 |
305 | ----------------------------------------------------------------------------
306 |
307 | # Note: Use of HdrHistogram.
308 |
309 | jHiccup depends on and makes systemic use of HdrHistogram to collected and
310 | report on the statistical distribution of hiccups. HdrHistogram sources
311 | and documentation can be found on GitHub, at
312 | http://hdrhistogram.github.io/HdrHistogram/
313 |
314 | ----------------------------------------------------------------------------
315 |
316 | # Building jHiccup:
317 |
318 | jHiccup can be (re)built from source files using Maven:
319 |
320 | % mvn package
321 |
322 | [example plot]:https://raw.github.com/giltene/jHiccup/master/examplePlot.png "Example jHiccup plot"
323 |
--------------------------------------------------------------------------------
/examplePlot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/giltene/jHiccup/d2e18b8e9f42c60e67633bf7fc00b91cd321136b/examplePlot.png
--------------------------------------------------------------------------------
/jHiccup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # jHiccup
4 | #
5 | # Written by Gil Tene, and released to the public domain, as explained at
6 | # http://creativecommons.org/publicdomain/zero/1.0/
7 | #
8 | JHICCUP_Version=2.0.10
9 | #
10 | # jHiccup is a platform pause measurement tool, it is meant to observe the
11 | # underlying platform (JVM, OS, HW, etc.) responsiveness while under an
12 | # unrelated application load, and establish a lower bound for the stalls
13 | # the application would experience. It is run as a wrapper around
14 | # other applications so that measurements can be done without any changes
15 | # to application code.
16 | #
17 | # The purpose of jHiccup is to aid application operators and testers in
18 | # characterizing the inherent "platform hiccups" (execution stalls)
19 | # that a Java platform will display when running under load. The hiccups
20 | # measured are NOT stalls caused by the application's code. They are stalls
21 | # caused by the platform (JVM, OS, HW, etc.) that would be visible to and
22 | # affect any application thread running on the platform at the time of the
23 | # stall.It is generally safe to assume that if jHiccup experiences and
24 | # records a certain level of measured platform hiccups, the application
25 | # running on the same JVM platform during that time had experienced
26 | # hiccup/stall effects that are at least as large as the measured level.
27 | #
28 | # jHiccup's measurement works on the simple basis of measuring the time it
29 | # takes an effectively empty workload to perform work (while running alongside
30 | # whatever load the platform is carrying). Hiccup measurements are performed
31 | # by a thread that repeatedly sleeps for a given interval (-r for resolutionMs,
32 | # defaults to 1 msec), and logs the amount of time it took to actually wake up
33 | # each time in a detailed internal hiccup histogram. The assumption is that
34 | # if the measuring thread experienced some delay in waking up, any other thread
35 | # in the system could/would have experienced a similar delay, resulting in
36 | # application stalls.
37 | #
38 | # jHiccup produces a single log file (hiccup.YYMMDD.HHMM.pid.hlog) in Histogram
39 | # log format (see HdrHistogram documentaton for HistogramLogReader for details).
40 | # This log file captures histograms for each logging interval (set
41 | # with -i , defaults to 5000 msec)., which can later
42 | # be processed to reconstruct hiccup behavior over an arbitrary portion of the
43 | # log. The -l can be used to override the log file name.
44 | #
45 | # An associated utlity, jHiccupLogProcessor, generates two log files from this
46 | # log file: a sequential interval log file and a histogram log file.
47 | # The sequential interval log file logs a single %'ile stats line for each
48 | # reporting interval. The histogram log file includes a detailed %'ile histogram
49 | # of the run so far.
50 | # See documentation or help for jHiccupLogProcessor for details.
51 | #
52 | #
53 | # jHiccup can be configured to delay the start of measurement
54 | # (using the -d flag, defaults to 0 msec).
55 | #
56 | # jHiccup will continue to run until the application it is wrapping exists.
57 | #
58 | # Using the -c option (off by default), jHiccup can be configured to launch
59 | # a concurrently executing "control process" that will separately log hiccup
60 | # information of an idle workload running on a separate jvm for the duration
61 | # of the instrumented application run. When selected, the control process log
62 | # file name will match the one used for the preceded application, preceded
63 | # with a "c.".
64 | #
65 | # For convenience in testing, jHiccup can be executed as a simple wrapper for
66 | # java program execution. All it takes is adding the word "jHiccup" in front
67 | # of whatever the java invocation command line is.
68 | #
69 | # For example, if your program were normally executed as:
70 | #
71 | # java UsefulProgram -a -b -c
72 | #
73 | # The launch line would become:
74 | #
75 | # jHiccup java UsefulProgram -a -b -c
76 | #
77 | # or, for a program that is launch like this:
78 | #
79 | # /usr/bin/java -jar UsefulProgram.jar -a -b -c
80 | #
81 | # The launch line would become:
82 | #
83 | # jHiccup /usr/bin/java -jar UsefulProgram.jar -a -b -c
84 | #
85 | # or, to override the defaults by making the recording start delay 60 seconds
86 | # and log to hlog, it would become:
87 | #
88 | # jHiccup -d 60000 -l hlog /usr/bin/java -jar UsefulProgram.jar -a -b -c
89 | #
90 |
91 | # Figure out installed path:
92 | # On Linux, we'd do the following:
93 | # PARSED_SCRIPT=`readlink -f $0`
94 | # INSTALLED_PATH=`dirname $PARSED_SCRIPT`
95 | # But readlink -f doesn't work the same everywhere (e.g. Mac OS). We use this instead:
96 | function readlink_f () { _=`pwd`; cd `dirname $1` && echo `pwd` && cd $_; }
97 | INSTALLED_PATH=$(readlink_f $0)
98 |
99 | # Check if running from unpacked distribution archive by assuming jHiccup.jar
100 | # in the same directory as this script. If not, try to search in target/ directory
101 | # (running from the source repository build).
102 | JHICCUP_JAR_FILE=$INSTALLED_PATH/jHiccup.jar
103 | if [ ! -f $JHICCUP_JAR_FILE ] ; then
104 | JHICCUP_JAR_FILE=$INSTALLED_PATH/target/jHiccup.jar
105 | fi
106 |
107 | DATE=`date +%y%m%d.%H%M`
108 |
109 | #
110 | # Parse original java execution arguments:
111 | #
112 | count=0
113 | JHiccupArgs=
114 | readingJHiccupArgs=0
115 | PARSED_BinJava=
116 | readingJavaBin=1
117 | readingJavaArgs=0
118 | PARSED_JavaArgs=
119 | PARSED_AppArgs=
120 | for var in $@; do
121 | # echo $count: "$var"
122 | if [ $readingJavaBin -eq 1 ] ; then
123 | # Looking for JavaBin. Identify and parse jHiccup args
124 | if [ $readingJHiccupArgs -eq 1 ]; then
125 | # This was marked as an arg to jHiccup
126 | JHiccupArgs="$JHiccupArgs $var"
127 | readingJHiccupArgs=0
128 | elif [ $var = "-v" ]; then
129 | # -v is a flag arg to jHiccup
130 | JHiccupArgs="$JHiccupArgs $var"
131 | elif [ $var = "-0" ]; then
132 | # -0 is a flag arg to jHiccup
133 | JHiccupArgs="$JHiccupArgs $var"
134 | elif [ $var = "-c" ]; then
135 | # -c is a flag arg to jHiccup
136 | JHiccupArgs="$JHiccupArgs $var"
137 | elif [ $var = "-o" ]; then
138 | # -o is a flag arg to jHiccup
139 | JHiccupArgs="$JHiccupArgs $var"
140 | elif [ ${var:0:1} = "-" ]; then
141 | # This is a parameter arg to jHiccup
142 | JHiccupArgs="$JHiccupArgs $var"
143 | readingJHiccupArgs=1
144 | else
145 | # Found JavaBin
146 | PARSED_BinJava="$var"
147 | readingJavaBin=0
148 | readingJavaArgs=1
149 | fi
150 | elif [ $readingJavaArgs -eq 1 ]; then
151 | # Parsing Java args
152 | if [ ${var:0:1} = "-" ]; then
153 | PARSED_JavaArgs="$PARSED_JavaArgs $var"
154 | else
155 | readingJavaArgs=0
156 | PARSED_AppArgs="$var"
157 | fi
158 | else
159 | # Parsing app args
160 | PARSED_AppArgs="$PARSED_AppArgs $var"
161 | fi
162 | let "count = $count + 1"
163 | done
164 | # At this point, we should have valid $PARSED_BinJava, $PARSED_JavaArgs, $PARSED_AppArgs:
165 | #echo PARSED_BinJava = "$PARSED_BinJava"
166 | #echo PARSED_JavaArgs = "$PARSED_JavaArgs"
167 | #echo PARSED_AppArgs = "$PARSED_AppArgs"
168 |
169 | #
170 | # Parse jHiccup arguments:
171 | #
172 | JHICCUP_DelayArg=
173 | readingDelayArg=0
174 | JHICCUP_RunTimeArg=
175 | readingRunTimeArg=0
176 | JHICCUP_IntervalArg=
177 | readingIntervalArg=0
178 | JHICCUP_ResolutionArg=
179 | readingResolutionArg=0
180 | JHICCUP_LognameArg=
181 | readingLognnameArg=0
182 | JHICCUP_PidOfProcessToAttacheToArg=
183 | readingPidOfProcessToAttacheToArg=0
184 |
185 | verboseOutput=
186 | logFormatCsv=
187 | startTimeAtZero=
188 | JHiccupArgs_parse_error=
189 | JHICCUP_ControlProcessFlag=
190 |
191 | for var in $JHiccupArgs; do
192 | if [ $readingDelayArg -eq 1 ]; then
193 | JHICCUP_DelayArg=$var
194 | readingDelayArg=0
195 | elif [ $readingRunTimeArg -eq 1 ]; then
196 | JHICCUP_RunTimeArg=$var
197 | readingRunTimeArg=0
198 | elif [ $readingIntervalArg -eq 1 ]; then
199 | JHICCUP_IntervalArg=$var
200 | readingIntervalArg=0
201 | elif [ $readingResolutionArg -eq 1 ]; then
202 | JHICCUP_ResolutionArg=$var
203 | readingResolutionArg=0
204 | elif [ $readingLognnameArg -eq 1 ]; then
205 | JHICCUP_LognameArg=$var
206 | readingLognnameArg=0
207 | elif [ $readingPidOfProcessToAttacheToArg -eq 1 ]; then
208 | JHICCUP_PidOfProcessToAttacheToArg=$var
209 | readingPidOfProcessToAttacheToArg=0
210 | elif [ $var = "-d" ]; then
211 | readingDelayArg=1
212 | elif [ $var = "-t" ]; then
213 | readingRunTimeArg=1
214 | elif [ $var = "-i" ]; then
215 | readingIntervalArg=1
216 | elif [ $var = "-r" ]; then
217 | readingResolutionArg=1
218 | elif [ $var = "-l" ]; then
219 | readingLognnameArg=1
220 | elif [ $var = "-p" ]; then
221 | readingPidOfProcessToAttacheToArg=1
222 | elif [ $var = "-c" ]; then
223 | JHICCUP_ControlProcessFlag=1
224 | elif [ $var = "-0" ]; then
225 | startTimeAtZero=1
226 | elif [ $var = "-o" ]; then
227 | logFormatCsv=1
228 | elif [ $var = "-v" ]; then
229 | verboseOutput=1
230 | echo jHiccup version $JHICCUP_Version
231 | else
232 | JHiccupArgs_parse_error=1
233 | fi
234 | done
235 |
236 | if [ $readingDelayArg -eq 1 ]; then
237 | JHiccupArgs_parse_error=1
238 | elif [ $readingRunTimeArg -eq 1 ]; then
239 | JHiccupArgs_parse_error=1
240 | elif [ $readingIntervalArg -eq 1 ]; then
241 | JHiccupArgs_parse_error=1
242 | elif [ $readingResolutionArg -eq 1 ]; then
243 | JHiccupArgs_parse_error=1
244 | elif [ $readingLognnameArg -eq 1 ]; then
245 | JHiccupArgs_parse_error=1
246 | elif [ $readingPidOfProcessToAttacheToArg -eq 1 ]; then
247 | JHiccupArgs_parse_error=1
248 | fi
249 |
250 | # Should not have both a java command and a -p option:
251 | if [ $PARSED_BinJava ]; then
252 | if [ $JHICCUP_PidOfProcessToAttacheToArg ]; then
253 | JHiccupArgs_parse_error=1
254 | fi
255 | fi
256 |
257 | if [ $JHiccupArgs_parse_error ]; then
258 | echo $PARSED_SCRIPT $@
259 | echo jHiccup version $JHICCUP_Version
260 | echo "Usage:"
261 | echo " jHiccup [-d startupDelayMsec] [-t runTimeMsec] [-i recordingIntervalMsec] [-l logname]"
262 | echo " [-r sampleResolutionMsec] [-c] [-p pidOfProcessToAttachTo]"
263 | echo " or:"
264 | echo " jHiccup [-d startupDelayMsec] [-t runTimeMsec] [-i recordingIntervalMsec] [-l logname]"
265 | echo " [-r sampleResolutionMsec] [-c] "
266 | echo "Where:"
267 | echo " -l logname Sets the log files to and .hgrm"
268 | echo " (default is \"hiccup.yymmdd.hhmm.pid\") "
269 | echo " (replaces occurrences of %pid and %date with appropriate info)"
270 | echo " -o Output log files in CSV format"
271 | echo " -c Concurrently start a control process to record hiccups"
272 | echo " experienced by an Idle load running on a separate jvm"
273 | echo " in log files .c and .c.hgrm"
274 | echo " -p pidOfProcessToAttachTo Attach to the process with given pid and inject jHiccup as an agent"
275 | echo " (no default)"
276 | echo " -d startupDelayMsec Sets the delay, in milliseconds before sampling starts"
277 | echo " (default 0)"
278 | echo " -t runTimeMsec Limit measurement and logging time"
279 | echo " (default 0, for infinite)"
280 | echo " -0 Start logfile timestamps at 0 (as opposed to JVM uptime at start point)"
281 | echo " (default off)"
282 | echo " -i recordingIntervalMsec Sets the reporting interval in milliseconds"
283 | echo " (default 5000)"
284 | echo " -r sampleResolutionMsec Sets the sampling resolution in milliseconds"
285 | echo " (default 1)"
286 | echo " -v Verbose output"
287 | exit -1
288 | fi
289 |
290 | JHICCUP_Options=""
291 |
292 | if [ $JHICCUP_DelayArg ]; then
293 | JHICCUP_Options="${JHICCUP_Options}-d $JHICCUP_DelayArg "
294 | fi
295 |
296 | if [ $JHICCUP_RunTimeArg ]; then
297 | JHICCUP_Options="${JHICCUP_Options}-t $JHICCUP_RunTimeArg "
298 | fi
299 |
300 | if [ $JHICCUP_IntervalArg ]; then
301 | JHICCUP_Options="${JHICCUP_Options}-i $JHICCUP_IntervalArg "
302 | fi
303 |
304 | if [ $JHICCUP_ResolutionArg ]; then
305 | JHICCUP_Options="${JHICCUP_Options}-r $JHICCUP_ResolutionArg "
306 | fi
307 |
308 | if [ $JHICCUP_LognameArg ]; then
309 | JHICCUP_Options="${JHICCUP_Options}-l $JHICCUP_LognameArg "
310 | fi
311 |
312 | if [ $startTimeAtZero ]; then
313 | JHICCUP_Options="${JHICCUP_Options}-0 "
314 | fi
315 |
316 | if [ $logFormatCsv ]; then
317 | JHICCUP_Options="${JHICCUP_Options}-o "
318 | fi
319 |
320 | if [ $JHICCUP_ControlProcessFlag ]; then
321 | JHICCUP_Options="${JHICCUP_Options}-c "
322 | fi
323 |
324 | if [ $verboseOutput ]; then
325 | JHICCUP_Options="${JHICCUP_Options}-v "
326 | fi
327 |
328 | # Deal with Windows/cygwin path normalization syntax needs:
329 | # Key Assumption: only cygwin/Windows installations will have a cygpath command...
330 | cygpath -w $JHICCUP_JAR_FILE &> /dev/null
331 | if [ $? -eq 0 ] ; then
332 | # if using cygwin, use valid windows-style classpath
333 | JHICCUP_JAR_FILE=`cygpath -w $JHICCUP_JAR_FILE`
334 | echo Windows path for hiccup jar file is $JHICCUP_JAR_FILE
335 | fi
336 |
337 | if [ $JHICCUP_PidOfProcessToAttacheToArg ]; then
338 | JHICCUP_Options="${JHICCUP_Options}-j $JHICCUP_JAR_FILE -p $JHICCUP_PidOfProcessToAttacheToArg "
339 |
340 | #
341 | # Prepare and execute attach command:
342 | #
343 |
344 | CMD="$JAVA_HOME/bin/java -cp $JAVA_HOME/lib/tools.jar:$JHICCUP_JAR_FILE org.jhiccup.HiccupMeterAttacher $JHICCUP_Options"
345 | if [ $verboseOutput ]; then
346 | echo jHiccup executing: $CMD
347 | fi
348 | exec $JAVA_HOME/bin/java -cp $JAVA_HOME/lib/tools.jar:$JHICCUP_JAR_FILE org.jhiccup.HiccupMeterAttacher $JHICCUP_Options
349 | fi
350 |
351 | #
352 | # Prepare and execute command:
353 | #
354 | CMD="$PARSED_BinJava -javaagent:$JHICCUP_JAR_FILE=\"$JHICCUP_Options\" $PARSED_JavaArgs $PARSED_AppArgs"
355 | if [ $verboseOutput ]; then
356 | echo jHiccup executing: $CMD
357 | fi
358 | exec $PARSED_BinJava -javaagent:$JHICCUP_JAR_FILE="$JHICCUP_Options" $PARSED_JavaArgs $PARSED_AppArgs
359 | #exec $CMD
360 |
--------------------------------------------------------------------------------
/jHiccupLogProcessor:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # jHiccupLogProcessor
4 | #
5 | # Written by Gil Tene, and released to the public domain, as explained at
6 | # http://creativecommons.org/publicdomain/zero/1.0/
7 | #
8 | JHICCUP_Version=2.0.4
9 | #
10 | # jHiccupLogProcessor will process an input log and can generate two
11 | # different log files from a single jHiccup histogram log file: a
12 | # sequential interval log file and a histogram log file.
13 | #
14 | # The sequential interval log file logs a single %'ile stats line for
15 | # each reporting interval.
16 | #
17 | # The histogram percentile log file includes a detailed %'ile histogram
18 | # of the entire log file range.
19 | #
20 | # jHiccupLogProcessor will process an input log file when provided with
21 | # the -i option. When no -i option is provided, standard input
22 | # will be processed.
23 | #
24 | # When provided with an output file name with the -o option
25 | # (e.g. "-o mylog"), jHiccupLogProcessor will produce both output files
26 | # under the names and .hgrm (e.g. mylog and mylog.hgrm).
27 | #
28 | # When not provided with an output file name, jHiccupLogProcessor will
29 | # produce [only] the histogram percentile log output to standard output.
30 | #
31 | # jHiccupLogProcessor accepts optional -start and -end time range
32 | # parameters. When provided, the output will only reflect the portion
33 | # of the input log with timestamps that fall within the provided start
34 | # and end time range parameters.
35 | #
36 | # jHiccupLogProcessor also accepts and optional -csv parameter, which
37 | # will cause the output formatting (of both output file forms) to use
38 | # a CSV file format.
39 | #
40 |
41 | # Figure out installed path:
42 | # On Linux, we'd do the following:
43 | # PARSED_SCRIPT=`readlink -f $0`
44 | # INSTALLED_PATH=`dirname $PARSED_SCRIPT`
45 | # But readlink -f doesn't work the same everywhere (e.g. Mac OS). We use this instead:
46 | readlink_f() {
47 | local _dir _path="$1"
48 | [ -d "$_path" ] && _path=$(cd "$_path"; pwd -P)
49 | while [ -L "$_path" ]; do
50 | _dir=$(dirname "$_path")
51 | _path=$(readlink "$_path")
52 | [ -n "${_path##/*}" ] && _path="${_dir}/${_path}"
53 | done
54 | [ -f "$_path" ] && _path="$(cd "$(dirname "$_path")"; pwd -P)/${_path##*/}"
55 | echo "${_path%/}"
56 | }
57 |
58 | INSTALLED_PATH=$(dirname "$(readlink_f "$0")")
59 |
60 | # Check if running from unpacked distribution archive by assuming jHiccup.jar
61 | # in the same directory as this script. If not, try to search in target/ directory
62 | # (running from the source repository build).
63 | JHICCUP_JAR_FILE="$INSTALLED_PATH/jHiccup.jar"
64 | if [ ! -f "$JHICCUP_JAR_FILE" ] ; then
65 | JHICCUP_JAR_FILE="$INSTALLED_PATH/target/jHiccup.jar"
66 | fi
67 |
68 | if [ ! -f "$JHICCUP_JAR_FILE" ] ; then
69 | JHICCUP_JAR_FILE="$INSTALLED_PATH/../jHiccup.jar"
70 | fi
71 |
72 | if [ ! -f "$JHICCUP_JAR_FILE" ] ; then
73 | echo "For this command to run, jHiccup.jar must be available in '${INSTALLED_PATH%/bin*}'."
74 | exit 1
75 | fi
76 |
77 | JAVA_BIN=`which java`
78 |
79 | if [ $JAVA_HOME ]; then
80 | JAVA_CMD=$JAVA_HOME/bin/java
81 | elif [ $JAVA_BIN ]; then
82 | JAVA_CMD=$JAVA_BIN
83 | else
84 | echo "For this command to run, either $JAVA_HOME must be set, or java must be in the path."
85 | exit 1
86 | fi
87 |
88 | #
89 | # Parse original java execution arguments:
90 | #
91 | # At this point, we should have valid $PARSED_BinJava, $PARSED_JavaArgs, $PARSED_AppArgs:
92 | #echo PARSED_BinJava = "$PARSED_BinJava"
93 | #echo PARSED_JavaArgs = "$PARSED_JavaArgs"
94 | #echo PARSED_AppArgs = "$PARSED_AppArgs"
95 |
96 | # Deal with Windows/cygwin path normalization syntax needs:
97 | # Key Assumption: only cygwin/Windows installations will have a cygpath command...
98 | cygpath -w $JHICCUP_JAR_FILE &> /dev/null
99 | if [ $? -eq 0 ] ; then
100 | # if using cygwin, use valid windows-style classpath
101 | JHICCUP_JAR_FILE=`cygpath -w $JHICCUP_JAR_FILE`
102 | echo Windows path for hiccup jar file is $JHICCUP_JAR_FILE
103 | fi
104 |
105 | exec $JAVA_CMD -cp $JHICCUP_JAR_FILE org.jhiccup.internal.hdrhistogram.HistogramLogProcessor $@
106 | #exec $CMD
107 |
--------------------------------------------------------------------------------
/jHiccupPlotter.xls:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/giltene/jHiccup/d2e18b8e9f42c60e67633bf7fc00b91cd321136b/jHiccupPlotter.xls
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | org.jhiccup
6 | jHiccup
7 | 2.0.11-SNAPSHOT
8 |
9 | jHiccup
10 |
11 | http://jhiccup.org
12 |
13 |
14 | jHiccup is a lightweight, non-intrusive instrumentation tool that logs and records
15 | platform "hiccups" - including the JVM stalls that often happen when
16 | Java applications are executed and/or any OS or hardware platform noise
17 | that may cause the running application to not be continuously runnable.
18 |
19 |
20 |
21 |
22 |
23 | * This code was Written by Gil Tene of Azul Systems, and released to the
24 | * public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/
25 |
26 | Public Domain, per Creative Commons CC0
27 | http://creativecommons.org/publicdomain/zero/1.0/
28 |
29 |
30 |
31 |
32 |
33 | giltene
34 | Gil Tene
35 | https://github.com/giltene
36 |
37 |
38 |
39 |
40 | scm:git:git://github.com/giltene/jHiccup.git
41 | scm:git:git://github.com/giltene/jHiccup.git
42 | scm:git:git@github.com:giltene/jHiccup.git
43 | jHiccup-2.0.10
44 |
45 |
46 |
47 | https://github.com/giltene/jHiccup/issues
48 | GitHub Issues
49 |
50 |
51 | jar
52 |
53 |
54 | UTF-8
55 | src/main/java/org/jhiccup/Version.java.template
56 | src/main/java/org/jhiccup/Version.java
57 |
58 |
59 |
60 |
61 |
62 |
63 | org.apache.maven.plugins
64 | maven-compiler-plugin
65 | 2.3.2
66 |
67 | 1.7
68 | 1.7
69 | UTF-8
70 |
71 |
72 |
73 |
74 | org.apache.maven.plugins
75 | maven-surefire-plugin
76 | 2.12.4
77 |
78 | false
79 |
80 |
81 |
82 |
83 | org.apache.maven.plugins
84 | maven-dependency-plugin
85 |
86 |
87 | copy-dependencies
88 | prepare-package
89 |
90 | copy-dependencies
91 |
92 |
93 | ${project.build.directory}/lib
94 | false
95 | false
96 | true
97 |
98 | tools
99 |
100 |
101 |
102 | copy-installed
103 | install
104 |
105 | copy
106 |
107 |
108 |
109 |
110 | ${project.groupId}
111 | ${project.artifactId}
112 | ${project.version}
113 | ${project.packaging}
114 | jHiccup.jar
115 |
116 |
117 | ${project.basedir}
118 |
119 |
120 |
121 |
122 |
123 |
124 | org.apache.maven.plugins
125 | maven-jar-plugin
126 | 2.4
127 |
128 | jHiccup
129 |
130 |
131 | false
132 | org.jhiccup.HiccupMeter
133 | true
134 | true
135 |
136 |
137 | org.jhiccup.HiccupMeter
138 | org.jhiccup.HiccupMeter
139 |
140 |
141 |
142 |
143 |
144 |
145 | org.apache.maven.plugins
146 | maven-release-plugin
147 | 2.5
148 |
149 |
150 |
151 |
152 | org.sonatype.plugins
153 | jarjar-maven-plugin
154 | 1.9
155 |
156 |
157 | package
158 |
159 | jarjar
160 |
161 |
162 |
163 | org.hdrhistogram:HdrHistogram
164 |
165 |
166 |
167 | org.HdrHistogram.**
168 | org.jhiccup.internal.hdrhistogram.@1
169 |
170 |
171 | true
172 |
173 |
174 |
175 |
176 |
177 |
178 | com.google.code.maven-replacer-plugin
179 | maven-replacer-plugin
180 | 1.4.0
181 |
182 |
183 | process-sources
184 |
185 | replace
186 |
187 |
188 |
189 |
190 | ${version.template.file}
191 | ${version.file}
192 |
193 |
194 | \$BUILD_TIME\$
195 | ${maven.build.timestamp}
196 |
197 |
198 | \$VERSION\$
199 | ${project.version}
200 |
201 |
202 |
203 |
204 |
205 |
206 | maven-assembly-plugin
207 | 2.4
208 |
209 |
210 | src/main/assembly/dist.xml
211 |
212 |
213 |
214 |
215 | package
216 |
217 | single
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 | junit
228 | junit
229 | 4.10
230 | test
231 |
232 |
233 | org.hdrhistogram
234 | HdrHistogram
235 | 2.1.12
236 |
237 |
238 |
239 |
240 |
241 |
242 | toolsjar-profile
243 |
244 |
245 | ${java.home}/../lib/tools.jar
246 |
247 |
248 |
249 | ${java.home}/../lib/tools.jar
250 |
251 |
252 |
253 |
254 | com.sun
255 | tools
256 |
257 | 99.9.9
258 | system
259 | ${java.home}/../lib/tools.jar
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
--------------------------------------------------------------------------------
/src/main/assembly/dist.xml:
--------------------------------------------------------------------------------
1 |
3 | dist
4 |
5 | tar.gz
6 | zip
7 |
8 |
9 |
10 | ${project.basedir}
11 | /
12 |
13 | COPYING.txt
14 | LICENSE.txt
15 | README.md
16 | jHiccupPlotter.xls
17 | pom.xml
18 |
19 |
20 |
21 | ${project.basedir}
22 | /
23 |
24 | jHiccup
25 | jHiccupLogProcessor
26 |
27 | 0744
28 |
29 |
30 | ${project.build.directory}
31 | /
32 |
33 | jHiccup.jar
34 |
35 |
36 |
37 | ${project.basedir}/src
38 | /src
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/main/java/org/jhiccup/HiccupMeter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Written by Gil Tene of Azul Systems, and released to the public domain,
3 | * as explained at http://creativecommons.org/publicdomain/zero/1.0/
4 | *
5 | * @author Gil Tene
6 | */
7 |
8 | package org.jhiccup;
9 |
10 | import org.HdrHistogram.*;
11 |
12 | import java.io.*;
13 | import java.net.InetAddress;
14 | import java.net.UnknownHostException;
15 | import java.security.CodeSource;
16 | import java.util.*;
17 | import java.text.SimpleDateFormat;
18 | import java.lang.management.*;
19 | import java.util.concurrent.TimeUnit;
20 |
21 | /**
22 | * HiccupMeter is a platform pause measurement tool, it is meant to observe
23 | * the underlying platform (JVM, OS, HW, etc.) responsiveness while under
24 | * an unrelated application load, and establish a lower bound for the stalls
25 | * the application would experience. It can be run as a wrapper around
26 | * other applications so that measurements can be done without any changes
27 | * to application code.
28 | *
29 | * The purpose of HiccupMeter is to aid application operators and testers
30 | * in characterizing the inherent "platform hiccups" (execution stalls)
31 | * that a Java platform will display when running under load. The hiccups
32 | * measured are NOT stalls caused by the application's code. They are stalls
33 | * caused by the platform (JVM, OS, HW, etc.) that would be visible to and
34 | * affect any application thread running on the platform at the time of the
35 | * stall. It is generally safe to assume that if HiccupMeter experiences and
36 | * records a certain level of measured platform hiccups, the application
37 | * running on the same JVM platform during that time had experienced
38 | * hiccup/stall effects that are at least as large as the measured level.
39 | *
40 | * HiccupMeter's measurement works on the simple basis of measuring the time
41 | * it takes an effectively empty workload to perform work (while running
42 | * alongside whatever load the platform is carrying). Hiccup measurements are
43 | * performed by a thread that repeatedly sleeps for a given interval (-r for
44 | * resolutionMs, defaults to 1 msec), and logs the amount of time it took to
45 | * actually wake up each time in a detailed internal hiccup histogram. The
46 | * assumption is that if the measuring thread experienced some delay in waking
47 | * up, any other thread in the system could/would have experienced a similar
48 | * delay, resulting in application stalls.
49 | *
50 | * HiccupMeter collects both raw and corrected (weighted) histogram results.
51 | * When the reported time in a histogram exceeds the interval used between
52 | * measurements, the raw histogram data would reflect only the single reported
53 | * results, while the corrected histogram data will reflect an appropriate
54 | * number of additional results with linearly decreasing times (down to a time
55 | * that is lower than the measurement interval). While raw and corrected
56 | * histogram data are both tracked internally, it is the corrected numbers that
57 | * are logged and reported, as they will more accurately reflect the response
58 | * time that a random, uncoordinated request would have experienced.
59 | *
60 | * HiccupMeter logs a single line with hiccup %'ile stats each reporting
61 | * interval (set with -i , defaults to 5000 msec) to a
62 | * log file. The log file name can be optionally controlled with the -l
63 | * flag, and will default (if no logfile name is supplied)to a name derived from
64 | * the process id and time (hiccup.yyMMdd.HHmm.pid). HiccupMeter will also produce
65 | * a detailed histogram log file under the .histogram name. A new
66 | * histogram log file will be produced each interval, and will replace the
67 | * one generated in the previous interval.
68 | *
69 | * HiccupMeter can be configured to delay the start of measurement
70 | * (using the -d flag, defaults to 0 msec). It can also be
71 | * configured to terminate measurement after a given length of time (using the
72 | * -t flag). If the -t flag is not used, HiccupMeter will continue
73 | * to run until the Class executed with via the -exec parameter (see below)
74 | * exits, or indefinitely (if no -exec is used).
75 | *
76 | * HiccupMeter can be configured to launch a separate "control process" on
77 | * startup (using the -c flag, defaulting to
78 | * nothing). This option launches a separate, standalone instance of
79 | * HiccupMeter wrapping running an idle workload, such that a concurrent
80 | * control measurement is established on the same system, at the same time
81 | * as the main observed application load is run.
82 | *
83 | * For convenience in testing, HiccupMeter is typically launched as a
84 | * javaagent. For example, if your program were normally executed as:
85 | *
86 | * java UsefulProgram -a -b -c
87 | *
88 | * This is how you would execute the same program so that HiccupMeter would
89 | * record hiccups while it is running:
90 | *
95 | * Measure internal jitter of JVM running MyProg, log into logFile and
96 | * logFile.hgrm, report in 5 seconds intervals (which is the default), start
97 | * measurements 60 seconds into the run, and run concurrent control process
98 | * that will record hiccups on an idle workload running at the same time,
99 | * logging those into c.logFile and c.logFile.hgrm:
100 | *