英文:
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
选项,并在编译日志中查找<uncommon_trap>
。
另一种方法是使用async-profiler跟踪反优化事件。
要这样做,使用-e Deoptimization::uncommon_trap_inner
。
这将向您显示发生反优化的Java代码位置,以及时间戳(如果使用jfr
输出格式)。
自JDK 14以来,反优化事件也通过Flight Recorder进行本机报告(JDK-8216041)。使用JMC中的事件浏览器,您可以找到所有罕见的陷阱,包括方法名称,字节码索引,反优化原因等。
上述方法的开销足够小。通常在生产中使用async-profiler没有问题;如果录制设置不多余,JFR也可以使用。
然而,对于非常特殊的情况,对反优化进行分析没有太大用处。对于典型的Java应用程序,多次重新编译方法是绝对正常的,只要JVM在运行时更多地了解应用程序。这可能听起来很奇怪,但罕见的陷阱是一种猜测优化的常见技术 正如您在上面的图片中可以看到的,甚至像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 <uncommon_trap>
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.
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.
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 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("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();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论