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