MethodHandle performance

Stephen Colebourne scolebourne at joda.org
Fri Jan 13 11:23:19 UTC 2017


Thanks Claes and everyone else who took a look. The asSpreader() trick
does indeed work.

So it looks like method handles can be a viable alternative to
reflection for Jigsaw, but users of method handles do need to take
care about the pattern of usage of method handles to get performance.
Hopefully JDK-8078511 will get addressed at some point too.

(Part of the problem I suspect is that because fewer people have
looked at method handles, there is less experience of how to use them
effectively on the web)

thanks
Stephen


On 12 January 2017 at 20:29, 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 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