Java has added a new launch option “-XX:+PreserveFramePointer” in JDK versions 8 and 9, that enables generation of mixed-mode flame graphs.

Flame graphs visually present the data gathered by performance profilers, tools used by developers for performance tuning their applications. In the past, Java developers had to use system profilers such as perf command in Linux, together with JVM profilers such as hprof, to get the full picture of their application performance.

System profilers only trace system code paths, whereas JVM profilers trace only the Java code paths. Netflix performance engineers Brendan Gregg and Martin Spier note that it is desirable for profilers to sample system as well as Java code paths:

To understand all types of CPU consumers, we previously used both types of profilers, creating a flame graph for each. This worked – sort of. While all CPU consumers could be seen, Java methods were missing from the system profile, which was crucial context we needed. Ideally, we would have one flame graph that shows it all: system and Java code together.

The reason profilers could not generate “mixed-mode” profiles (i.e., profile information from both system code path and Java code paths) was a result of how JVM Just In Time (JIT) compilers were implemented.

To understand this, we need to know that the operating system maintains layers of system calls in a “stack frame”. For example, on x86 machines, the most recent call of the stack frame is referenced by the frame pointer register. System profilers traverse the call stack of the process for profiling, and fetch details from the frame pointer register. Compilers and virtual machines (including the JVM JIT implementations) targeting x86 machines often calculate the offset from the stack pointer and hence they don't need to use the frame pointer register. They instead use the frame pointer as a general purpose register as an optimization. However, this optimization by the JVM JIT implementations break the ability of the profiling tools to traverse the stack and fetch call details.

To support mixed-mode profilers, the JVM has added support for the “-XX:+PreserveFramePointer” option. When this option is supplied, the JVM will abide by the frame pointer intended semantics and not use it as a general purpose register. Because this option disables a compiler optimization, there could be a small performance hit when this option is turned on. However, since this option is disabled by default, there is no performance impact for the default configuration of the JVM.

Brendan’s original post on the OpenJDK mailing list provides details of the patch for hotspot JVM.

InfoQ spoke to Brendan about the flame graphs and the new JDK option.

InfoQ: Does the new JDK option: -XX:+PreserveFramePointer help tools other than profilers, such as debuggers?

Brendan: This can make a difference for any debugger or profiler which uses frame pointers as a stack walking method, which is the traditional technique, e.g., gdb.

InfoQ: The Java bug issue supporting this option describes potential performance hit when this option is enabled. Can you elaborate on that?

Brendan: The performance hit should be small: between 0 and 3% depending on the workload. Microbenchmarks that run tight code may hurt more from lacking an extra register for compiler optimizations; whereas real world workloads should hurt less. The performance hit was much larger in the past. x86 had fewer registers, so by freeing up a register helped more. There were also pipeline stall issues with managing the frame pointer. Both of these problems are much less of a concern with most modern processors.

InfoQ: Can you please share a sample mixed-mode flame graph that was generated with the help of this Java option?

Brendan: I think this is a nice example, and well understood.

With this JVM enhancement, Java developers can now run profilers and generate flame graphs that visualize both system code paths and Java code paths.

The FlameGraph project, which provides flame graph functionality externally, is available as a free download from GitHub. Developers can also download JDK 8 (OpenJDK 8u60 - update 60 build 19) and Java 9 early access releases that support the “-XX:+PreserveFramePointer” option.