Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-42740] [GR-44248] Experimental support for JFR event streaming. #6146

Merged
merged 81 commits into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
71c62ee
wip. patch file header to not finish chunk, dont repeat metadata, don…
roberttoyonaga Oct 7, 2022
0ce364e
wip. Fixed dumping format error with thread repo. Fixed symbol table …
roberttoyonaga Oct 17, 2022
866ea81
fix thread pool writing. Write only when dirty. Clear everytime.
roberttoyonaga Oct 18, 2022
be8f179
flushing/rotate thread does all cleanup. Reuse JFR buffer lock
roberttoyonaga Oct 27, 2022
324caa0
working on hang up
roberttoyonaga Oct 31, 2022
5bed29b
fix conflicts with master
roberttoyonaga Oct 31, 2022
668abb7
wip. Fixed problem with parser reading stale files. MarkChunkFinal. …
roberttoyonaga Nov 1, 2022
3542375
fix deadlock issue. Change acquire and release ints
roberttoyonaga Nov 3, 2022
8949bd1
cleanup and refactor
roberttoyonaga Nov 3, 2022
aa62cfb
refactor
roberttoyonaga Nov 7, 2022
94e5155
checkstyle refactor format
roberttoyonaga Nov 7, 2022
137170a
clean diff
roberttoyonaga Nov 7, 2022
d473300
clean up. remove debug stacktrace print
roberttoyonaga Nov 7, 2022
f234b27
fix mx gate errors
roberttoyonaga Nov 7, 2022
3e33ee4
Avoid indeterminisim by setting JFR buffer to be unaquired when creat…
roberttoyonaga Nov 7, 2022
4d91ed8
fix for gate tests
roberttoyonaga Nov 7, 2022
62df18a
style
roberttoyonaga Nov 7, 2022
c41931f
make initialize synchronized
roberttoyonaga Nov 14, 2022
2d955a3
factor out buffer list initialization
roberttoyonaga Nov 14, 2022
c4832f6
Support exclusion of current thread. Fix bug by reordering node remov…
roberttoyonaga Dec 5, 2022
8bea083
fix head visibility bug
roberttoyonaga Dec 7, 2022
2162d2b
Simplifying touch ups. Comments.
roberttoyonaga Jan 3, 2023
142c343
fix conflicts
roberttoyonaga Jan 31, 2023
4c6488a
more fixes related to bringing up to date w master
roberttoyonaga Jan 31, 2023
08416fb
style and remove unused code
roberttoyonaga Jan 31, 2023
3602040
style fix intermittent segfault due to notifying event writer
roberttoyonaga Feb 1, 2023
1fcceaa
style, formatting, comments
roberttoyonaga Feb 1, 2023
d029bfb
change LL to be less complex
roberttoyonaga Feb 7, 2023
f39b69d
add JfrMetadata class to simplify things
roberttoyonaga Feb 7, 2023
5bbb52a
make constant pool write methods uninterruptable to prevent single th…
roberttoyonaga Feb 8, 2023
cd82127
write repositories individually. Get rid of old array
roberttoyonaga Feb 8, 2023
35adfcb
fix bug in traverse list. Notify event writer during epoch change
roberttoyonaga Feb 8, 2023
3751fc0
flush to global buffers first instead of disk
roberttoyonaga Feb 8, 2023
92ff049
refactoring to resolve PR comments
roberttoyonaga Feb 8, 2023
e564a8c
comments, docs, small fixes
roberttoyonaga Feb 9, 2023
806602b
types get epoch constant IDs. Only serialize new Types
roberttoyonaga Feb 10, 2023
eae9640
only serialize new symbol table entries
roberttoyonaga Feb 10, 2023
f233aef
only flush new constant pool entries
roberttoyonaga Feb 10, 2023
3201ebd
enums and uninterruptible reasons
roberttoyonaga Feb 10, 2023
03a8ce6
tests, inject exclude field into thread
roberttoyonaga Feb 13, 2023
ed1be34
fix test class name
roberttoyonaga Feb 14, 2023
44aed0d
tests and helper classes
roberttoyonaga Feb 14, 2023
20e33b1
merge changes from master
roberttoyonaga Feb 14, 2023
d3b78d8
fix minor things from merge
roberttoyonaga Feb 14, 2023
87d6a07
unit test for linked list
roberttoyonaga Feb 14, 2023
5b22ef9
unit tests
roberttoyonaga Feb 14, 2023
9cafc27
update constant pool parsing test
roberttoyonaga Feb 15, 2023
f72616b
rename JFR buffer pointers. Add assertions to ensure buffers are lock…
roberttoyonaga Feb 15, 2023
9f6bfcc
reduce possibility of race on thread repo writing. Minor fixes# This …
roberttoyonaga Feb 16, 2023
38cc7a3
style
roberttoyonaga Feb 17, 2023
d16e30e
use atomic long for metadata id
roberttoyonaga Feb 17, 2023
749e2c8
pull master
roberttoyonaga Feb 23, 2023
eb35d36
first half of review comments
roberttoyonaga Feb 23, 2023
131f427
more changes. Metadata fixes
roberttoyonaga Feb 23, 2023
c4c7c8e
more changes
roberttoyonaga Feb 27, 2023
f273004
Thread repo, type repo review comments
roberttoyonaga Feb 27, 2023
083f1c4
JavaOwnedSpinLockUtils
roberttoyonaga Feb 27, 2023
0bf1204
rework symbol repo. Touch-ups.
roberttoyonaga Feb 28, 2023
0ce8666
use JavaOwnedSpinlockUtils
roberttoyonaga Feb 28, 2023
cfbc3f4
gate fixes
roberttoyonaga Feb 28, 2023
77aa514
Merge with master.
christianhaeubl Mar 2, 2023
fa64197
Small refactorings and fixed a buffer overflow.
christianhaeubl Mar 2, 2023
39d9907
Added more documentation and changed the locking concept.
christianhaeubl Mar 2, 2023
7396d87
Various cleanups and simplifications.
christianhaeubl Mar 3, 2023
274e71e
More fixes and refactorings.
christianhaeubl Mar 3, 2023
6d20de0
More cleanups.
christianhaeubl Mar 3, 2023
441b794
Merge with master.
christianhaeubl Mar 3, 2023
1940cf9
More cleanups.
christianhaeubl Mar 4, 2023
3a7fdfe
Merge with master.
christianhaeubl Mar 4, 2023
fd0baa9
Fixed concurrency issues.
christianhaeubl Mar 4, 2023
f01fee1
Moved UninterruptibleHashtable to 'com.oracle.svm.core.collections'.
christianhaeubl Mar 4, 2023
72364c6
Fix further issues.
christianhaeubl Mar 4, 2023
92ee77b
Style fixes.
christianhaeubl Mar 5, 2023
667323d
Fixed test cases.
christianhaeubl Mar 5, 2023
51d19cb
More fixes and refactorings.
christianhaeubl Mar 6, 2023
1796df1
Merge with master.
christianhaeubl Mar 6, 2023
79bd420
Small fixes and cleanups.
christianhaeubl Mar 6, 2023
b5b3e78
Further fixes.
christianhaeubl Mar 7, 2023
8aa9f26
Merge with master.
christianhaeubl Mar 7, 2023
e2da2db
A few more fixes.
christianhaeubl Mar 7, 2023
322c36d
Review feedback and minor test case improvements.
christianhaeubl Mar 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ This changelog summarizes major changes to GraalVM Native Image.
* (GR-38414) BellSoft implemented the `MemoryPoolMXBean` for the serial and epsilon GCs.
* (GR-40641) Dynamic linking of AWT libraries on Linux.
* (GR-40463) Red Hat added experimental support for JMX, which can be enabled with the `--enable-monitoring` option (e.g. `--enable-monitoring=jmxclient,jmxserver`).
* (GR-42740) Together with Red Hat, we added experimental support for JFR event streaming.
* (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`.
* (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.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.jdk;
package com.oracle.svm.core.collections;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
Expand Down Expand Up @@ -147,6 +147,14 @@ public boolean putIfAbsent(UninterruptibleEntry valueOnStack) {
}
}

@Override
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public UninterruptibleEntry putNew(UninterruptibleEntry valueOnStack) {
assert valueOnStack.isNonNull();
assert get(valueOnStack).isNull();
return insertEntry(valueOnStack);
}

@Override
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public void clear() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.jdk;
package com.oracle.svm.core.collections;

import org.graalvm.nativeimage.c.struct.RawField;
import org.graalvm.nativeimage.c.struct.RawStructure;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.jdk;
package com.oracle.svm.core.collections;

import com.oracle.svm.core.Uninterruptible;

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

/**
* Inserts {@code valueOnStack} into the hashtable. May only be called if it is guaranteed that
* there is no matching entry in the table. Returns the inserted entry. If an error occurred
* while inserting the entry, a null pointer is returned instead.
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
UninterruptibleEntry putNew(UninterruptibleEntry valueOnStack);

/**
* If the hashtable contains an existing entry that matches {@code valueOnStack}, then this
* existing entry will be returned and no value will be inserted.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@

package com.oracle.svm.core.jdk;

import org.graalvm.nativeimage.Platform.LINUX;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantLock;

import org.graalvm.nativeimage.Platform.LINUX;
import org.graalvm.nativeimage.Platforms;

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;

import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;

@TargetClass(className = "jdk.internal.platform.cgroupv1.CgroupV1Subsystem", onlyWith = JDK17OrLater.class)
@Platforms(LINUX.class)
Expand Down Expand Up @@ -69,6 +69,11 @@ final class Target_jdk_jfr_internal_instrument_JDKEvents {
@TargetClass(className = "jdk.jfr.internal.RequestEngine", onlyWith = JDK17OrLater.class)
@Platforms(LINUX.class)
final class Target_jdk_jfr_internal_RequestEngine {
@Alias //
@TargetElement(onlyWith = JDK20OrLater.class) //
@RecomputeFieldValue(kind = Kind.NewInstance, declClass = ReentrantLock.class) //
private static ReentrantLock lock;

@Alias //
@RecomputeFieldValue(kind = Kind.NewInstance, declClass = CopyOnWriteArrayList.class) //
private static List<?> entries;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,11 @@ public static int numberOfLeadingZeros(long i) {
// @formatter:on
}
// Checkstyle: resume

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static int hashCode(long value) {
return (int) (value ^ (value >>> 32));
}
}

public static class Integer {
Expand Down Expand Up @@ -530,23 +535,19 @@ private static int modifiedUTF8Length(char c) {
* Write a char in modified UTF8 format into the buffer.
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
private static Pointer writeModifiedUTF8(Pointer buffer, char c, boolean replaceDotWithSlash) {
private static Pointer writeModifiedUTF8(Pointer buffer, char c) {
Pointer pos = buffer;
char replacedChar = c;
if (replaceDotWithSlash && replacedChar == '.') {
replacedChar = '/';
}
if (replacedChar >= 0x0001 && replacedChar <= 0x007F) {
pos.writeByte(0, (byte) replacedChar);
if (c >= 0x0001 && c <= 0x007F) {
pos.writeByte(0, (byte) c);
pos = pos.add(1);
} else if (replacedChar <= 0x07FF) {
pos.writeByte(0, (byte) (0xC0 | (replacedChar >> 6)));
pos.writeByte(1, (byte) (0x80 | (replacedChar & 0x3F)));
} else if (c <= 0x07FF) {
pos.writeByte(0, (byte) (0xC0 | (c >> 6)));
pos.writeByte(1, (byte) (0x80 | (c & 0x3F)));
pos = pos.add(2);
} else {
pos.writeByte(0, (byte) (0xE0 | (replacedChar >> 12)));
pos.writeByte(1, (byte) (0x80 | ((replacedChar >> 6) & 0x3F)));
pos.writeByte(2, (byte) (0x80 | (replacedChar & 0x3F)));
pos.writeByte(0, (byte) (0xE0 | (c >> 12)));
pos.writeByte(1, (byte) (0x80 | ((c >> 6) & 0x3F)));
pos.writeByte(2, (byte) (0x80 | (c & 0x3F)));
pos = pos.add(3);
}
return pos;
Expand All @@ -559,9 +560,17 @@ private static Pointer writeModifiedUTF8(Pointer buffer, char c, boolean replace
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static int modifiedUTF8Length(java.lang.String string, boolean addNullTerminator) {
return modifiedUTF8Length(string, addNullTerminator, null);
}

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static int modifiedUTF8Length(java.lang.String string, boolean addNullTerminator, CharReplacer replacer) {
int result = 0;
for (int index = 0; index < string.length(); index++) {
char ch = StringUtil.charAt(string, index);
if (replacer != null) {
ch = replacer.replace(ch);
}
result += modifiedUTF8Length(ch);
}

Expand All @@ -577,15 +586,18 @@ public static int modifiedUTF8Length(java.lang.String string, boolean addNullTer
*/
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static Pointer toModifiedUTF8(java.lang.String string, Pointer buffer, Pointer bufferEnd, boolean addNullTerminator) {

return toModifiedUTF8(string, buffer, bufferEnd, addNullTerminator, false);
return toModifiedUTF8(string, buffer, bufferEnd, addNullTerminator, null);
}

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static Pointer toModifiedUTF8(java.lang.String string, Pointer buffer, Pointer bufferEnd, boolean addNullTerminator, boolean replaceDotWithSlash) {
public static Pointer toModifiedUTF8(java.lang.String string, Pointer buffer, Pointer bufferEnd, boolean addNullTerminator, CharReplacer replacer) {
Pointer pos = buffer;
for (int index = 0; index < string.length(); index++) {
pos = writeModifiedUTF8(pos, StringUtil.charAt(string, index), replaceDotWithSlash);
char ch = StringUtil.charAt(string, index);
if (replacer != null) {
ch = replacer.replace(ch);
}
pos = writeModifiedUTF8(pos, ch);
}

if (addNullTerminator) {
Expand All @@ -596,4 +608,10 @@ public static Pointer toModifiedUTF8(java.lang.String string, Pointer buffer, Po
return pos;
}
}

@FunctionalInterface
public interface CharReplacer {
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
char replace(char val);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,50 @@

import com.oracle.svm.core.c.struct.PinnedObjectField;
import com.oracle.svm.core.util.VMError;
import org.graalvm.nativeimage.IsolateThread;

/**
* A {@link JfrBuffer} is a block of native memory (either thread-local or global) into which JFR
* events are written. {@link JfrBuffer#getFlushedPos()} returns the point up to which data has been
* flushed. {@link JfrBuffer#getCommittedPos()} returns the point up to which data has been
* committed. This means that data between the these two positions is unflushed data that is ready
* to be flushed. This also means that {@link JfrBuffer#getFlushedPos()} should never exceed
* {@link JfrBuffer#getCommittedPos()}. New emitted events are written after the
* {@link JfrBuffer#getCommittedPos()}. The new events are committed by advancing the committed
* position.
* data (e.g., events) are written. It has the following layout:
*
* <pre>
* Buffer: --------------------------------------------------------------------
* | header | flushed data | committed data | unflushed data | unused |
* --------------------------------------------------------------------
* | | | |
* data start flushed pos committed pos data end
* </pre>
*
* The header contains the fields that are defined in the {@link RawStructure} below. The data part
* consists of several sections:
* <ul>
* <li>Flushed data has already been flushed to the {@link JfrGlobalMemory global memory} or to the
* disk.</li>
* <li>Committed data refers to fully written, valid event data that can be flushed at any
* time.</li>
* <li>Unflushed data refers to the data of a JFR event that is currently being written.</li>
* </ul>
*
* Multiple threads may access the same {@link JfrBuffer} concurrently:
* <li>If a thread owns/created a thread-local buffer, then it may access and modify most of that
* buffer's data at any time, without the need for any locking. Only the following operations
* require that the {@link JfrBufferNode} is locked:
* <ul>
* <li>accessing or modifying the flushed position (see {@link JfrBufferAccess#setFlushedPos}</li>
* <li>freeing the buffer</li>
* </ul>
* <li>Accessing a thread-local buffer of another thread is only allowed after locking the
* corresponding {@link JfrBufferNode} (see {@link #getNode()}). This prevents other threads from
* freeing the buffer in meanwhile. The thread that holds the lock may read any field in the buffer
* header and it may also access flushed or committed data (i.e., everything below
* {@link #getCommittedPos()}). It must not modify any header fields, except for the flushed
* position.</li>
*/
@RawStructure
public interface JfrBuffer extends PointerBase {

/**
* Returns the size of the buffer. This excludes the header of the buffer.
* Returns the size of the buffer. This excludes the header of the buffer. This field is
* effectively final.
*/
@RawField
UnsignedWord getSize();
Expand All @@ -61,7 +88,7 @@ public interface JfrBuffer extends PointerBase {
void setSize(UnsignedWord value);

/**
* Returns the committed position. Any data before this position is valid event data.
* Any data before this position was committed and is therefore valid event data.
*/
@RawField
Pointer getCommittedPos();
Expand All @@ -78,20 +105,20 @@ static int offsetOfCommittedPos() {
}

/**
* Returns the position of unflushed data. Any data before this position was already flushed to
* some other buffer or to the disk.
* Any data before this position was already flushed to some other buffer or to the disk. Needs
* locking, see JavaDoc at the class level.
*/
@RawField
Pointer getFlushedPos();

/**
* Sets the position of unflushed data.
* Sets the flushed position. Needs locking, see JavaDoc at the class level.
*/
@RawField
void setFlushedPos(Pointer value);

/**
* Returns the type of the buffer.
* Returns the type of the buffer. This field is effectively final.
*/
@RawField
@PinnedObjectField
Expand All @@ -102,16 +129,19 @@ static int offsetOfCommittedPos() {
*/
@RawField
@PinnedObjectField
void setBufferType(JfrBufferType bufferType);
void setBufferType(JfrBufferType value);

/**
* Returns the {@link JfrBufferNode} that references this {@link JfrBuffer}. This field is only
* set when a {@link JfrBuffer} was added to a {@link JfrBufferList} (i.e., for
* {@link JfrBufferType#C_HEAP} buffers, this field is usually null).
*/
@RawField
void setLockOwner(IsolateThread thread);
JfrBufferNode getNode();

/**
* Sets the {@link JfrBufferNode}.
*/
@RawField
IsolateThread getLockOwner();

@RawFieldOffset
static int offsetOfLockOwner() {
throw VMError.unimplemented(); // replaced
}
void setNode(JfrBufferNode value);
}
Loading