8382332: Large regression (~50%) in SPECjbb2015 when using JFR after JEP 500#30922
8382332: Large regression (~50%) in SPECjbb2015 when using JFR after JEP 500#30922mgronlun wants to merge 9 commits intoopenjdk:masterfrom
Conversation
|
👋 Welcome back mgronlun! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
|
@mgronlun The following labels will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing lists. If you would like to change these labels, use the /label pull request command. |
|
The total number of required reviews for this PR has been set to 2 based on the presence of this label: |
|
/label remove security |
|
/label add hotspot-jfr |
|
@mgronlun |
|
@mgronlun |
Webrevs
|
|
While there are many unused bits in the slot field, there is something a bit uncomfortable with encoding a the epoch generation into a final field. Did you consider adding an additional field, or even an injected field that is conditionally compiled in with #if INCLUDE_JFR ? |
| if (currentEpoch != (slot >> JfrEpochGeneration.EPOCH_SHIFT_INT)) { | ||
| int newRootFieldSlotEpoch = | ||
| currentEpoch << JfrEpochGeneration.EPOCH_SHIFT_INT | (slot & JfrEpochGeneration.VALUE_MASK_INT); | ||
| return JfrEpochGeneration.compareAndExchange(root, SLOT_OFFSET, slot, newRootFieldSlotEpoch); |
There was a problem hiding this comment.
Drive-by-comment: Can you make slot non-final? I'm afraid there is a chance the JIT will not produce correct code for accesses into this field if it lies about its finality. See JDK-8379875.
There was a problem hiding this comment.
I will leave the slot final, and instead inject a dedicated field for the epoch value.
|
Adding an injected field for the epoch generation will be safer, of course. Sometimes, we try to preserve the footprint, and the encoding scheme might need to be implemented in existing fields to maintain it. If that is not considered a problem here, I will add an injected field. |
|
I think it would be good to mention in the event description that only one event per field, per chunk, is recorded, and there might be more mutations, possibly with different stack traces. Perhaps rename the label to make it clear, e.g. "Final Field Mutation Sample", or something similar. |
|
Attempting to add an injected field did not work because you cannot reflect an injected field, not even using Unsafe. So I cannot read the value of an injected field from Java. Either we go with the encoding in the slot field, or I will add a separate non-final field "jfrEpoch" to java.lang.reflect.Field. Thoughts? |
|
Updated with an alternative provided by @merykitty to make the slot non-final. As well as @egahlin's suggestions for better event descriptions. If we don't want to use the "slot" field, we must introduce another non-final int field, explicitly (not injected), dedicated to holding the encoded epoch. It can be done, I have no preferences either way. |
I assume an injected field would be feasible if all the access were via JVM funtions rather than reflect/Unsafe but that would add complexity as it might end up needing instrinics. In that case, an explicit field would be better so the slot field is not overridden. |
Sounds like @AlanBateman suggests a dedicated field for the jfrEpoch - coming up. |
| @Label("Final Field Mutation") | ||
| @Label("Final Field Mutation Sample") | ||
| @Description("One event per field, per chunk, is recorded." + | ||
| "There might be more mutations, possibly with different stack traces") |
There was a problem hiding this comment.
The description is "developer facing" and I wonder if this will be understandable.
Yes, we can do an intrinsic too, if we really want to tuck this away. I can look into that alternative as well, since I already built similar intrinsics to read the jfrEpoch, which are currently in use for virtual threads. |
Ok, let's try this design, which can be generalized more broadly: we inject a field into those classes that need this support. The JfrEpochGeneration class will get an intrinsic to read and potentially cas-update any instance passed to it. |
|
@mgronlun |
|
Updated with a solution that uses injected fields and extendable intrinsics. |
|
/label remove security |
|
@mgronlun |
AlanBateman
left a comment
There was a problem hiding this comment.
I did a pass over the updated implementation that uses the injected fields and it looks good.
| // Epoch 4. | ||
| validate(secondRecording, 3); | ||
| secondRecording.close(); | ||
| validate(firstRecording, 9); |
There was a problem hiding this comment.
I haven't seen a test that has two recordings in use at the same time. The event isn't explicitly enabled for secondRecording, is the nesting relevant here? Also does the stop + start guaranteed to bump the epoch?
There was a problem hiding this comment.
We have many JFR tests that start multiple, nested recordings. Since a recording cannot turn off an event enabled by another recording, and there is only one recording stream in total, the second recording inherits the enabled event (the event setting is a union of 1 v 0), which means the event is also enabled for the subsequent recording.
Start and stop are both implemented as rotations, and rotations use a stop-the-world safepoint to bump the epoch.
There was a problem hiding this comment.
I wasn't sure how it worked with concurrent recordings so your message is useful, thanks. I will note that I did read through the Recording API docs but couldn't find anything obvious that documents this.
There was a problem hiding this comment.
It's really an implementation detail.
| int len = next_length(); // 0 or length in [1..5] | ||
| if (len == 0) break; | ||
| _position += len; | ||
| ++actual; |
There was a problem hiding this comment.
This looks like a pre-existing bug, should it be tracked separately?
There was a problem hiding this comment.
Its a pre-existing bug, indeed. I will refactor it.
AlanBateman
left a comment
There was a problem hiding this comment.
I don't have any other comments, thanks for taking this on.
Many thanks for reviewing this, @AlanBateman. Cheers. |
|
@mgronlun how important While looking on external addresses referenced in C2 intrinsics we noticed that JFR's
|
Greetings,
please see JDK-8382332 for detailed information about this issue.
Testing: jdk_jfr, tier1-6, SpecJbb2015
Thanks
Markus
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/30922/head:pull/30922$ git checkout pull/30922Update a local copy of the PR:
$ git checkout pull/30922$ git pull https://git.openjdk.org/jdk.git pull/30922/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 30922View PR using the GUI difftool:
$ git pr show -t 30922Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/30922.diff
Using Webrev
Link to Webrev Comment