-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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
8341127: Extra call to MethodHandle::asType from memory segment var handles fails to inline #21283
Conversation
👋 Welcome back mcimadamore! A progress list of the required criteria for merging this PR into |
|
||
static { | ||
types = new Class<?>[TYPE_SIZE]; | ||
ClassLoader customLoader = new URLClassLoader(new URL[0], LoopOverNonConstantAsType.class.getClassLoader()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, using a different class loadrer is not required - but using classes with different class loaders can end up taking even longer code paths when calling MethodHandle::asType
, so I've added that here.
@mcimadamore This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 278 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) | ||
@State(org.openjdk.jmh.annotations.Scope.Thread) | ||
@OutputTimeUnit(TimeUnit.MILLISECONDS) | ||
@Fork(value = 3, jvmArgsAppend = { "-XX:-TieredCompilation" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The benchmark only reproduces if tiered compilation is disabled. This is due to the fact that some threshold are updated accordingly, and set to a smaller value, which is enough to exhibit the issue.
@mcimadamore The following label 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 list. If you would like to change these labels, use the /label pull request command. |
Webrevs
|
Benchmark results Before:
After:
|
Alternatives considered:
Of these, (1) was preferred as it fixes the underlying issue (and not just for memory segment var handles), while at the same time avoiding unwanted side-effects (e.g. adding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
In the micro perhaps the unsafe_loop
variant is superfluous for this special case test? At least it's distinct from the test in LoopOverNonConstant
by summing longs rather than ints.
Yeah - that is a bit redundant - however could be useful to have some sort of baseline, so I left it in there. |
@@ -885,7 +886,9 @@ private MethodHandle asTypeCached(MethodType newType) { | |||
return null; | |||
} | |||
|
|||
private MethodHandle setAsTypeCache(MethodHandle at) { | |||
@DontInline |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you leave a comment explaining why we put DontInline
here?
} | ||
} | ||
|
||
@CompilerControl(CompilerControl.Mode.DONT_INLINE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the intent was to block inlining of asType
, so it gets compiled in isolation? That should be done with a CompileCommand
though. This annotation just blocks inlining of compileAsType
AFAIK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you mean... I'll do some experiments and see how the current annotation affects the benchmark - if at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue with using a compile command is that it will then work globally. So the benchmark would not really test much - besides checking that var handle access is slow when asType
cannot inline. What I was trying to do here was to avoid asType
being inlined into that compileAsType
method - but I agree that the annotation I added isn't it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe EXCLUDE
is what I was reaching out for
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think EXCLUDE would work, yes. True about CompileCommand having a global effect, so that won't work. (With a CompilerDirective file we could be more precise, not sure if it's worth it though).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the latest iteration, I removed the annotation. Doesn't seem to be making any difference.
test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java
Outdated
Show resolved
Hide resolved
…tantAsType.java Co-authored-by: Jorn Vernee <[email protected]>
I don't have a clear understanding how It does make sense to annotate |
A var handle guard is a piece of code that detects var handle call of a certain shape, to avoid creation of lambda forms in some common cases. This was done in Java 9, and was unchanged by FFM. In this case, we just happen to hit the var handle guard for The difference is that in the normal code path (lambda form), the call to Normally, var handle guards don't need an But if a var handle guard is triggered on an "indirect" var handle (read: a var handle that has been adapted with some combinator - this part is new since FFM), then we go through a different path in the guard code which always calls (note: this "slow path" inside var handle guards predates FFM, but var handle adaptation has increased the number of cases in which we hit this slow path). The PR that introduced this regression made all FFM var handles undergo some adaptation. Which is why now we're seeing this issue - as we're now hitting a (no-op) |
/integrate |
Going to push as commit 7fa2f22.
Your commit was automatically rebased without conflicts. |
@mcimadamore Pushed as commit 7fa2f22. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
/backport :jdk23 |
@mcimadamore the backport was successfully created on the branch backport-mcimadamore-7fa2f229-jdk23 in my personal fork of openjdk/jdk. To create a pull request with this backport targeting openjdk/jdk:jdk23, just click the following link: The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:
If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk:
|
/backport jdk23u |
@mcimadamore the backport was successfully created on the branch backport-mcimadamore-7fa2f229-master in my personal fork of openjdk/jdk23u. To create a pull request with this backport targeting openjdk/jdk23u:master, just click the following link: The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:
If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk23u:
|
The fix for JDK-8331865 introduced an accidental performance regression.
The main issue is that now all memory segment var handles go through some round of adaptation.
Adapting a var handle results in a so called indirect var handle.
When an indirect var handle is called through a var handle guard, an extra
MethodHandle::asType
call is triggered.In some cases, if
asType
has already been compiled into a big method, it cannot be inlined into the caller, which then results in a failure to inline through the var handle call, resulting in a big performance regression.The solution is to make sure that the compiled size of
MethodHandle::asType
stays small: this is done by making sure that the slowpath (the one which populates the cache used byasType
) is not inlined by the JVM. This is done by consolidating the slow path into a separate method, which is annotated with the internal@DontInline
annotation.This problem was originally reported here:
https://mail.openjdk.org/pipermail/panama-dev/2024-September/020643.html
While we did not test this fix directly, we have made sure that running the problematic benchmark with the flags:
Solves the performance regression. The fix in this PR is just a programmatic way to achieve the same results w/o the need of command line flags.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/21283/head:pull/21283
$ git checkout pull/21283
Update a local copy of the PR:
$ git checkout pull/21283
$ git pull https://git.openjdk.org/jdk.git pull/21283/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 21283
View PR using the GUI difftool:
$ git pr show -t 21283
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/21283.diff
Webrev
Link to Webrev Comment