我如何使用JNI+JVMTI捕获类似于”unstable_if”的JIT去优化事件?

huangapple go评论89阅读模式
英文:

How can I catch JIT's deoptimization events like "unstable_if" with JNI+JVMTI

问题

我确实思考过如何捕获JIT的去优化事件。
今天,我读了Andrei Pangin的精彩回答当繁忙自旋的Java线程绑定到物理核心时,是否可能因代码中的新分支被触发而发生上下文切换?,并对此再次思考了一下。

我想通过JNI+JVMTI捕获类似于“unstable_if、class_check等”这样的JIT去优化事件,然后将警报发送到我的监控系统或其他任何地方。

这是否可能?
这对JVM性能有什么影响?

英文:

I've realy though about how can I catch JIT's deoptimization events.<br/>
Today, I've read brilliant answer by Andrei Pangin When busy-spining java thread is bound to physical core, can context switch happen by the reason that new branch in code is reached? and thought about it again.

I want to catch JIT's deoptimization events like "unstable_if, class_check and etc" with JNI+JVMTI then send alert to my monitoring system or anything else.

Is it possible?
What is it impact on performance JVM ?

答案1

得分: 6

罕见的陷阱和反优化是HotSpot实现的细节。您在标准接口(专为通用虚拟机设计,而不仅仅是HotSpot)中找不到它们。

如我在先前的答案中建议的,诊断反优化的一种可能方法是添加-XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation选项,并在编译日志中查找&lt;uncommon_trap&gt;

另一种方法是使用async-profiler跟踪反优化事件。
要这样做,使用-e Deoptimization::uncommon_trap_inner
这将向您显示发生反优化的Java代码位置,以及时间戳(如果使用jfr输出格式)。

自JDK 14以来,反优化事件也通过Flight Recorder进行本机报告(JDK-8216041)。使用JMC中的事件浏览器,您可以找到所有罕见的陷阱,包括方法名称,字节码索引,反优化原因等。

上述方法的开销足够小。通常在生产中使用async-profiler没有问题;如果录制设置不多余,JFR也可以使用。

然而,对于非常特殊的情况,对反优化进行分析没有太大用处。对于典型的Java应用程序,多次重新编译方法是绝对正常的,只要JVM在运行时更多地了解应用程序。这可能听起来很奇怪,但罕见的陷阱是一种猜测优化的常见技术 我如何使用JNI+JVMTI捕获类似于”unstable_if”的JIT去优化事件? 正如您在上面的图片中可以看到的,甚至像HashMap.put这样的基本方法也可能导致反优化,这是可以接受的。

英文:

Uncommon traps and deoptimization are HotSpot implementation details. You won't find them in a standard interface like JVM TI (which is designed for a generic virtual machine, not just HotSpot).

As suggested in my previous answer, one possible way to diagnose deoptimization is to add -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation options and to look for &lt;uncommon_trap&gt; in the compilation log.

Another approach is to trace deoptimization events with async-profiler.
To do so, use -e Deoptimization::uncommon_trap_inner.
This will show you the places in Java code where deoptimization happens, and also timestamps, if using jfr output format.

我如何使用JNI+JVMTI捕获类似于”unstable_if”的JIT去优化事件?

Since JDK 14, deoptimization events are also reported natively by Flight Recorder (JDK-8216041). Using Event Browser in JMC, you may find all uncommon traps, including method name, bytecode index, deoptimization reason, etc.

我如何使用JNI+JVMTI捕获类似于”unstable_if”的JIT去优化事件?

The overhead of all the above approaches is small enough. There is usually no problem in using async-profiler in production; JFR is also fine, if the recording settings are not superfluous.

However, there is no much use in profiling deoptimizations, except for very special cases. This is absolutely normal for a typical Java application to recompile methods multiple times, as long as the JVM learns more about the application in runtime. It may sound weird, but uncommon traps is a common technique of the speculative optimization 我如何使用JNI+JVMTI捕获类似于”unstable_if”的JIT去优化事件? As you can see on the above pictures, even basic methods like HashMap.put may cause deoptimization, and this is fine.

答案2

得分: 2

从 JDK 14(基于 OpenJDK)开始,您可以使用事件流 API 在程序中编程访问去优化事件。原生态环境中没有相应的 API。

import jdk.jfr.consumer.RecordingStream;

RecordingStream s = new RecordingStream();
s.enable("jdk.Deoptimization").withStackTrace();
s.onEvent("jdk.Deoptimization", e -> {
  System.out.println("Time: " + e.getEndTime());
  System.out.println("Reason: " + e.getString("reason"));
  System.out.println("Action: " + e.getString("action"));
  System.out.println("Instruction: " + e.getString("instruction"));
  System.out.println("Line Number: " + e.getInt("lineNumber"));
  System.out.println("Bytecode Index" + e.getInt("bci"));
  RecordedMethod m = e.getValue("method");
  RecordedStackTrace st = e.getStackTrace();
  RecordedThread t = e.getThread();
  ...
});
s.start();
英文:

From JDK 14 (based on OpenJDK) you can access deoptimization events programmatically using the Event Steaming API. There is no API from native.

import jdk.jfr.consumer.RecordingStream;

RecordingStream s = new RecordingStream();
s.enable(&quot;jdk.Deoptimization&quot;).withStackTrace();
s.onEvent(&quot;jdk.Deoptimization&quot;, e -&gt; {
  System.out.println(&quot;Time: &quot; + e.getEndTime());
  System.out.println(&quot;Reason: &quot; + e.getString(&quot;reason&quot;));
  System.out.println(&quot;Action: &quot; + e.getString(&quot;action&quot;));
  System.out.println(&quot;Instruction: &quot;+ e.getString(&quot;instruction&quot;));
  System.out.println(&quot;Line Number: &quot; + e.getInt(&quot;lineNumber&quot;));
  System.out.println(&quot;Bytecode Index&quot; + e.getInt(&quot;bci&quot;));
  RecordedMethod m = e.getValue(&quot;method&quot;);
  RecordedStackTrace st = e.getStackTrace();
  RecordedThread t = e.getThread();
  ...
});
s.start();

huangapple
  • 本文由 发表于 2020年10月19日 17:39:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/64424775.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定