Skip to content

Commit 26cea85

Browse files
[GR-40033] Implement JFR MonitorWaitEvent.
PullRequest: graal/12324
2 parents dde1006 + 0a6d9ca commit 26cea85

File tree

5 files changed

+92
-56
lines changed

5 files changed

+92
-56
lines changed

substratevm/CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ 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) (GR-39649) Red Hat added support for the JFR events `JavaMonitorEnter` and `ThreadSleep`.
7+
* (GR-39390) (GR-39649) (GR-40033) Red Hat added support for the JFR events `JavaMonitorEnter`, `JavaMonitorWait`, and `ThreadSleep`.
88
* (GR-39497) Add `-H:BuildOutputJSONFile=<file.json>` option for [JSON build output](https://github.com/oracle/graal/edit/master/docs/reference-manual/native-image/BuildOutput.md#machine-readable-build-output). Please feel free to provide feedback so that we can stabilize the schema/API.
99

1010
## Version 22.2.0
1111
* (GR-20653) Re-enable the usage of all CPU features for JIT compilation on AMD64.
1212
* (GR-38413) Add support for `-XX:+ExitOnOutOfMemoryError`.
1313
* (GR-37606) Add support for URLs and short descriptions to `Feature`. This info is shown as part of the build output.
14-
* (GR-38965) Heap dumps are now supported in Community Edition.
14+
* (GR-38965) Heap dumps are now supported in Community Edition.
1515
* (GR-38951) Add `-XX:+DumpHeapAndExit` option to dump the initial heap of a native executable.
1616
* (GR-37582) Run image-builder on module-path per default. Opt-out with env setting `USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false`.
1717
* (GR-38660) Expose -H:Name=<outfile> as API option -o <outfile>

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
@@ -55,7 +55,8 @@ public enum JfrEvent {
5555
SafepointEnd("jdk.SafepointEnd"),
5656
ExecuteVMOperation("jdk.ExecuteVMOperation"),
5757
JavaMonitorEnter("jdk.JavaMonitorEnter"),
58-
ThreadSleep("jdk.ThreadSleep");
58+
ThreadSleep("jdk.ThreadSleep"),
59+
JavaMonitorWait("jdk.JavaMonitorWait");
5960

6061
private final long id;
6162

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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.annotate.Uninterruptible;
30+
import com.oracle.svm.core.jfr.JfrEvent;
31+
import com.oracle.svm.core.jfr.JfrNativeEventWriter;
32+
import com.oracle.svm.core.jfr.JfrNativeEventWriterData;
33+
import com.oracle.svm.core.jfr.JfrNativeEventWriterDataAccess;
34+
import com.oracle.svm.core.jfr.JfrTicks;
35+
import com.oracle.svm.core.jfr.SubstrateJVM;
36+
import org.graalvm.compiler.word.Word;
37+
import com.oracle.svm.core.jfr.HasJfrSupport;
38+
39+
public class JavaMonitorWaitEvent {
40+
public static void emit(long startTicks, Object obj, long notifier, long timeout, boolean timedOut) {
41+
if (HasJfrSupport.get()) {
42+
emit0(startTicks, obj, notifier, timeout, timedOut);
43+
}
44+
}
45+
46+
@Uninterruptible(reason = "Accesses a JFR buffer.")
47+
private static void emit0(long startTicks, Object obj, long notifier, long timeout, boolean timedOut) {
48+
if (SubstrateJVM.isRecording() && SubstrateJVM.get().isEnabled(JfrEvent.JavaMonitorWait)) {
49+
JfrNativeEventWriterData data = org.graalvm.nativeimage.StackValue.get(JfrNativeEventWriterData.class);
50+
JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data);
51+
JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.JavaMonitorWait);
52+
JfrNativeEventWriter.putLong(data, startTicks);
53+
JfrNativeEventWriter.putLong(data, JfrTicks.elapsedTicks() - startTicks);
54+
JfrNativeEventWriter.putEventThread(data);
55+
JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.JavaMonitorWait, 0));
56+
JfrNativeEventWriter.putClass(data, obj.getClass());
57+
JfrNativeEventWriter.putLong(data, notifier);
58+
JfrNativeEventWriter.putLong(data, timeout);
59+
JfrNativeEventWriter.putBoolean(data, timedOut);
60+
JfrNativeEventWriter.putLong(data, Word.objectToUntrackedPointer(obj).rawValue());
61+
JfrNativeEventWriter.endSmallEvent(data);
62+
}
63+
}
64+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java

Lines changed: 22 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@
2929
import java.util.concurrent.TimeUnit;
3030
import java.util.concurrent.locks.LockSupport;
3131

32-
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
32+
import org.graalvm.nativeimage.CurrentIsolate;
3333

34-
import com.oracle.svm.core.SubstrateUtil;
3534
import com.oracle.svm.core.annotate.Alias;
3635
import com.oracle.svm.core.annotate.TargetClass;
3736
import com.oracle.svm.core.annotate.TargetElement;
3837
import com.oracle.svm.core.annotate.Uninterruptible;
39-
import com.oracle.svm.core.jdk.JDK11OrEarlier;
40-
import com.oracle.svm.core.jdk.JDK17OrLater;
38+
import com.oracle.svm.core.jfr.JfrTicks;
39+
import com.oracle.svm.core.jfr.SubstrateJVM;
40+
import com.oracle.svm.core.jfr.events.JavaMonitorWaitEvent;
4141

4242
import jdk.internal.misc.Unsafe;
4343

@@ -114,6 +114,7 @@ static final class ExclusiveNode extends Node {
114114
// see AbstractQueuedSynchronizer.ConditionNode
115115
static final class ConditionNode extends Node {
116116
ConditionNode nextWaiter;
117+
long notifierJfrTid;
117118

118119
// see AbstractQueuedSynchronizer.ConditionNode.isReleasable()
119120
public boolean isReleasable() {
@@ -364,6 +365,7 @@ private void doSignal(ConditionNode first, boolean all) {
364365
lastWaiter = null;
365366
}
366367
if ((first.getAndUnsetStatus(COND) & COND) != 0) {
368+
first.notifierJfrTid = SubstrateJVM.getThreadId(CurrentIsolate.getCurrentThread());
367369
enqueue(first);
368370
if (!all) {
369371
break;
@@ -451,8 +453,10 @@ private void unlinkCancelledWaiters(ConditionNode node) {
451453

452454
// see AbstractQueuedSynchronizer.ConditionObject.await()
453455
@SuppressWarnings("all")
454-
public void await() throws InterruptedException {
456+
public void await(Object obj) throws InterruptedException {
457+
long startTicks = JfrTicks.elapsedTicks();
455458
if (Thread.interrupted()) {
459+
JavaMonitorWaitEvent.emit(startTicks, obj, 0, 0L, false);
456460
throw new InterruptedException();
457461
}
458462
ConditionNode node = new ConditionNode();
@@ -473,6 +477,8 @@ public void await() throws InterruptedException {
473477
}
474478
setCurrentBlocker(null);
475479
node.clearStatus();
480+
// waiting is done, emit wait event
481+
JavaMonitorWaitEvent.emit(startTicks, obj, node.notifierJfrTid, 0L, false);
476482
acquire(node, savedState);
477483
if (interrupted) {
478484
if (cancelled) {
@@ -485,9 +491,11 @@ public void await() throws InterruptedException {
485491

486492
// see AbstractQueuedSynchronizer.ConditionObject.await(long, TimeUnit)
487493
@SuppressWarnings("all")
488-
public boolean await(long time, TimeUnit unit) throws InterruptedException {
494+
public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedException {
495+
long startTicks = JfrTicks.elapsedTicks();
489496
long nanosTimeout = unit.toNanos(time);
490497
if (Thread.interrupted()) {
498+
JavaMonitorWaitEvent.emit(startTicks, obj, 0, 0L, false);
491499
throw new InterruptedException();
492500
}
493501
ConditionNode node = new ConditionNode();
@@ -506,6 +514,8 @@ public boolean await(long time, TimeUnit unit) throws InterruptedException {
506514
}
507515
}
508516
node.clearStatus();
517+
// waiting is done, emit wait event
518+
JavaMonitorWaitEvent.emit(startTicks, obj, node.notifierJfrTid, time, cancelled);
509519
acquire(node, savedState);
510520
if (cancelled) {
511521
unlinkCancelledWaiters(node);
@@ -525,31 +535,19 @@ static void setCurrentBlocker(JavaMonitorConditionObject condition) {
525535
}
526536
}
527537

538+
@SuppressWarnings("deprecation")
528539
static boolean compareAndSetReference(Object object, long offset, Node expected, Node newValue) {
529-
Target_jdk_internal_misc_Unsafe u = SubstrateUtil.cast(U, Target_jdk_internal_misc_Unsafe.class);
530-
if (JavaVersionUtil.JAVA_SPEC >= 17) {
531-
return u.compareAndSetReference(object, offset, expected, newValue);
532-
} else {
533-
return u.compareAndSetObject(object, offset, expected, newValue);
534-
}
540+
return U.compareAndSetObject(object, offset, expected, newValue);
535541
}
536542

543+
@SuppressWarnings("deprecation")
537544
static boolean weakCompareAndSetReference(Object object, long offset, Node expected, Node newValue) {
538-
Target_jdk_internal_misc_Unsafe u = SubstrateUtil.cast(U, Target_jdk_internal_misc_Unsafe.class);
539-
if (JavaVersionUtil.JAVA_SPEC >= 17) {
540-
return u.weakCompareAndSetReference(object, offset, expected, newValue);
541-
} else {
542-
return u.weakCompareAndSetObject(object, offset, expected, newValue);
543-
}
545+
return U.weakCompareAndSetObject(object, offset, expected, newValue);
544546
}
545547

548+
@SuppressWarnings("deprecation")
546549
static void putReference(Object object, long offset, Node p) {
547-
Target_jdk_internal_misc_Unsafe u = SubstrateUtil.cast(U, Target_jdk_internal_misc_Unsafe.class);
548-
if (JavaVersionUtil.JAVA_SPEC >= 17) {
549-
u.putReference(object, offset, p);
550-
} else {
551-
u.putObject(object, offset, p);
552-
}
550+
U.putObject(object, offset, p);
553551
}
554552

555553
// Unsafe
@@ -565,30 +563,3 @@ final class Target_java_util_concurrent_locks_LockSupport {
565563
@TargetElement(onlyWith = com.oracle.svm.core.jdk.JDK17OrLater.class)
566564
public static native void setCurrentBlocker(Object blocker);
567565
}
568-
569-
@TargetClass(value = Unsafe.class)
570-
final class Target_jdk_internal_misc_Unsafe {
571-
@Alias
572-
@TargetElement(onlyWith = JDK17OrLater.class)
573-
public native boolean compareAndSetReference(Object o, long offset, Object expected, Object x);
574-
575-
@Alias
576-
@TargetElement(onlyWith = JDK11OrEarlier.class)
577-
public native boolean compareAndSetObject(Object o, long offset, Object expected, Object x);
578-
579-
@Alias
580-
@TargetElement(onlyWith = JDK17OrLater.class)
581-
public native boolean weakCompareAndSetReference(Object o, long offset, Object expected, Object x);
582-
583-
@Alias
584-
@TargetElement(onlyWith = JDK11OrEarlier.class)
585-
public native boolean weakCompareAndSetObject(Object o, long offset, Object expected, Object x);
586-
587-
@Alias
588-
@TargetElement(onlyWith = JDK17OrLater.class)
589-
public native void putReference(Object o, long offset, Object x);
590-
591-
@Alias
592-
@TargetElement(onlyWith = JDK11OrEarlier.class)
593-
public native void putObject(Object o, long offset, Object x);
594-
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,9 @@ protected void doWait(Object obj, long timeoutMillis) throws InterruptedExceptio
331331
JavaMonitor lock = ensureLocked(obj);
332332
JavaMonitorConditionObject condition = lock.getOrCreateCondition(true);
333333
if (timeoutMillis == 0L) {
334-
condition.await();
334+
condition.await(obj);
335335
} else {
336-
condition.await(timeoutMillis, TimeUnit.MILLISECONDS);
336+
condition.await(obj, timeoutMillis, TimeUnit.MILLISECONDS);
337337
}
338338
}
339339

0 commit comments

Comments
 (0)