Chapter 24. Firing on All Engines

Michael Hunger

Traditional Java profilers use either byte code instrumentation or sampling (taking stack traces at short intervals) to determine where time was spent. Both approaches add their own skews and oddities. Understanding the output of those profilers is an art of its own and requires quite some experience.

Fortunately, Brendan Gregg, a performance engineer at Netflix, came up with flame graphs, an ingenious kind of diagram for stack traces that can be gathered from almost any system.

A flame graph sorts and aggregates the traces up to each stack level, so that their count per level represents the percentage of the total time spent in that part of the code. Rendering those blocks as actual blocks (rectangles) with the width being proportional to the percentage and stacking the blocks onto each other turned out to be very useful.

Flame graph of the benchmark of filling a non-preallocated ArrayList

The “flames” represent from bottom to top the progression from the entry point of the program or thread (main or an event loop) to the leaves of the execution in the tips of the flames. Note that the left-to-right order has no significance; often, it’s just alphabetical sorting. The same is true for colors. Only the relative widths and stack depths are relevant.

You can immediately see if certain parts of the program take an unexpectedly large amount of time. The higher up in the diagram that happens, the worse it is. Especially if you have a flame that’s very wide on top, you know you’ve found a bottleneck that is not delegating work elsewhere. After fixing the issue, measure again, and if the overall performance issue persists, revisit the diagram for new indications.

To address the shortcomings of traditional profilers, many modern tools make use of an internal JVM feature (AsyncGetCallTrace) that allows the gathering of stack traces outside of safepoints. Additionally, they combine measurement of JVM operations with native code and system calls to the operating system so that time spent in network, input/output (I/O), or garbage collection can become part of the flame graph as well.

Tools like Honest Profiler, perf-map-agent, async-profiler, and even IntelliJ IDEA make capturing the information and generating flame graphs really easy.

In most cases, you just download the tool, provide the process ID (PID) of your Java process, and tell the tool to run for a certain amount of time and generate the interactive scalable vector graphics (SVG):

# download and unzip async profiler for your OS from:
# https://github.com/jvm-profiling-tools/async-profiler
./profiler.sh -d <duration> -f flamegraph.svg -s -o svg <pid> && 
open flamegraph.svg  -a "Google Chrome"

The SVG that the tools produce is not just colorful but also interactive. You can zoom into sections, search for symbols, and more.

Flame graphs are an impressively powerful tool to quickly get an overview of the performance characteristics of your programs; you can see hotspots immediately and focus on those. Including non-JVM aspects also helps with the bigger picture.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset