MethodHandle lookup&invocation performance
Alexander Turner
nerdscentral at googlemail.com
Sat Jul 9 07:13:25 PDT 2011
Hi,
I am Alex Turner - I was working on a COBOL to JVM compiler and am now
helping with a Magik to JVM compiler. I thought I might just confirm
that invokeExact has proven a lt ot quicker than invoke in our tests.
We have also noticed that using a method adapter to convert argument
counts makes things a little slower (a few percent). But using an
adapter then invokeExact is much faster than using invoke.
My approach from here is to try very hard to avoid invoke and only use
it when there is no realistic chance of resolving an invokeExact for
more than one call.
Best wishes - AJ
On 9 July 2011 14:08, Hiroshi Nakamura <nakahiro at gmail.com> wrote:
> Hello,
>
> Thanks for your swift responses.
>
> On Sat, Jul 9, 2011 at 19:29, Rémi Forax <forax at univ-mlv.fr> wrote:
>>> You should avoid to create constants more than once.
>
> Indeed. I updated the benckmark. (please see below)
>
>>> Also, bindTo() will create a method handle for-each call.
>
> Sure, but 'bindTo(rec).invokeExact(arg)' looks faster than
> 'invoke(rec, arg)' for this microbenchmark.
>
>>> or like that:
>>>
>>> private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
>>> private static final MethodType mt = MethodType.methodType(String.class, String.class);
>>> private static final MethodType mt2 = MethodType.methodType(String.class, Object.class, String.class);
>>>
>>> private static MethodHandle methodhandleLookup(Object receiver, String methodName) throws Throwable {
>>> MethodHandle mh = lookup.findVirtual(receiver.getClass(), methodName, mt);
>>> return mh.asType(mt2);
>>> }
>>>
>>> private static String methodhandleInvoke(Object receiver, MethodHandle method) throws Throwable {
>>> return (String) method.bindTo(receiver).invokeExact(receiver, "methodhandle");
>>> }
>>
>> oups, typo:
>>
>> private static String methodhandleInvoke(Object receiver, MethodHandle method) throws Throwable {
>> return (String) method.invokeExact(receiver, "methodhandle");
>> }
>
> Thank you very much. I didn't understand asType well.
>
> Here's the updated code:
> https://raw.github.com/nahi/jsr292-sandbox/master/src/jp/gr/java_conf/jruby/MethodHandleTest.java
> and the benchmark result follows. I updated 'methodhandle' as
> 'methodhandle1' to use constants, and added 'methodhandle2' which uses
> 'asType'. Interestingly, 'methodhandle2' invocation perf got as fast
> as reflection, but lookup got slower than 'methodhandle1'.
>
> -- 0
> methodhandle1 lookup * 100000: 557.97 [msec], average: 5.58 [nsec]
> methodhandle1 lookup+invoke * 100000: 431.21 [msec], average: 4.31 [nsec]
> methodhandle2 lookup * 100000: 413.81 [msec], average: 4.14 [nsec]
> methodhandle2 lookup+invoke * 100000: 297.56 [msec], average: 2.98 [nsec]
> reflection lookup * 100000: 99.52 [msec], average: 1.00 [nsec]
> reflection lookup+invoke * 100000: 181.40 [msec], average: 1.81 [nsec]
> -- 1
> methodhandle1 lookup * 100000: 192.42 [msec], average: 1.92 [nsec]
> methodhandle1 lookup+invoke * 100000: 289.65 [msec], average: 2.90 [nsec]
> methodhandle2 lookup * 100000: 267.24 [msec], average: 2.67 [nsec]
> methodhandle2 lookup+invoke * 100000: 327.26 [msec], average: 3.27 [nsec]
> reflection lookup * 100000: 38.44 [msec], average: 0.38 [nsec]
> reflection lookup+invoke * 100000: 65.53 [msec], average: 0.66 [nsec]
> -- 2
> methodhandle1 lookup * 100000: 176.79 [msec], average: 1.77 [nsec]
> methodhandle1 lookup+invoke * 100000: 270.87 [msec], average: 2.71 [nsec]
> methodhandle2 lookup * 100000: 259.02 [msec], average: 2.59 [nsec]
> methodhandle2 lookup+invoke * 100000: 289.60 [msec], average: 2.90 [nsec]
> reflection lookup * 100000: 31.77 [msec], average: 0.32 [nsec]
> reflection lookup+invoke * 100000: 104.24 [msec], average: 1.04 [nsec]
> -- 3
> methodhandle1 lookup * 100000: 220.45 [msec], average: 2.20 [nsec]
> methodhandle1 lookup+invoke * 100000: 282.01 [msec], average: 2.82 [nsec]
> methodhandle2 lookup * 100000: 265.23 [msec], average: 2.65 [nsec]
> methodhandle2 lookup+invoke * 100000: 299.53 [msec], average: 3.00 [nsec]
> reflection lookup * 100000: 39.24 [msec], average: 0.39 [nsec]
> reflection lookup+invoke * 100000: 70.76 [msec], average: 0.71 [nsec]
> -- 4
> methodhandle1 lookup * 100000: 183.54 [msec], average: 1.84 [nsec]
> methodhandle1 lookup+invoke * 100000: 268.61 [msec], average: 2.69 [nsec]
> methodhandle2 lookup * 100000: 262.18 [msec], average: 2.62 [nsec]
> methodhandle2 lookup+invoke * 100000: 284.43 [msec], average: 2.84 [nsec]
> reflection lookup * 100000: 28.34 [msec], average: 0.28 [nsec]
> reflection lookup+invoke * 100000: 62.86 [msec], average: 0.63 [nsec]
> -- 5
> methodhandle1 lookup * 100000: 182.89 [msec], average: 1.83 [nsec]
> methodhandle1 lookup+invoke * 100000: 260.14 [msec], average: 2.60 [nsec]
> methodhandle2 lookup * 100000: 262.31 [msec], average: 2.62 [nsec]
> methodhandle2 lookup+invoke * 100000: 284.80 [msec], average: 2.85 [nsec]
> reflection lookup * 100000: 28.60 [msec], average: 0.29 [nsec]
> reflection lookup+invoke * 100000: 67.08 [msec], average: 0.67 [nsec]
> -- 6
> methodhandle1 lookup * 100000: 191.14 [msec], average: 1.91 [nsec]
> methodhandle1 lookup+invoke * 100000: 260.52 [msec], average: 2.61 [nsec]
> methodhandle2 lookup * 100000: 246.75 [msec], average: 2.47 [nsec]
> methodhandle2 lookup+invoke * 100000: 282.33 [msec], average: 2.82 [nsec]
> reflection lookup * 100000: 28.98 [msec], average: 0.29 [nsec]
> reflection lookup+invoke * 100000: 66.73 [msec], average: 0.67 [nsec]
> -- 7
> methodhandle1 lookup * 100000: 182.27 [msec], average: 1.82 [nsec]
> methodhandle1 lookup+invoke * 100000: 260.33 [msec], average: 2.60 [nsec]
> methodhandle2 lookup * 100000: 255.34 [msec], average: 2.55 [nsec]
> methodhandle2 lookup+invoke * 100000: 290.13 [msec], average: 2.90 [nsec]
> reflection lookup * 100000: 30.20 [msec], average: 0.30 [nsec]
> reflection lookup+invoke * 100000: 72.33 [msec], average: 0.72 [nsec]
> -- 8
> methodhandle1 lookup * 100000: 176.21 [msec], average: 1.76 [nsec]
> methodhandle1 lookup+invoke * 100000: 267.92 [msec], average: 2.68 [nsec]
> methodhandle2 lookup * 100000: 261.67 [msec], average: 2.62 [nsec]
> methodhandle2 lookup+invoke * 100000: 285.91 [msec], average: 2.86 [nsec]
> reflection lookup * 100000: 34.12 [msec], average: 0.34 [nsec]
> reflection lookup+invoke * 100000: 68.78 [msec], average: 0.69 [nsec]
> -- 9
> methodhandle1 lookup * 100000: 181.78 [msec], average: 1.82 [nsec]
> methodhandle1 lookup+invoke * 100000: 265.34 [msec], average: 2.65 [nsec]
> methodhandle2 lookup * 100000: 252.99 [msec], average: 2.53 [nsec]
> methodhandle2 lookup+invoke * 100000: 299.42 [msec], average: 2.99 [nsec]
> reflection lookup * 100000: 31.08 [msec], average: 0.31 [nsec]
> reflection lookup+invoke * 100000: 66.65 [msec], average: 0.67 [nsec]
>
> Am I still missing something?
>
> Regards,
> // NaHi
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
>
--
Dr Alexander J Turner
http://nerds-central.blogspot.com/2008/01/about-me.html
More information about the mlvm-dev
mailing list