Using the Flight Recorder Parsers

This blog post is the second in a series of posts on using unsupported functionality in the Oracle JDK and/or Java Mission Control.

Just as there is no supported way to add custom events to the Java Flight Recorder (yet), there is even less in terms of programmatic support to read recordings. There are however two different unsupported parsers available. Both are POJO APIs, and except for supportability / future API breakage issues, there is in practice nothing stopping you from using either one to read your recordings.

Disclaimer:

The following blog entry will describe UNSUPPORTED functionality. This means that relying on the described APIs or functionality may BREAK your code/plugin with any given update of the JDK and/or Mission Control.

I strongly recommend against using these APIs in production code. There will be supported APIs for reading reading recordings eventually and they may be quite different. Also note that older versions of the parsers are not guaranteed to be forward compatible with newer versions of the binary format. In short, this is NOT supported and WILL CHANGE!

That said, it can sometimes be quite useful to have programmatic access to flight recorder data. One could, for example, do automatic filtering and/or reporting on recordings, and then use JMC to do detailed analysis on the ones that are flagged as interesting.

The Reference Parser

The reference parser shipped with the Oracle JDK can be likened to a SAX XML parser. It allows you to iterate through the recording, uses little memory, is somewhat limited, and provides a very simple Java model. If your needs are simple, this may be the perfect parser to use. It is available by default in JDK 7u4 and later. The parser API is located in the JDK_HOME/jre/lib/jfr.jar file.

Here is an example snippet that iterates through a recording and prints out the total event count:

import java.io.File;
import java.io.IOException;
import java.util.Iterator;

import oracle.jrockit.jfr.parser.*;

public class JDKParserTest {
    @SuppressWarnings("deprecation")
    public static void main(String[] args) throws IOException {
        File recordingFile = new File("C:\\demo\\wldf.jfr");
        Parser parser = new Parser(recordingFile);
        int count = 0;
        Iterator<ChunkParser> chunkIter = parser.iterator();
        while (chunkIter.hasNext()) {           
            ChunkParser chunkParser = chunkIter.next();
            for (FLREvent event : chunkParser) {
                count++;
                //System.out.println(event.toString());
            }
        }
        parser.close();
        System.out.println("Found " + count + " events");
    }
}   

I will not spend too much time on this parser.

Strengths:

  • Uses little memory
  • Included in the Hotspot JDK (>=7u4)

Weaknesses:

  • Slow
  • Simple model/API

The JMC Parser

If the reference parser is the SAX XML parser equivalent, then the JMC parser is the DOM equivalent. The jar for the parser is easily nicked from the JMC distribution, either from the update site or from the JDK installation. In the JDK, you’ll find the jar containing the JMC flight recorder parser at JDK_HOME/lib/missioncontrol/plugins/com.jrockit.mc.flightrecorder_<version>.jar.

You will also need to add the JDK_HOME/lib/missioncontrol/plugins/com.jrockit.mc.common_<version>.jar to your path.

Here is the equivalent event counting example using the JMC parser:

import java.io.File;

import com.jrockit.mc.flightrecorder.FlightRecording;
import com.jrockit.mc.flightrecorder.FlightRecordingLoader;
import com.jrockit.mc.flightrecorder.spi.IEvent;
import com.jrockit.mc.flightrecorder.spi.IView;

public class FlightRecorderParserTest {
    public static void main(String[] args) throws ClassNotFoundException {
        FlightRecording recording = FlightRecordingLoader.loadFile(new File("C:\\demo\\wldf.jfr"));    
        IView view = recording.createView();

        int count = 0;
        for (IEvent event : view) {
            count++;
        }
        System.out.println("Fount " + count + " events");
    }
}

Strengths:

  • Fast
  • The jar can be used with any JDK (>=6)
  • Rich API
  • Good for complex analysis scenarios

Weaknesses:

  • Builds a Java model of the recording – uses more memory

Summary

This blog post lists two different UNSUPPORTED parsers that can be used to read java flight recordings programmatically from Java. A very simple example showing how to iterate through the events in a recording was shown for both of the parsers.

6 Responses to "Using the Flight Recorder Parsers"

  1. Lewis says:

    Marcus,

    Using JDK 1.7.0_55, I create a long recording (10 hours).

    There are multiple recordings files, created from startup, in the JMC\work directory using :-

    -XX:FlightRecorderOptions=repository=C:\JMC\work,disk=true,maxage=10h.

    I would like to merge these files together to create a single .jfr file as the JMC does.

    Any pointers would be very helpful!

    Kind regards

    Lewis

  2. Liudmila says:

    Hi! API, described in this article does not allow to parse jfr files that were generated by new Java 9 Flight Recorder. Here is the repository that gets stacktraces from jfr file using new JMC Parser: https://github.com/kornilova-l/flight-recorder-parser-for-java-9

  3. Marcus says:

    Another way to parse JDK 7, 8 and 9 recordings (supports all versions), would be to use this:
    http://hirt.se/blog/?p=920

    Then you will also have automated analysis of the flight recordings available to you. Note that all of this will be open sourced next year.

  4. Liudmila says:

    Thanks! I did not read this article

  5. Paulo says:

    Hi, I am trying to parse a .jfr file generated by async-profiler. They use JMC 5.5 file format, as described in this issue (https://github.com/jvm-profiling-tools/async-profiler/issues/134).

    I implemented the code described in this post to parse the jfr file but I’m having the following error. Please, can you give me any tip to parse it? I tryed with oracle jdk 1.7.0_04 and 1.8.0_202.

    Exception in thread “main” java.lang.RuntimeException: java.nio.BufferUnderflowException
    at oracle.jrockit.jfr.parser.Parser$1.hasNext(Parser.java:165)
    at JDKParserTest.main(JDKParserTest.java:16)
    Caused by: java.nio.BufferUnderflowException
    at java.nio.Buffer.nextGetIndex(Buffer.java:506)
    at java.nio.DirectByteBuffer.getInt(DirectByteBuffer.java:681)
    at oracle.jrockit.jfr.parser.MappedFLRInput.getInt(MappedFLRInput.java:79)
    at oracle.jrockit.jfr.parser.ChunkParser.readDescriptors(ChunkParser.java:552)
    at oracle.jrockit.jfr.parser.ChunkParser.begin(ChunkParser.java:230)
    at oracle.jrockit.jfr.parser.ChunkParser.(ChunkParser.java:95)
    at oracle.jrockit.jfr.parser.Parser.next(Parser.java:124)
    at oracle.jrockit.jfr.parser.Parser$1.hasNext(Parser.java:163)
    … 1 more

  6. Marcus says:

    The JDK API can only be used to open recordings from the same version. To parse all versions, including Oracle JDK 7 (JFR 0.9+), use the JMC parser. For more info, see https://github.com/openjdk/jmc, and e.g. https://github.com/thegreystone/jmc-jshell.

Leave a Reply

Your email address will not be published. Required fields are marked *