Skip to content

Commit 6238398

Browse files
[GR-42740] [GR-44248] Experimental support for JFR event streaming.
PullRequest: graal/13951
2 parents a1ca629 + 322c36d commit 6238398

File tree

97 files changed

+3236
-1287
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+3236
-1287
lines changed

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ This changelog summarizes major changes to GraalVM Native Image.
2525
* (GR-38414) BellSoft implemented the `MemoryPoolMXBean` for the serial and epsilon GCs.
2626
* (GR-40641) Dynamic linking of AWT libraries on Linux.
2727
* (GR-40463) Red Hat added experimental support for JMX, which can be enabled with the `--enable-monitoring` option (e.g. `--enable-monitoring=jmxclient,jmxserver`).
28+
* (GR-42740) Together with Red Hat, we added experimental support for JFR event streaming.
2829
* (GR-44110) Native Image now targets `x86-64-v3` by default on AMD64 and supports a new `-march` option. Use `-march=compatibility` for best compatibility (previous default) or `-march=native` for best performance if the native executable is deployed on the same machine or on a machine with the same CPU features. To list all available machine types, use `-march=list`.
2930
* (GR-43971) Add native-image option `-E<env-var-key>[=<env-var-value>]` and support environment variable capturing in bundles. Previously almost all environment variables were available in the builder. To temporarily revert back to the old behaviour, env setting `NATIVE_IMAGE_SLOPPY_BUILDER_SANITATION=true` can be used. The old behaviour will be removed in a future release.
3031

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* or visit www.oracle.com if you need additional information or have any
2323
* questions.
2424
*/
25-
package com.oracle.svm.core.jdk;
25+
package com.oracle.svm.core.collections;
2626

2727
import org.graalvm.nativeimage.ImageSingletons;
2828
import org.graalvm.nativeimage.Platform;
@@ -147,6 +147,14 @@ public boolean putIfAbsent(UninterruptibleEntry valueOnStack) {
147147
}
148148
}
149149

150+
@Override
151+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
152+
public UninterruptibleEntry putNew(UninterruptibleEntry valueOnStack) {
153+
assert valueOnStack.isNonNull();
154+
assert get(valueOnStack).isNull();
155+
return insertEntry(valueOnStack);
156+
}
157+
150158
@Override
151159
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
152160
public void clear() {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleEntry.java renamed to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/collections/UninterruptibleEntry.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* or visit www.oracle.com if you need additional information or have any
2323
* questions.
2424
*/
25-
package com.oracle.svm.core.jdk;
25+
package com.oracle.svm.core.collections;
2626

2727
import org.graalvm.nativeimage.c.struct.RawField;
2828
import org.graalvm.nativeimage.c.struct.RawStructure;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleHashtable.java renamed to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/collections/UninterruptibleHashtable.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@
2222
* or visit www.oracle.com if you need additional information or have any
2323
* questions.
2424
*/
25-
package com.oracle.svm.core.jdk;
25+
package com.oracle.svm.core.collections;
2626

2727
import com.oracle.svm.core.Uninterruptible;
2828

2929
/**
3030
* Common interface for all uninterruptible hashtable implementations. Please note that we don't use
31-
* generics as this sometimes breaks the {@link Uninterruptible} annotation when ECJ is used for
32-
* compiling the Java sources.
31+
* generics as this may break the {@link Uninterruptible} annotations.
3332
*/
3433
public interface UninterruptibleHashtable {
3534
/**
@@ -59,6 +58,14 @@ public interface UninterruptibleHashtable {
5958
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
6059
boolean putIfAbsent(UninterruptibleEntry valueOnStack);
6160

61+
/**
62+
* Inserts {@code valueOnStack} into the hashtable. May only be called if it is guaranteed that
63+
* there is no matching entry in the table. Returns the inserted entry. If an error occurred
64+
* while inserting the entry, a null pointer is returned instead.
65+
*/
66+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
67+
UninterruptibleEntry putNew(UninterruptibleEntry valueOnStack);
68+
6269
/**
6370
* If the hashtable contains an existing entry that matches {@code valueOnStack}, then this
6471
* existing entry will be returned and no value will be inserted.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/feature/AutomaticallyRegisteredFeature.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434

3535
/**
3636
* {@link InternalFeature} classes with this annotation are automatically registered using an
37-
* annotation processor.
37+
* annotation processor. If multiple implementations for a class are annotated with
38+
* {@link AutomaticallyRegisteredFeature}, only the most specific one will be registered as a
39+
* feature.
3840
*
3941
* Note that this requires the `SVM_PROCESSOR` to be defined as an annotation processor in the
4042
* suite.py file.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKContainerSubstitutions.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,18 @@
2525

2626
package com.oracle.svm.core.jdk;
2727

28-
import org.graalvm.nativeimage.Platform.LINUX;
29-
3028
import java.util.List;
3129
import java.util.concurrent.CopyOnWriteArrayList;
30+
import java.util.concurrent.locks.ReentrantLock;
3231

32+
import org.graalvm.nativeimage.Platform.LINUX;
3333
import org.graalvm.nativeimage.Platforms;
3434

3535
import com.oracle.svm.core.annotate.Alias;
3636
import com.oracle.svm.core.annotate.RecomputeFieldValue;
3737
import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
38-
3938
import com.oracle.svm.core.annotate.TargetClass;
39+
import com.oracle.svm.core.annotate.TargetElement;
4040

4141
@TargetClass(className = "jdk.internal.platform.cgroupv1.CgroupV1Subsystem", onlyWith = JDK17OrLater.class)
4242
@Platforms(LINUX.class)
@@ -69,6 +69,11 @@ final class Target_jdk_jfr_internal_instrument_JDKEvents {
6969
@TargetClass(className = "jdk.jfr.internal.RequestEngine", onlyWith = JDK17OrLater.class)
7070
@Platforms(LINUX.class)
7171
final class Target_jdk_jfr_internal_RequestEngine {
72+
@Alias //
73+
@TargetElement(onlyWith = JDK20OrLater.class) //
74+
@RecomputeFieldValue(kind = Kind.NewInstance, declClass = ReentrantLock.class) //
75+
private static ReentrantLock lock;
76+
7277
@Alias //
7378
@RecomputeFieldValue(kind = Kind.NewInstance, declClass = CopyOnWriteArrayList.class) //
7479
private static List<?> entries;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleUtils.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,11 @@ public static int numberOfLeadingZeros(long i) {
456456
// @formatter:on
457457
}
458458
// Checkstyle: resume
459+
460+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
461+
public static int hashCode(long value) {
462+
return (int) (value ^ (value >>> 32));
463+
}
459464
}
460465

461466
public static class Integer {
@@ -555,9 +560,17 @@ private static Pointer writeModifiedUTF8(Pointer buffer, char c) {
555560
*/
556561
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
557562
public static int modifiedUTF8Length(java.lang.String string, boolean addNullTerminator) {
563+
return modifiedUTF8Length(string, addNullTerminator, null);
564+
}
565+
566+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
567+
public static int modifiedUTF8Length(java.lang.String string, boolean addNullTerminator, CharReplacer replacer) {
558568
int result = 0;
559569
for (int index = 0; index < string.length(); index++) {
560570
char ch = StringUtil.charAt(string, index);
571+
if (replacer != null) {
572+
ch = replacer.replace(ch);
573+
}
561574
result += modifiedUTF8Length(ch);
562575
}
563576

@@ -573,9 +586,18 @@ public static int modifiedUTF8Length(java.lang.String string, boolean addNullTer
573586
*/
574587
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
575588
public static Pointer toModifiedUTF8(java.lang.String string, Pointer buffer, Pointer bufferEnd, boolean addNullTerminator) {
589+
return toModifiedUTF8(string, buffer, bufferEnd, addNullTerminator, null);
590+
}
591+
592+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
593+
public static Pointer toModifiedUTF8(java.lang.String string, Pointer buffer, Pointer bufferEnd, boolean addNullTerminator, CharReplacer replacer) {
576594
Pointer pos = buffer;
577595
for (int index = 0; index < string.length(); index++) {
578-
pos = writeModifiedUTF8(pos, StringUtil.charAt(string, index));
596+
char ch = StringUtil.charAt(string, index);
597+
if (replacer != null) {
598+
ch = replacer.replace(ch);
599+
}
600+
pos = writeModifiedUTF8(pos, ch);
579601
}
580602

581603
if (addNullTerminator) {
@@ -586,4 +608,10 @@ public static Pointer toModifiedUTF8(java.lang.String string, Pointer buffer, Po
586608
return pos;
587609
}
588610
}
611+
612+
@FunctionalInterface
613+
public interface CharReplacer {
614+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
615+
char replace(char val);
616+
}
589617
}

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

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,47 @@
3636

3737
/**
3838
* A {@link JfrBuffer} is a block of native memory (either thread-local or global) into which JFR
39-
* events are written.
39+
* data (e.g., events) are written. It has the following layout:
40+
*
41+
* <pre>
42+
* Buffer: --------------------------------------------------------------------
43+
* | header | flushed data | committed data | unflushed data | unused |
44+
* --------------------------------------------------------------------
45+
* | | | |
46+
* data start flushed pos committed pos data end
47+
* </pre>
48+
*
49+
* The header contains the fields that are defined in the {@link RawStructure} below. The data part
50+
* consists of several sections:
51+
* <ul>
52+
* <li>Flushed data has already been flushed to the {@link JfrGlobalMemory global memory} or to the
53+
* disk.</li>
54+
* <li>Committed data refers to fully written, valid event data that can be flushed at any
55+
* time.</li>
56+
* <li>Unflushed data refers to the data of a JFR event that is currently being written.</li>
57+
* </ul>
58+
*
59+
* Multiple threads may access the same {@link JfrBuffer} concurrently:
60+
* <li>If a thread owns/created a thread-local buffer, then it may access and modify most of that
61+
* buffer's data at any time, without the need for any locking. Only the following operations
62+
* require that the {@link JfrBufferNode} is locked:
63+
* <ul>
64+
* <li>accessing or modifying the flushed position (see {@link JfrBufferAccess#setFlushedPos}</li>
65+
* <li>freeing the buffer</li>
66+
* </ul>
67+
* <li>Accessing a thread-local buffer of another thread is only allowed after locking the
68+
* corresponding {@link JfrBufferNode} (see {@link #getNode()}). This prevents other threads from
69+
* freeing the buffer in meanwhile. The thread that holds the lock may read any field in the buffer
70+
* header and it may also access flushed or committed data (i.e., everything below
71+
* {@link #getCommittedPos()}). It must not modify any header fields, except for the flushed
72+
* position.</li>
4073
*/
4174
@RawStructure
4275
public interface JfrBuffer extends PointerBase {
4376

4477
/**
45-
* Returns the size of the buffer. This excludes the header of the buffer.
78+
* Returns the size of the buffer. This excludes the header of the buffer. This field is
79+
* effectively final.
4680
*/
4781
@RawField
4882
UnsignedWord getSize();
@@ -54,45 +88,37 @@ public interface JfrBuffer extends PointerBase {
5488
void setSize(UnsignedWord value);
5589

5690
/**
57-
* Returns the committed position. Any data before this position is valid event data.
91+
* Any data before this position was committed and is therefore valid event data.
5892
*/
5993
@RawField
60-
Pointer getPos();
94+
Pointer getCommittedPos();
6195

6296
/**
6397
* Sets the committed position.
6498
*/
6599
@RawField
66-
void setPos(Pointer value);
100+
void setCommittedPos(Pointer value);
67101

68102
@RawFieldOffset
69-
static int offsetOfPos() {
103+
static int offsetOfCommittedPos() {
70104
throw VMError.unimplemented(); // replaced
71105
}
72106

73107
/**
74-
* Returns the position of unflushed data. Any data before this position was already flushed to
75-
* some other buffer or to the disk.
108+
* Any data before this position was already flushed to some other buffer or to the disk. Needs
109+
* locking, see JavaDoc at the class level.
76110
*/
77111
@RawField
78-
Pointer getTop();
112+
Pointer getFlushedPos();
79113

80114
/**
81-
* Sets the position of unflushed data.
115+
* Sets the flushed position. Needs locking, see JavaDoc at the class level.
82116
*/
83117
@RawField
84-
void setTop(Pointer value);
85-
86-
@RawField
87-
int getLocked();
88-
89-
@RawFieldOffset
90-
static int offsetOfLocked() {
91-
throw VMError.unimplemented(); // replaced
92-
}
118+
void setFlushedPos(Pointer value);
93119

94120
/**
95-
* Returns the type of the buffer.
121+
* Returns the type of the buffer. This field is effectively final.
96122
*/
97123
@RawField
98124
@PinnedObjectField
@@ -103,5 +129,19 @@ static int offsetOfLocked() {
103129
*/
104130
@RawField
105131
@PinnedObjectField
106-
void setBufferType(JfrBufferType bufferType);
132+
void setBufferType(JfrBufferType value);
133+
134+
/**
135+
* Returns the {@link JfrBufferNode} that references this {@link JfrBuffer}. This field is only
136+
* set when a {@link JfrBuffer} was added to a {@link JfrBufferList} (i.e., for
137+
* {@link JfrBufferType#C_HEAP} buffers, this field is usually null).
138+
*/
139+
@RawField
140+
JfrBufferNode getNode();
141+
142+
/**
143+
* Sets the {@link JfrBufferNode}.
144+
*/
145+
@RawField
146+
void setNode(JfrBufferNode value);
107147
}

0 commit comments

Comments
 (0)