RFR: 8186670: Implement _onSpinWait() intrinsic for AArch64 [v13]

Evgeny Astigeevich duke at openjdk.java.net
Wed Nov 10 18:13:38 UTC 2021


On Mon, 1 Nov 2021 13:11:40 GMT, Andrew Haley <aph at openjdk.org> wrote:

>> This test is too artificial. Going through my records I've found I have a microbenchmark for `java.util.concurrent. SynchronousQueue` which shows good improvements on jdk11. `SynchronousQueue` uses `onSpinWait`. Since jdk17 `SynchronousQueue` has not been using `onSpinWait` any more (See https://bugs.openjdk.java.net/browse/JDK-8267502). Maybe I can come up with a microbenchmark based on `SynchronousQueue` [code](https://github.com/openjdk/jdk11u-dev/blob/master/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java#L412):
>> 
>>         SNode awaitFulfill(SNode s, boolean timed, long nanos) {
>>             /*
>>              * When a node/thread is about to block, it sets its waiter
>>              * field and then rechecks state at least one more time
>>              * before actually parking, thus covering race vs
>>              * fulfiller noticing that waiter is non-null so should be
>>              * woken.
>>              *
>>              * When invoked by nodes that appear at the point of call
>>              * to be at the head of the stack, calls to park are
>>              * preceded by spins to avoid blocking when producers and
>>              * consumers are arriving very close in time.  This can
>>              * happen enough to bother only on multiprocessors.
>>              *
>>              * The order of checks for returning out of main loop
>>              * reflects fact that interrupts have precedence over
>>              * normal returns, which have precedence over
>>              * timeouts. (So, on timeout, one last check for match is
>>              * done before giving up.) Except that calls from untimed
>>              * SynchronousQueue.{poll/offer} don't check interrupts
>>              * and don't wait at all, so are trapped in transfer
>>              * method rather than calling awaitFulfill.
>>              */
>>             final long deadline = timed ? System.nanoTime() + nanos : 0L;
>>             Thread w = Thread.currentThread();
>>             int spins = shouldSpin(s)
>>                 ? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
>>                 : 0;
>>             for (;;) {
>>                 if (w.isInterrupted())
>>                     s.tryCancel();
>>                 SNode m = s.match;
>>                 if (m != null)
>>                     return m;
>>                 if (timed) {
>>                     nanos = deadline - System.nanoTime();
>>                     if (nanos <= 0L) {
>>                         s.tryCancel();
>>                         continue;
>>                     }
>>                 }
>>                 if (spins > 0) {
>>                     Thread.onSpinWait();
>>                     spins = shouldSpin(s) ? (spins - 1) : 0;
>>                 }
>>                 else if (s.waiter == null)
>>                     s.waiter = w; // establish waiter so can park next iter
>>                 else if (!timed)
>>                     LockSupport.park(this);
>>                 else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
>>                     LockSupport.parkNanos(this, nanos);
>>             }
>>         }
>> 
>> 
>> I've created https://bugs.openjdk.java.net/browse/JDK-8275728 to write such a microbenchmark.
>
> I suggest you do https://bugs.openjdk.java.net/browse/JDK-8275728 before you commit this. A benchmark which proves that this patch has some utility is needed, isn't it?

Hi Andrew (@theRealAph),
I've created a PR: https://github.com/openjdk/jdk/pull/6338 with a microbenchmark.

-------------

PR: https://git.openjdk.java.net/jdk/pull/5562


More information about the hotspot-dev mailing list