-
-
Notifications
You must be signed in to change notification settings - Fork 16k
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
Make Recycler faster on OpenJ9 #13357
Conversation
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.
Well done!
Just curious ..any other call sites where we use anything similar?
Previously we were getting these numbers from
With this PR we're getting these numbers:
So OpenJ9 improves a lot, but OpenJDK regresses. |
Motivation: To avoid reference processing overhead while at the same time ensuring that we clear Recycler data structures that were used by now-terminated threads, we need to check if the LocalPool owner thread has terminated. We used to do this by calling `Thread.getState`, but this turns out to be quite expensive on OpenJ9, because they need to halt the target thread before its state can be safely inspected. See the `haltThreadForInspection` call in [`Java_java_lang_Thread_getStateImpl`](https://github.com/eclipse-openj9/openj9/blob/55b9267740559406b8471000cd3a3b6f681dc095/runtime/jcl/common/thread.cpp#L76-L102). This turns out to be a scalability bottleneck in some deployments. Modification: We can get the same semantics as `Thread.getState() == Thread.State.TERMINATED` by checking `!Thread.isAlive()`. The `isAlive` call is cheap on both [OpenJ9](https://github.com/eclipse-openj9/openj9/blob/03967d8cc24dc1f60168110c9d207d2dff57765a/jcl/src/java.base/share/classes/java/lang/Thread.java#L756-L761) and [OpenJDK](https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/Thread.java#L1798-L1815). Result: We no longer see the scalability bottleneck observed in netty#13347 (comment)
96454c0
to
3498d7a
Compare
We can get the best of both by checking if we're on OpenJ9:
|
I don't see any other calls to |
I am surprised that we have regressed on Jdk, it doesn't seem anything but a load there - you checked on x86? |
I only checked on aarch |
What hardware? Such a heavy impact for a volatile read is odd. |
@theRealAph M1 Pro, macOS |
@chrisvest @theRealAph https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/9a751dc19fae78ce58fb0eb176522070c992fb6f/jdk/src/share/classes/java/lang/Thread.java#L1003 That's why! Ah what an horror story weekend 🥶 |
Ah, it's going through a java<->native transition. So, a slowdown makes sense. |
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 once this comment is addressed.
Co-authored-by: Trustin Lee <t@motd.kr>
@chrisvest thanks a lot! |
Motivation: To avoid reference processing overhead while at the same time ensuring that we clear Recycler data structures that were used by now-terminated threads, we need to check if the LocalPool owner thread has terminated. We used to do this by calling `Thread.getState`, but this turns out to be quite expensive on OpenJ9, because they need to halt the target thread before its state can be safely inspected. See the `haltThreadForInspection` call in [`Java_java_lang_Thread_getStateImpl`](https://github.com/eclipse-openj9/openj9/blob/55b9267740559406b8471000cd3a3b6f681dc095/runtime/jcl/common/thread.cpp#L76-L102). This turns out to be a scalability bottleneck in some deployments. Modification: We can get the same semantics as `Thread.getState() == Thread.State.TERMINATED` by checking `!Thread.isAlive()`. The `isAlive` call is cheap on both [OpenJ9](https://github.com/eclipse-openj9/openj9/blob/03967d8cc24dc1f60168110c9d207d2dff57765a/jcl/src/java.base/share/classes/java/lang/Thread.java#L756-L761) and [OpenJDK](https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/Thread.java#L1798-L1815). Result: We no longer see the scalability bottleneck observed in #13347 (comment) Co-authored-by: Trustin Lee <t@motd.kr>
Motivation:
To avoid reference processing overhead while at the same time ensuring that we clear Recycler data structures that were used by now-terminated threads, we need to check if the LocalPool owner thread has terminated.
We used to do this by calling
Thread.getState
, but this turns out to be quite expensive on OpenJ9, because they need to halt the target thread before its state can be safely inspected. See thehaltThreadForInspection
call inJava_java_lang_Thread_getStateImpl
.This turns out to be a scalability bottleneck in some deployments.
Modification:
We can get the same semantics as
Thread.getState() == Thread.State.TERMINATED
by checking!Thread.isAlive()
.The
isAlive
call is cheap on both OpenJ9 and OpenJDK.Result:
We no longer see the scalability bottleneck observed in #13347 (comment)