Skip to content

Commit 72f73fd

Browse files
[GR-39390] Add support for JFR monitor enter events.
PullRequest: graal/12073
2 parents 8da850a + eaa586b commit 72f73fd

File tree

11 files changed

+201
-64
lines changed

11 files changed

+201
-64
lines changed

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ This changelog summarizes major changes to GraalVM Native Image.
44

55
## Version 22.3.0
66
* (GR-35721) Remove old build output style and the `-H:±BuildOutputUseNewStyle` option.
7+
* (GR-39390) Red Hat added support for the JFR event `JavaMonitorEnter`.
78

89
## Version 22.2.0
910
* (GR-20653) Re-enable the usage of all CPU features for JIT compilation on AMD64.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/allocationprofile/AllocationSite.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@
2626

2727
import java.text.DecimalFormat;
2828
import java.util.ArrayList;
29+
import java.util.Collections;
2930
import java.util.Comparator;
3031
import java.util.List;
3132
import java.util.concurrent.ConcurrentHashMap;
3233
import java.util.concurrent.ConcurrentMap;
3334
import java.util.concurrent.atomic.AtomicReference;
3435

36+
import com.oracle.svm.core.jdk.RuntimeFeature;
3537
import org.graalvm.compiler.options.Option;
3638
import org.graalvm.nativeimage.hosted.Feature;
3739

@@ -212,6 +214,11 @@ public static void dumpProfilingResults(final Log log) {
212214

213215
@AutomaticFeature
214216
class AllocationProfilingFeature implements Feature {
217+
@Override
218+
public List<Class<? extends Feature>> getRequiredFeatures() {
219+
return Collections.singletonList(RuntimeFeature.class);
220+
}
221+
215222
@Override
216223
public void afterRegistration(AfterRegistrationAccess access) {
217224
if (AllocationSite.Options.AllocationProfiling.getValue()) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ public enum JfrEvent {
5353
GCPhasePauseLevel4Event("jdk.GCPhasePauseLevel4"),
5454
SafepointBegin("jdk.SafepointBegin"),
5555
SafepointEnd("jdk.SafepointEnd"),
56-
ExecuteVMOperation("jdk.ExecuteVMOperation");
56+
ExecuteVMOperation("jdk.ExecuteVMOperation"),
57+
JavaMonitorEnter("jdk.JavaMonitorEnter");
5758

5859
private final long id;
5960

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrNativeEventWriter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ public static void putThread(JfrNativeEventWriterData data, IsolateThread isolat
216216
if (isolateThread.isNull()) {
217217
putLong(data, 0L);
218218
} else {
219-
long threadId = SubstrateJVM.get().getThreadId(isolateThread);
219+
long threadId = SubstrateJVM.getThreadId(isolateThread);
220220
putLong(data, threadId);
221221
}
222222
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrThreadLocal.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public Target_jdk_jfr_internal_EventWriter newEventWriter() {
167167
long startPos = buffer.getPos().rawValue();
168168
long maxPos = JfrBufferAccess.getDataEnd(buffer).rawValue();
169169
long addressOfPos = JfrBufferAccess.getAddressOfPos(buffer).rawValue();
170-
long jfrThreadId = SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread());
170+
long jfrThreadId = SubstrateJVM.getThreadId(CurrentIsolate.getCurrentThread());
171171
Target_jdk_jfr_internal_EventWriter result = new Target_jdk_jfr_internal_EventWriter(startPos, maxPos, addressOfPos, jfrThreadId, true);
172172
javaEventWriter.set(result);
173173

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/SubstrateJVM.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -255,15 +255,21 @@ public long getStackTraceId(int skipCount) {
255255
}
256256

257257
/** See {@link JVM#getThreadId}. */
258-
public long getThreadId(Thread thread) {
259-
return thread.getId();
258+
public static long getThreadId(Thread thread) {
259+
if (HasJfrSupport.get()) {
260+
return thread.getId();
261+
}
262+
return 0;
260263
}
261264

262265
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
263-
public long getThreadId(IsolateThread isolateThread) {
264-
long threadId = threadLocal.getTraceId(isolateThread);
265-
VMError.guarantee(threadId > 0);
266-
return threadId;
266+
public static long getThreadId(IsolateThread isolateThread) {
267+
if (HasJfrSupport.get()) {
268+
long threadId = get().threadLocal.getTraceId(isolateThread);
269+
VMError.guarantee(threadId > 0);
270+
return threadId;
271+
}
272+
return 0;
267273
}
268274

269275
/** See {@link JVM#storeMetadataDescriptor}. */

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ public long getStackTraceId(int skipCount) {
136136
/** See {@link JVM#getThreadId}. */
137137
@Substitute
138138
public long getThreadId(Thread t) {
139-
return SubstrateJVM.get().getThreadId(t);
139+
return SubstrateJVM.getThreadId(t);
140140
}
141141

142142
/** See {@link JVM#getTicksFrequency}. */
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2022, 2022, Red Hat Inc. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation. Oracle designates this
9+
* particular file as subject to the "Classpath" exception as provided
10+
* by Oracle in the LICENSE file that accompanied this code.
11+
*
12+
* This code is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15+
* version 2 for more details (a copy is included in the LICENSE file that
16+
* accompanied this code).
17+
*
18+
* You should have received a copy of the GNU General Public License version
19+
* 2 along with this work; if not, write to the Free Software Foundation,
20+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21+
*
22+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23+
* or visit www.oracle.com if you need additional information or have any
24+
* questions.
25+
*/
26+
27+
package com.oracle.svm.core.jfr.events;
28+
29+
import com.oracle.svm.core.jfr.HasJfrSupport;
30+
import org.graalvm.nativeimage.StackValue;
31+
32+
import com.oracle.svm.core.annotate.Uninterruptible;
33+
import com.oracle.svm.core.jfr.JfrEvent;
34+
import com.oracle.svm.core.jfr.JfrNativeEventWriter;
35+
import com.oracle.svm.core.jfr.JfrNativeEventWriterData;
36+
import com.oracle.svm.core.jfr.JfrNativeEventWriterDataAccess;
37+
import com.oracle.svm.core.jfr.JfrTicks;
38+
import com.oracle.svm.core.jfr.SubstrateJVM;
39+
40+
public class JavaMonitorEnterEvent {
41+
public static void emit(Object obj, long previousOwnerTid, long startTicks) {
42+
if (HasJfrSupport.get()) {
43+
emit0(obj, previousOwnerTid, startTicks);
44+
}
45+
}
46+
47+
@Uninterruptible(reason = "Accesses a JFR buffer.")
48+
public static void emit0(Object obj, long previousOwnerTid, long startTicks) {
49+
if (SubstrateJVM.isRecording() && SubstrateJVM.get().isEnabled(JfrEvent.JavaMonitorEnter)) {
50+
JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class);
51+
JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data);
52+
53+
JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.JavaMonitorEnter);
54+
JfrNativeEventWriter.putLong(data, startTicks);
55+
JfrNativeEventWriter.putLong(data, JfrTicks.elapsedTicks() - startTicks);
56+
JfrNativeEventWriter.putEventThread(data);
57+
JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.JavaMonitorEnter.getId(), 0));
58+
JfrNativeEventWriter.putClass(data, obj.getClass());
59+
JfrNativeEventWriter.putLong(data, previousOwnerTid);
60+
JfrNativeEventWriter.putLong(data, org.graalvm.compiler.word.Word.objectToUntrackedPointer(obj).rawValue());
61+
JfrNativeEventWriter.endSmallEvent(data);
62+
63+
}
64+
}
65+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2022, 2022, Red Hat Inc. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation. Oracle designates this
9+
* particular file as subject to the "Classpath" exception as provided
10+
* by Oracle in the LICENSE file that accompanied this code.
11+
*
12+
* This code is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15+
* version 2 for more details (a copy is included in the LICENSE file that
16+
* accompanied this code).
17+
*
18+
* You should have received a copy of the GNU General Public License version
19+
* 2 along with this work; if not, write to the Free Software Foundation,
20+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21+
*
22+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23+
* or visit www.oracle.com if you need additional information or have any
24+
* questions.
25+
*/
26+
27+
package com.oracle.svm.core.monitor;
28+
29+
import java.util.concurrent.locks.ReentrantLock;
30+
31+
import org.graalvm.nativeimage.CurrentIsolate;
32+
33+
import com.oracle.svm.core.SubstrateUtil;
34+
import com.oracle.svm.core.jfr.JfrTicks;
35+
import com.oracle.svm.core.jfr.SubstrateJVM;
36+
import com.oracle.svm.core.jfr.events.JavaMonitorEnterEvent;
37+
38+
public class JavaMonitor extends ReentrantLock {
39+
private static final long serialVersionUID = 3921577070627519721L;
40+
41+
private long latestJfrTid;
42+
43+
public JavaMonitor() {
44+
Target_java_util_concurrent_locks_ReentrantLock lock = SubstrateUtil.cast(this, Target_java_util_concurrent_locks_ReentrantLock.class);
45+
Target_java_util_concurrent_locks_ReentrantLock_NonfairSync sync = SubstrateUtil.cast(lock.sync, Target_java_util_concurrent_locks_ReentrantLock_NonfairSync.class);
46+
sync.objectMonitorCondition = SubstrateUtil.cast(MultiThreadedMonitorSupport.MONITOR_WITHOUT_CONDITION, Target_java_util_concurrent_locks_AbstractQueuedSynchronizer_ConditionObject.class);
47+
latestJfrTid = 0;
48+
}
49+
50+
/**
51+
* Creates a new {@link ReentrantLock} that is locked by the provided thread. This requires
52+
* patching of internal state, since there is no public API in {@link ReentrantLock} to do that
53+
* (for a good reason, because it is a highly unusual operation).
54+
*/
55+
public static JavaMonitor newLockedMonitorForThread(Thread thread, int recursionDepth) {
56+
JavaMonitor result = new JavaMonitor();
57+
for (int i = 0; i < recursionDepth; i++) {
58+
result.lock();
59+
}
60+
61+
result.latestJfrTid = SubstrateJVM.getThreadId(thread);
62+
Target_java_util_concurrent_locks_ReentrantLock lock = SubstrateUtil.cast(result, Target_java_util_concurrent_locks_ReentrantLock.class);
63+
Target_java_util_concurrent_locks_AbstractOwnableSynchronizer sync = SubstrateUtil.cast(lock.sync, Target_java_util_concurrent_locks_AbstractOwnableSynchronizer.class);
64+
65+
assert sync.exclusiveOwnerThread == Thread.currentThread() : "Must be locked by current thread";
66+
sync.exclusiveOwnerThread = thread;
67+
68+
return result;
69+
}
70+
71+
public void monitorEnter(Object obj) {
72+
if (!tryLock()) {
73+
long startTicks = JfrTicks.elapsedTicks();
74+
lock();
75+
JavaMonitorEnterEvent.emit(obj, latestJfrTid, startTicks);
76+
}
77+
78+
latestJfrTid = SubstrateJVM.getThreadId(CurrentIsolate.getCurrentThread());
79+
}
80+
}

0 commit comments

Comments
 (0)