RFR: 8305670: Performance regression in LockSupport.unpark with lots of idle threads [v3]
Robbin Ehn
rehn at openjdk.org
Fri Apr 21 09:59:48 UTC 2023
On Thu, 20 Apr 2023 17:50:47 GMT, Daniel D. Daugherty <dcubed at openjdk.org> wrote:
>> But ignoring the asserts `cv_internal_thread_to_JavaThread()` serves absolutely no purpose when we could request quick-mode - and we don't need to know what `cv_internal_thread_to_JavaThread` does - we know how thread startup and exit is managed and we know what a TLH guarantees . Sure we can bail sooner but there is no need to, so that is not required. In quick-mode, barring the assertion for includes, it all boils down to nothing! We don't need the Thread_oop passed out as we already have it before we start; we don't even need the JavaThread* passed out as we already have it too! So what does it actually do for us? Nothing. We could just have:
>>
>> UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) {
>> if (jthread != nullptr) {
>> oop thread_oop = JNIHandles::resolve_non_null(jthread);
>> if (java_lang_Thread::thread(thread_oop) != nullptr) {
>> // Try to capture the live JavaThread in a ThreadsListHandle:
>> ThreadsListHandle tlh; // Provides memory barrier
>> JavaThread* thr;
>> if ( (thr = java_lang_Thread::thread(thread_oop)) != nullptr) {
>> assert(tlh.includes(thr), "must be");
>> // The still live JavaThread is protected by the ThreadsListHandle
>> // so is safe to access.
>> Parker* p = thr->parker();
>> HOTSPOT_THREAD_UNPARK((uintptr_t) p);
>> p->unpark();
>> }
>> } // ThreadsListHandle is destroyed here.
>> }
>> } UNSAFE_END
>
> Before we went down the road of creating this `quick_mode` variant of the
> conversion function, I added this comment about "API indigestion" to the bug report:
>
> https://bugs.openjdk.org/browse/JDK-8305670?focusedCommentId=14573647&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-14573647
>
> @robehn's proposed `quick_mode` changes were an attempt to make the indigestion
> a little less bothersome (Tums anyone?), but @dholmes-ora's comments have made a
> good case here for what we've done is jump thru hoops to keep a call to the (slightly
> modified) conversion function when it's clear that the general purpose conversion
> function just isn't the right tool for this particular job.
>
> I'm going to take another look at backing out portions of the `quick_mode` fix while
> trying to keep the performance improvements. This will result in `Unsafe_Unpark()`
> not trying to use the general purpose conversion function.
>
> On a related note, we're having a bit of trouble trying to reproduce the performance
> improvements on the machines in our performance lab.
It's also possible to create a special version of ThreadsListHandle which takes an Thread object in constructor.
Do the eetop check and then safe fetch the ThreadsList.
If you call include() with the same JavaThread* as the eetop was before creating the ThreadsList, you can return true directly, i.e. quick mode.
SpecialThreadsListHandle::SpecialThreadsListHandle(oop thread_oop) {
_javaThread_from_eetop = java_lang_Thread::thread(thread_oop);
_threadList = ...
}
bool includes(JavaThread* jt) {
if (jt == _javaThread_from_eetop && jt != nullptr) return true;
return _threadsList->includes(jt);
}
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/13519#discussion_r1173583349
More information about the hotspot-runtime-dev
mailing list