MethodHandle performance

Claes Redestad claes.redestad at oracle.com
Thu Jan 12 20:29:46 UTC 2017


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 appears to be a known issue[1], so a design that can use invoke or
invokeExact instead should be considered:

-    this.constructor = constructorHandle;
+    this.constructor = constructorHandle.asSpreader(Object[].class, 
propertyTypes.size());

...

-        return (T) constructor.invokeWithArguments(args);
+        return (T) constructor.invoke(args);

This seems sufficient to get the MH-based implementation on par with
the reflection based one in all tests.

Thanks!

/Claes

[1] https://bugs.openjdk.java.net/browse/JDK-8078511

On 2017-01-12 20:46, Michael Rasmussen wrote:
> Doing a quick JMH benchmark here, with a constructor taking 4
> arguments, invokeWithArguments was about 15-30x slower than invoke and
> invokeExact.
> Otherwise, static final MH was 2.5x faster then reflection, and
> instance field MH was 1.3x faster
>
> For output and test code:
> https://gist.github.com/anonymous/32e698d04c7456c10f069686072d7cc6
>
> /Michael
>
> On 12 January 2017 at 20:12, Stephen Colebourne <scolebourne at joda.org> wrote:
>> @Claes
>>
>> Fat fingers - should have been 1.8.0_112
>>
>> The code is in the link:
>> https://github.com/JodaOrg/joda-beans/commit/ad7d61a7ff72f932957127117dd8f377e1e2bf60
>>
>> where a HandleMetaBean (method handle) performs the same job as
>> LightMetaBean (reflection) as shown in the non-JMH test
>> TestHandle.main().
>>
>> @Jochen
>>
>> The method handle setup code is all done in static initializers. The
>> performance tests are all testing runtime usage, excluding the static
>> initializer setup cost (as one off startup costs are not relevant to
>> my use case).
>>
>> @Remi
>> Thanks for taking a look. Its the constructor invocation that is most
>> obviously a problem. In HandleMetaBean.build(Object[]) where it uses
>> invokeWithArguments(Object[]). I get 1650ms for reflection vs 3500ms
>> for method handles.
>>
>> The meta-property getter code runs much quicker, so a JMH test would
>> really be needed to confirm the difference there.
>>
>> The asType() and invokeExact() code was added to see if that made a
>> difference, but it did not.
>>
>> @Aleksey
>> I saw you post when researching before writing my mail today. The code
>> cannot use static final method handles (I doubt there are many use
>> cases for those, to be honest). The goal of the code here is to obtain
>> an object implementing my interfaces that can be invoked in a general
>> way to invoke a constructor or a getter. As such, the method handles
>> need to be instance variables.
>>
>> I have now done a JMH test.
>>
>> The good news is that the method handle for the getter is slightly
>> faster when taken in isolation:
>>
>> JodaBenchmark.testMethodHandleGet    avgt   50    8.421 ± 0.078  ns/op
>> JodaBenchmark.testReflectionGet      avgt   50   11.003 ± 0.050  ns/op
>>
>> The bad news is that the method handle constructor call is not 2x
>> reflection, but 6x:
>>
>> JodaBenchmark.testMethodHandleBuild  avgt   50  219.212 ± 2.400  ns/op
>> JodaBenchmark.testReflectionBuild    avgt   50   36.012 ± 0.167  ns/op
>>
>> This test reduced the difference to :
>>    return (T) constructorHandle.invokeWithArguments(args);
>> vs
>>     return constructor.newInstance(args);
>>
>> Email me privately for a zip of the JMH test:
>>
>> Any thoughts on the 6x slower call? thanks for looking
>> Stephen
>>
>>
>> On 12 January 2017 at 14:47, Claes Redestad <claes.redestad at oracle.com> wrote:
>>> Hi Stephen,
>>>
>>> this is surprising; handles should typically be as fast or much
>>> faster than reflection (VarHandles can be faster than Unsafe in certain
>>> cases), but may carry a slightly more expensive setup cost - do you have a
>>> reproducer I could try?
>>>
>>> 8b122 - do you mean 8u122 EA?
>>>
>>> Thanks!
>>>
>>> /Claes
>>>
>>>
>>> On 2017-01-12 15:23, Stephen Colebourne wrote:
>>>>
>>>> I've recently tried [1] converting Joda-Beans use of setAccessible()
>>>> to use MethodHandle. Since it is a code generator, the actual coding
>>>> is relatively easy, and obtaining the MethodHandles.Lookup instance
>>>> with the "private" capability is simple. While the MethodHandles API
>>>> looks very complex, it isn't too bad to use, although it is
>>>> undoubtedly more complex than reflection.
>>>>
>>>> (Note that the standard Joda-Beans technique is to code generate
>>>> normal Java code to avoid the need to use reflection, but it can
>>>> optionally generate reflection-based code in "light bean" mode. It is
>>>> that reflection approach that is being examined here).
>>>>
>>>> The real problem however is performance. In my tests, I am seeing a
>>>> MethodHandle approach being 2 to 3 times slower than a reflection
>>>> approach for identical functionality, which is quite a significant
>>>> degradation. (using Java 8 b122)
>>>>
>>>> Given the performance, I left to question whether the repeated Jigsaw
>>>> advice to use MethodHandle instead of setAccessible is viable - in the
>>>> kinds of places that use reflection, performance tends to be critical.
>>>> Is there, or has there been, work in Java 9 to improve the performance
>>>> of method handles?
>>>>
>>>> Stephen
>>>>
>>>> [1] https://github.com/JodaOrg/joda-beans/commits/wip/methodhandles
>>>>
>>>


More information about the jigsaw-dev mailing list