MethodHandle performance

Remi Forax forax at univ-mlv.fr
Sat Jan 14 14:53:46 UTC 2017


Attila,
you can use @Stable initialized with null instead of final when you declare the spreaderCache so you do not have to use Unsafe.

Rémi

----- Mail original -----
> De: "Hontvári Attila" <attila at hontvari.net>
> À: jigsaw-dev at openjdk.java.net
> Envoyé: Samedi 14 Janvier 2017 13:56:58
> Objet: Re: MethodHandle performance

> As an experiment I have reimplemented MethodHandle::invokeWithArguments,
> so it only generates a spreader on the first invocation, after that the
> spreader will be reused. Now it is 10 times faster, therefore it reaches
> the performance of reflection. If we don't pass primitive arguments, the
> performance is close to MethodHandle::invoke.
> 
> https://gist.github.com/hoat4/b459938cf7ae93e64bba3208c69af567
> 
> On the first invocation of iWA, the new code checks if the MH is a
> fixed-arity MH, or a varargs collector. In case of a fixed-arity MH,
> this is simple, it stores the spreadInvoker in a field to be called by
> iWA. But if the MH is a varargs-collector, it creates a new object for
> caching the spreaders by the arguments count, and the iWA calls will be
> forwarded to this object.
> 
> To enable inlining of a constant MH's iWA, the spreader is stored in a
> final field. The field's initial value is an MH pointing to a setup
> method, and when it is called, it generates the spreader, and rewrites
> the final field with the generated spreader. This is risky, but I
> couldn't induce the JVM to inline the wrong spreader method. I haven't
> considered concurrency problems.
> 
> I've ran Michael Rasmussen's benchmark. This is the original JDK 8
> MethodHandle:
> 
> Benchmark                              Mode  Cnt    Score Error  Units
> 
> MyBenchmark.invoke                     avgt    5   25,611 ± 0,256  ns/op
> MyBenchmark.invokeExact                avgt    5   25,658 ± 0,116  ns/op
> MyBenchmark.invokeWithArguments        avgt    5  397,023 ± 39,137  ns/op
> MyBenchmark.reflective                 avgt    5   42,578 ± 4,206  ns/op
> MyBenchmark.staticInvoke               avgt    5   18,863 ± 0,417  ns/op
> MyBenchmark.staticInvokeExact          avgt    5   18,918 ± 0,461  ns/op
> MyBenchmark.staticInvokeWithArguments  avgt    5  390,777 ± 41,888  ns/op
> 
> And this is the new code's performance:
> 
> Benchmark                              Mode  Cnt   Score Error  Units
> MyBenchmark.invoke                     avgt    5  25,623 ± 0,249 ns/op
> MyBenchmark.invokeExact                avgt    5  25,623 ± 0,390 ns/op
> MyBenchmark.invokeWithArguments        avgt    5  44,167 ± 0,774 ns/op
> MyBenchmark.reflective                 avgt    5  42,549 ± 4,202 ns/op
> MyBenchmark.staticInvoke               avgt    5  19,025 ± 0,417 ns/op
> MyBenchmark.staticInvokeExact          avgt    5  18,910 ± 0,304 ns/op
> MyBenchmark.staticInvokeWithArguments  avgt    5  32,013 ± 2,749 ns/op
> 
>  Attila
> 
> 2017-01-13 20:04 keltezéssel, John Rose írta:
>> On Jan 12, 2017, at 12:29 PM, Claes Redestad <claes.redestad at oracle.com> wrote:
>>> Right, I was just looking at the micro Stephen provided me, and it does
>>> seem that the added cost for this case is due to invokeWithArguments
>>> creating a new invoker every time.
>> This is a good workaround, and Stephen's report is a helpful reminder
>> that our performance story has a sharp edge.
>>
>> We cache spreaders in the case of varargs methods,
>> for full performance, but not for the ad hoc spreader used by MH.iWA.
>>
>> We should cache them, to remove this sharp edge (or performance pothole).
>> There are small technical challenges to do so.  Claes and I added
>> some notes to the bug report; maybe someone can look into it more.
>>
> > — John


More information about the jigsaw-dev mailing list