[concurrency-interest] Does factoring out VarHandle-based manipulations cause performance penalties?

Aleksey Shipilev shade at redhat.com
Wed Aug 9 04:30:22 EDT 2017


On 08/09/2017 10:25 AM, Aleksey Shipilev wrote:
> On 08/09/2017 10:17 AM, Dávid Karnok wrote:
>> In my codebase, targeting Java 9, I often have to perform the same set of atomic operations on
>> fields of various classes, for example, a deferred cancellation of Flow.Subscriptions:
>>
>> Flow.Subscription upstream;
>> static final VarHandle UPSTREAM;
>>
>> @Override
>> public void cancel() {
>>     Flow.Subscription a = (Flow.Subscription)UPSTREAM.getAcquire(this);
>>     if (a != CancelledSubscription.INSTANCE) {
>>         a = (Flow.Subscription)UPSTREAM.getAndSet(this, CancelledSubscription.INSTANCE);
>>         if (a != null && a != CancelledSubscription.INSTANCE) {
>>             a.cancel();
>>         }
>>     }
>> }
>>
>> Refactored into:
>>
>> final class SubscriptionHelper {
>>
>>     public static void cancel(Object target, VarHandle handle) {
>>         Flow.Subscription a = (Flow.Subscription)handle.getAcquire(target);
>>         if (a != CancelledSubscription.INSTANCE) {
>>             a = (Flow.Subscription)handle.getAndSet(target, CancelledSubscription.INSTANCE);
>>             if (a != null && a != CancelledSubscription.INSTANCE) {
>>                 a.cancel();
>>             }
>>         }
>>     }
>> }
>>
>> @Override
>> public void cancel() {
>>     SubscriptionHelper.cancel(this, UPSTREAM);
>> }
>>
>>
>> I'd think JIT can and will inline SubscriptionHelper.cancel to all its use sites, but the fact that
>> the cancel method no longer has "this" but an arbitrary target Object, my concern is that the
>> optimizations may not happen.
>>
>> I haven't noticed any performance penalties so far but I remember Aleksey Shipilev mentioning
>> somewhere, some time ago, a warning about such out-of-context VarHandle uses.
> 
> Like with Unsafe, like with Atomic*FieldUpdaters, like with *Handles in general, the compiler's
> ability to optimize is dependent on constant propagation. Putting the VarHandle to static final
> field helps that a lot, with the same mechanism as putting OFFSET for Unsafe accesses helps
> performance.
> 
> It your case above, making VarHandle a method parameter is performance-risky move, but it is
> mitigated by the use-site that loads it from the static final field anyway. Thus, if method is
> inlined, you get the same benefits. The concern for "Object" and "this" is not valid there, I think,
> because inlining propagates type information too.

I should have mentioned that at least in Hotspot, there is a real problem with type *profile*
pollution, because the type profile is context-agnostic, and bound to the concrete bytecode index.
So if SubscriptionHelper.cancel gets called with different "targets", *and* optimization depends on
profile, the inlining would not help to untangle that knot. Pretty sure the static type propagation
works fine there, but do test.

Thanks,
-Aleksey

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20170809/ff8f9eff/attachment.sig>


More information about the Concurrency-interest mailing list