RFR(XL): 8203469: Faster safepoints

David Holmes david.holmes at oracle.com
Mon Feb 11 01:24:25 UTC 2019


Hi Robbin,

Some comments below but I just noticed there seems to be a major problem 
with your webrevs/patches. If look at:

http://cr.openjdk.java.net/~rehn/8203469/v06_2/full/webrev/open.changeset

It shows in safepoint.cpp:

+void SafepointSynchronize::increment_jni_active_count() {
+  Atomic::add(1, &_current_jni_active_count);
+}

but if I look at the safepoint.cpp raw file:

http://cr.openjdk.java.net/~rehn/8203469/v06_2/full/webrev/raw_files/new/src/hotspot/share/runtime/safepoint.cpp

it shows the correct:

void SafepointSynchronize::increment_jni_active_count() {
   ++_current_jni_active_count;
}

This makes it impossible to use the changeset to search through to check 
out how things are being used. In particular in this case there doesn't 
seem to be a need for the 
SafepointSynchronize::increment_jni_active_count() function because its 
only used by the VMThread now from within the other safepoint code.

More below ...

On 8/02/2019 2:05 am, Robbin Ehn wrote:
> Hi all, here is the promised re-base (v06) on
> 8210832: Remove sneaky locking in class Monitor.
> 
> v06_1 is just a straight re-base.
> 
> Full:
> http://cr.openjdk.java.net/~rehn/8203469/v06_1/full/
> Inc:
> http://cr.openjdk.java.net/~rehn/8203469/v06_1/inc/
> 
> Passes stress test and t1-5.
> 
> But there is a 'better' way.
> Before I added the more graceful "_vm_wait->wait();" semaphore in the while
> (_waiting_to_block > 0) { loop, it was a just a busy spin using the same

I think I've lost track of the changes here. Initially we waited on the 
_safepoint_lock; then in preview_13 we switched to polling with backoff. 
Not sure when _vm_wait->wait was introduced but we're now returning to 
polling with backoff. Is that right?

Once the VMThread polls until all threads are known to be safepoint-safe 
we eliminate a whole category of race conditions with the thread-state 
changes that allows us to simplify those thread-state changes.

> back-off as the rolling forward loop. It turns out that we mostly never 
> spin
> here at all, when all java threads are stop the callbacks is often 
> already done.
> So the addition of the semaphore have no impact on our benchmarks and is 
> mostly
> unused. This is because most threads are in java which we need to spin-wait
> since they can elide into native without doing a callback. My proposed 
> re-base
> removes the the callbacks completely and let the vm thread do all thread
> accounting. All that the stopping threads needs to do is write state and
> safepoint id, everything else is handle by the vm thread. We trade 2 
> atomics +
> a local store per thread against doing 2 stores per thread by the vm 
> thread.
> This makes it possible for a thread in vm to transition into blocked 
> WITHOUT
> safepoint poll. Just set thread_blocked and promise to do safepoint poll 
> when
> leaving that state.

Right - but you've only implemented that for the new 
ThreadBlockInVMWithDeadlockCheck, though the same argument applies to 
the regular TBIVM. We can/should re-examine TBIVM logic, and see if we 
can simplify and combine with new ThreadBlockInVMWithDeadlockCheck. 
Future RFE.

Aside: from a safepoint perspective I really don't see any difference 
between going out to "native" and going out to a (potentially) 
"blocking" library call. There are both safepoint-safe and should have 
the same requirements as you exit and enter the VM.

> v06_2
> Full:
> http://cr.openjdk.java.net/~rehn/8203469/v06_2/full/
> Inc against v05:
> http://cr.openjdk.java.net/~rehn/8203469/v06_2/inc/
> Inc against v06_1:
> http://cr.openjdk.java.net/~rehn/8203469/v06_2/rebase_inc/
> 
> v06_2 simplifies and removes ~200 LOC with same performance.
> If there is a case with a thread in vm taking long time, it will already
> screw-up latency and thus should be fixed regardless of v06_1 vs v06_2. 
> So I
> see no reason why we should not push v06_2.

src/hotspot/share/runtime/interfaceSupport.inline.hpp

317     thread->set_thread_state((JavaThreadState)(_thread_in_vm + 1));

Should use _thread_in_vm_trans

326     _thread->set_thread_state((JavaThreadState)(_thread_blocked + 1));

Should use _thread_blocked_trans

That said, I'm unclear what role the trans states now play here. 
Originally the VMThread had to spin when it saw a trans state because 
the final state would determine how the VMThread needed to respond next. 
But with the VMThread always spinning I don't see that we necessarily 
need the additional complexity. Anyway that too could be looked at later.

I'd like to take one more pass through the full changeset once it has 
been generated correctly.

Thanks,
David

> Passes stress test and t1-5.
> 
> Thanks, Robbin


More information about the hotspot-dev mailing list