Skip to content

Commit 6864634

Browse files
iignatevMarkus Grönlund
authored andcommitted
8216041: [Event Request] - Deoptimization
Reviewed-by: iignatyev, vlivanov, egahlin
1 parent fec6f8a commit 6864634

File tree

11 files changed

+270
-5
lines changed

11 files changed

+270
-5
lines changed

src/hotspot/share/code/codeBlob.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class CodeBlob {
147147
inline bool is_compiled_by_c2() const { return _type == compiler_c2; };
148148
inline bool is_compiled_by_jvmci() const { return _type == compiler_jvmci; };
149149
const char* compiler_name() const;
150+
CompilerType compiler_type() const { return _type; }
150151

151152
// Casting
152153
nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; }

src/hotspot/share/compiler/compileBroker.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2019,8 +2019,10 @@ void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, bool
20192019
static void post_compilation_event(EventCompilation* event, CompileTask* task) {
20202020
assert(event != NULL, "invariant");
20212021
assert(event->should_commit(), "invariant");
2022-
event->set_method(task->method());
2022+
assert(task != NULL, "invariant");
20232023
event->set_compileId(task->compile_id());
2024+
event->set_compiler(task->compiler()->type());
2025+
event->set_method(task->method());
20242026
event->set_compileLevel(task->comp_level());
20252027
event->set_succeded(task->is_success());
20262028
event->set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);

src/hotspot/share/jfr/metadata/metadata.xml

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,8 +465,9 @@
465465
</Event>
466466

467467
<Event name="Compilation" category="Java Virtual Machine, Compiler" label="Compilation" thread="true">
468-
<Field type="Method" name="method" label="Java Method" />
469468
<Field type="uint" name="compileId" label="Compilation Identifier" relation="CompileId" />
469+
<Field type="CompilerType" name="compiler" label="Compiler" />
470+
<Field type="Method" name="method" label="Method" />
470471
<Field type="ushort" name="compileLevel" label="Compilation Level" />
471472
<Field type="boolean" name="succeded" label="Succeeded" />
472473
<Field type="boolean" name="isOsr" label="On Stack Replacement" />
@@ -497,7 +498,7 @@
497498
<Field type="CalleeMethod" name="callee" struct="true" label="Callee Method" />
498499
<Field type="boolean" name="succeeded" label="Succeeded" />
499500
<Field type="string" name="message" label="Message" />
500-
<Field type="int" name="bci" label="Byte Code Index" />
501+
<Field type="int" name="bci" label="Bytecode Index" />
501502
</Event>
502503

503504
<Event name="SweepCodeCache" category="Java Virtual Machine, Code Sweeper" label="Sweep Code Cache" thread="true" >
@@ -519,6 +520,17 @@
519520
<Field type="int" name="fullCount" label="Full Count" />
520521
</Event>
521522

523+
<Event name="Deoptimization" category="Java Virtual Machine, Compiler" label="Deoptimization" thread="true" stackTrace="true" startTime="false">
524+
<Field type="uint" name="compileId" label="Compilation Identifier" relation="CompileId" />
525+
<Field type="CompilerType" name="compiler" label="Compiler" />
526+
<Field type="Method" name="method" label="Method" />
527+
<Field type="int" name="lineNumber" label="Line Number" />
528+
<Field type="int" name="bci" label="Bytecode Index" />
529+
<Field type="Bytecode" name="instruction" label="Instruction" />
530+
<Field type="DeoptimizationReason" name="reason" label="Reason"/>
531+
<Field type="DeoptimizationAction" name="action" label="Action"/>
532+
</Event>
533+
522534
<Event name="SafepointBegin" category="Java Virtual Machine, Runtime, Safepoint" label="Safepoint Begin" description="Safepointing begin" thread="true">
523535
<Field type="ulong" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
524536
<Field type="int" name="totalThreadCount" label="Total Threads" description="The total number of threads at the start of safe point" />
@@ -1041,6 +1053,22 @@
10411053
<Field type="ulong" contentType="bytes" name="size" label="Size Written" />
10421054
</Event>
10431055

1056+
<Type name="DeoptimizationReason" label="Deoptimization Reason">
1057+
<Field type="string" name="reason" label="Reason" />
1058+
</Type>
1059+
1060+
<Type name="DeoptimizationAction" label="Deoptimization Action">
1061+
<Field type="string" name="action" label="Action" />
1062+
</Type>
1063+
1064+
<Type name="Bytecode" label="Bytecode Instruction">
1065+
<Field type="string" name="bytecode" label="Instruction" />
1066+
</Type>
1067+
1068+
<Type name="CompilerType" label="Compiler Type">
1069+
<Field type="string" name="compiler" label="Compiler" />
1070+
</Type>
1071+
10441072
<Type name="ZStatisticsCounterType" label="Z Statistics Counter">
10451073
<Field type="string" name="counter" label="Counter" />
10461074
</Type>

src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "classfile/javaClasses.inline.hpp"
2727
#include "code/codeBlob.hpp"
2828
#include "code/codeCache.hpp"
29+
#include "compiler/compilerDefinitions.hpp"
2930
#include "gc/shared/gcCause.hpp"
3031
#include "gc/shared/gcName.hpp"
3132
#include "gc/shared/gcTrace.hpp"
@@ -293,3 +294,21 @@ void JfrThreadConstant::serialize(JfrCheckpointWriter& writer) {
293294
writer.write((traceid)0); // java thread id
294295
writer.write((traceid)0); // java thread group
295296
}
297+
298+
void BytecodeConstant::serialize(JfrCheckpointWriter& writer) {
299+
static const u4 nof_entries = Bytecodes::number_of_codes;
300+
writer.write_count(nof_entries);
301+
for (u4 i = 0; i < nof_entries; ++i) {
302+
writer.write_key(i);
303+
writer.write(Bytecodes::name((Bytecodes::Code)i));
304+
}
305+
}
306+
307+
void CompilerTypeConstant::serialize(JfrCheckpointWriter& writer) {
308+
static const u4 nof_entries = compiler_number_of_types;
309+
writer.write_count(nof_entries);
310+
for (u4 i = 0; i < nof_entries; ++i) {
311+
writer.write_key(i);
312+
writer.write(compilertype2name((CompilerType)i));
313+
}
314+
}

src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,14 @@ class JfrThreadConstant : public JfrSerializer {
115115
void serialize(JfrCheckpointWriter& writer);
116116
};
117117

118+
class BytecodeConstant : public JfrSerializer {
119+
public:
120+
void serialize(JfrCheckpointWriter& writer);
121+
};
122+
123+
class CompilerTypeConstant : public JfrSerializer {
124+
public:
125+
void serialize(JfrCheckpointWriter& writer);
126+
};
127+
118128
#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPE_HPP

src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ bool JfrTypeManager::initialize() {
222222
register_static_type(TYPE_CODEBLOBTYPE, true, new CodeBlobTypeConstant());
223223
register_static_type(TYPE_VMOPERATIONTYPE, true, new VMOperationTypeConstant());
224224
register_static_type(TYPE_THREADSTATE, true, new ThreadStateConstant());
225+
register_static_type(TYPE_BYTECODE, true, new BytecodeConstant());
226+
register_static_type(TYPE_COMPILERTYPE, true, new CompilerTypeConstant());
225227
return true;
226228
}
227229

src/hotspot/share/runtime/deoptimization.cpp

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@
5656
#include "runtime/fieldDescriptor.hpp"
5757
#include "runtime/fieldDescriptor.inline.hpp"
5858
#include "runtime/frame.inline.hpp"
59-
#include "runtime/jniHandles.inline.hpp"
6059
#include "runtime/handles.inline.hpp"
6160
#include "runtime/interfaceSupport.inline.hpp"
61+
#include "runtime/jniHandles.inline.hpp"
6262
#include "runtime/safepointVerifiers.hpp"
6363
#include "runtime/sharedRuntime.hpp"
6464
#include "runtime/signature.hpp"
@@ -69,9 +69,13 @@
6969
#include "runtime/vframeArray.hpp"
7070
#include "runtime/vframe_hp.hpp"
7171
#include "utilities/events.hpp"
72+
#include "utilities/macros.hpp"
7273
#include "utilities/preserveException.hpp"
7374
#include "utilities/xmlstream.hpp"
74-
75+
#if INCLUDE_JFR
76+
#include "jfr/jfrEvents.hpp"
77+
#include "jfr/metadata/jfrSerializer.hpp"
78+
#endif
7579

7680
bool DeoptimizationMarker::_is_active = false;
7781

@@ -1652,6 +1656,69 @@ void Deoptimization::load_class_by_index(const constantPoolHandle& constant_pool
16521656
}
16531657
}
16541658

1659+
#if INCLUDE_JFR
1660+
1661+
class DeoptReasonSerializer : public JfrSerializer {
1662+
public:
1663+
void serialize(JfrCheckpointWriter& writer) {
1664+
writer.write_count((u4)(Deoptimization::Reason_LIMIT + 1)); // + Reason::many (-1)
1665+
for (int i = -1; i < Deoptimization::Reason_LIMIT; ++i) {
1666+
writer.write_key((u8)i);
1667+
writer.write(Deoptimization::trap_reason_name(i));
1668+
}
1669+
}
1670+
};
1671+
1672+
class DeoptActionSerializer : public JfrSerializer {
1673+
public:
1674+
void serialize(JfrCheckpointWriter& writer) {
1675+
static const u4 nof_actions = Deoptimization::Action_LIMIT;
1676+
writer.write_count(nof_actions);
1677+
for (u4 i = 0; i < Deoptimization::Action_LIMIT; ++i) {
1678+
writer.write_key(i);
1679+
writer.write(Deoptimization::trap_action_name((int)i));
1680+
}
1681+
}
1682+
};
1683+
1684+
static void register_serializers() {
1685+
static int critical_section = 0;
1686+
if (1 == critical_section || Atomic::cmpxchg(&critical_section, 0, 1) == 1) {
1687+
return;
1688+
}
1689+
JfrSerializer::register_serializer(TYPE_DEOPTIMIZATIONREASON, true, new DeoptReasonSerializer());
1690+
JfrSerializer::register_serializer(TYPE_DEOPTIMIZATIONACTION, true, new DeoptActionSerializer());
1691+
}
1692+
1693+
static void post_deoptimization_event(CompiledMethod* nm,
1694+
const Method* method,
1695+
int trap_bci,
1696+
int instruction,
1697+
Deoptimization::DeoptReason reason,
1698+
Deoptimization::DeoptAction action) {
1699+
assert(nm != NULL, "invariant");
1700+
assert(method != NULL, "invariant");
1701+
if (EventDeoptimization::is_enabled()) {
1702+
static bool serializers_registered = false;
1703+
if (!serializers_registered) {
1704+
register_serializers();
1705+
serializers_registered = true;
1706+
}
1707+
EventDeoptimization event;
1708+
event.set_compileId(nm->compile_id());
1709+
event.set_compiler(nm->compiler_type());
1710+
event.set_method(method);
1711+
event.set_lineNumber(method->line_number_from_bci(trap_bci));
1712+
event.set_bci(trap_bci);
1713+
event.set_instruction(instruction);
1714+
event.set_reason(reason);
1715+
event.set_action(action);
1716+
event.commit();
1717+
}
1718+
}
1719+
1720+
#endif // INCLUDE_JFR
1721+
16551722
JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint trap_request)) {
16561723
HandleMark hm;
16571724

@@ -1746,6 +1813,8 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
17461813
MethodData* trap_mdo =
17471814
get_method_data(thread, profiled_method, create_if_missing);
17481815

1816+
JFR_ONLY(post_deoptimization_event(nm, trap_method(), trap_bci, trap_bc, reason, action);)
1817+
17491818
// Log a message
17501819
Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d %s",
17511820
trap_reason_name(reason), trap_action_name(action), p2i(fr.pc()),

src/jdk.jfr/share/conf/jfr/default.jfc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,11 @@
728728
<setting name="threshold">0 ms</setting>
729729
</event>
730730

731+
<event name="jdk.Deoptimization">
732+
<setting name="enabled">true</setting>
733+
<setting name="stackTrace">false</setting>
734+
</event>
735+
731736

732737

733738

src/jdk.jfr/share/conf/jfr/profile.jfc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,10 @@
728728
<setting name="threshold">0 ms</setting>
729729
</event>
730730

731+
<event name="jdk.Deoptimization">
732+
<setting name="enabled">true</setting>
733+
<setting name="stackTrace">true</setting>
734+
</event>
731735

732736

733737

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package jdk.jfr.event.compiler;
27+
28+
import java.util.List;
29+
import java.util.stream.Collectors;
30+
31+
import jdk.jfr.Recording;
32+
import jdk.jfr.consumer.RecordedEvent;
33+
import jdk.test.lib.Asserts;
34+
import jdk.test.lib.jfr.EventNames;
35+
import jdk.test.lib.jfr.Events;
36+
37+
// THIS TEST IS LINE NUMBER SENSITIVE
38+
39+
// Careful if moving this class or method somewhere since verifyDeoptimizationEventFields asserts the linenumber
40+
class Dummy {
41+
static void dummyMethod(boolean b) {
42+
if (b) {
43+
return;
44+
}
45+
}
46+
}
47+
48+
/**
49+
* @test
50+
* @key jfr
51+
* @summary sanity test for Deoptimization event, depends on Compilation event
52+
* @requires vm.hasJFR
53+
* @requires vm.compMode != "Xint"
54+
* @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == 4 | vm.opt.TieredStopAtLevel == null)
55+
* @library /test/lib
56+
* @run main/othervm -XX:-BackgroundCompilation jdk.jfr.event.compiler.TestDeoptimization
57+
*/
58+
public class TestDeoptimization {
59+
private final static String TYPE_NAME = Dummy.class.getName().replace(".", "/");
60+
private final static String METHOD_NAME = "dummyMethod";
61+
private static final String METHOD_DESCRIPTOR = "(Z)V";
62+
private static final String COMPILER = "c2";
63+
64+
public static void main(String[] args) throws Throwable {
65+
new TestDeoptimization().doTest();
66+
}
67+
68+
public void doTest() throws Throwable {
69+
Recording recording = new Recording();
70+
recording.enable(EventNames.Deoptimization);
71+
recording.enable(EventNames.Compilation);
72+
recording.start();
73+
74+
long start = System.currentTimeMillis();
75+
// compile dummyMethod
76+
for (int i = 0; i < 20000; i++) {
77+
Dummy.dummyMethod(false);
78+
}
79+
// provoke deoptimization by executing the uncommon trap in dummyMethod
80+
Dummy.dummyMethod(true);
81+
System.out.println("Time to load, compile and deoptimize dummyMethod: " + (System.currentTimeMillis() - start));
82+
recording.stop();
83+
84+
List<RecordedEvent> events = Events.fromRecording(recording);
85+
Events.hasEvents(events);
86+
87+
// get compile ids for all compilations of dummyMethod
88+
List<Integer> compileIds = events.stream()
89+
.filter(e -> e.getEventType().getName().equals(EventNames.Compilation))
90+
.filter(TestDeoptimization::isForDummyMethod)
91+
.map(e -> Events.assertField(e, "compileId").<Integer>getValue())
92+
.collect(Collectors.toList());
93+
Asserts.assertFalse(compileIds.isEmpty(),
94+
"couldn't find any " + EventNames.Compilation + " for " + METHOD_NAME);
95+
96+
// get all deoptimization events associated with the compile ids
97+
List<RecordedEvent> deoptEventsForCompileIds = events.stream()
98+
.filter(e -> e.getEventType().getName().equals(EventNames.Deoptimization))
99+
.filter(e -> compileIds.contains(Events.assertField(e, "compileId").<Integer>getValue()))
100+
.collect(Collectors.toList());
101+
Asserts.assertFalse(deoptEventsForCompileIds.isEmpty(),
102+
"couldn't find any " + EventNames.Deoptimization + " for ids : " + compileIds);
103+
104+
// verify deoptimization event fields
105+
deoptEventsForCompileIds.forEach(this::verifyDeoptimizationEventFields);
106+
}
107+
108+
static boolean isForDummyMethod(RecordedEvent e) {
109+
return TYPE_NAME.equals(Events.assertField(e, "method.type.name").getValue())
110+
&& METHOD_NAME.equals(Events.assertField(e, "method.name").getValue())
111+
&& METHOD_DESCRIPTOR.equals(Events.assertField(e, "method.descriptor").getValue());
112+
}
113+
114+
private void verifyDeoptimizationEventFields(RecordedEvent event) {
115+
Events.assertEventThread(event);
116+
Events.assertField(event, "compileId").atLeast(0);
117+
Events.assertField(event, "compiler").equal(COMPILER);
118+
Events.assertField(event, "lineNumber").equal(42);
119+
Events.assertField(event, "bci").equal(1);
120+
Events.assertField(event, "instruction").equal("ifeq");
121+
Events.assertField(event, "action").notEmpty().equal("reinterpret");
122+
Events.assertField(event, "reason").notEmpty().equal("unstable_if");
123+
}
124+
}

0 commit comments

Comments
 (0)