2

I would like to be able to extract, in a textual format, some kind of a summary of the 'hot spots' detected by analyzing a JFR recording. To be precise, I would like to extract the hot-spots resulting from running some specific functions or some specific class. Something like this:

<some tool> myfile.jfr --look-at-class='org/me/MyClass' --limit 10 --order-by self-time

And obtain a table of the most time-consuming 10 methods methods called from MyClass in org.me. I tried looking at the jfr command-line tool, but it does not have such functionality. Alternatively, JMC only has a graphical interface, but not a command-line interface. Is there another way to obtain such a result?

Alex Shtoff
  • 2,520
  • 1
  • 25
  • 53

1 Answers1

2

It's easy to create such a tool using JFR Parsing API.

import jdk.jfr.consumer.RecordingFile;

import java.nio.file.Paths;
import java.util.HashMap;

public class JfrTop {

    public static void main(String[] args) throws Exception {
        var fileName = args[0];
        var packageName = args.length > 1 ? args[1] : "";
        var top = args.length > 2 ? Integer.parseInt(args[2]) : 10;

        var hotMethods = new HashMap<String, Long>();
        long total = 0;

        try (var recording = new RecordingFile(Paths.get(fileName))) {
            while (recording.hasMoreEvents()) {
                var event = recording.readEvent();
                if (event.getEventType().getName().equals("jdk.ExecutionSample")) {
                    var stackTrace = event.getStackTrace();
                    if (stackTrace != null && stackTrace.getFrames().size() > 0) {
                        var method = stackTrace.getFrames().get(0).getMethod();
                        var className = method.getType().getName();
                        if (className.startsWith(packageName)) {
                            var fullName = className + '.' + method.getName() + method.getDescriptor();
                            hotMethods.compute(fullName, (key, val) -> val == null ? 1L : (val + 1));
                        }
                    }
                    total++;
                }
            }
        }

        double percent = 100.0 / total;
        hotMethods.entrySet().stream()
                .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
                .limit(top)
                .forEachOrdered(e -> System.out.printf("%5.2f%% %s\n", e.getValue() * percent, e.getKey()));
    }
}

How to run:

java JfrTop idea.jfr com.intellij.openapi.editor 10

Sample output:

20,35% com.intellij.openapi.editor.impl.RangeHighlighterTree$RHNode.recalculateRenderFlags()V
 4,20% com.intellij.openapi.editor.impl.IntervalTreeImpl.maxEndOf(Lcom/intellij/openapi/editor/impl/IntervalTreeImpl$IntervalNode;I)I
 3,19% com.intellij.openapi.editor.impl.IntervalTreeImpl.assertAllDeltasAreNull(Lcom/intellij/openapi/editor/impl/IntervalTreeImpl$IntervalNode;)V
 2,19% com.intellij.openapi.editor.impl.IntervalTreeImpl$IntervalNode.computeDeltaUpToRoot()I
 1,94% com.intellij.openapi.editor.impl.IntervalTreeImpl.pushDelta(Lcom/intellij/openapi/editor/impl/IntervalTreeImpl$IntervalNode;)Z
 1,63% com.intellij.openapi.editor.impl.IntervalTreeImpl$IntervalNode.hasAliveKey(Z)Z
 1,50% com.intellij.openapi.editor.impl.IntervalTreeImpl.correctMax(Lcom/intellij/openapi/editor/impl/IntervalTreeImpl$IntervalNode;I)V
 1,31% com.intellij.openapi.editor.impl.IntervalTreeImpl$1.hasNext()Z
 0,88% com.intellij.openapi.editor.impl.IntervalTreeImpl$IntervalNode.tryToSetCachedValues(IZI)Z
 0,63% com.intellij.openapi.editor.impl.IntervalTreeImpl.findOrInsert(Lcom/intellij/openapi/editor/impl/IntervalTreeImpl$IntervalNode;)Lcom/intellij/openapi/editor/impl/IntervalTreeImpl$IntervalNode;
apangin
  • 92,924
  • 10
  • 193
  • 247
  • Is there an alternative to the JFR parsing API on JDK8? It seems not to be available. – Alex Shtoff Apr 22 '20 at 08:27
  • @AlexShtof Yes, see [this answer](https://stackoverflow.com/a/37290020/3448419) – apangin Apr 22 '20 at 10:02
  • You can also use the JMC core library to parse and perform various operations on any given JFR file (both old and new). It’s not available from maven central, but building the source locally is very simple. – Henrik Dafgård Aug 03 '20 at 12:44