----- Mail original -----
> De: "Vladimir Ivanov" <vladimir.x.iva...@oracle.com>
> À: "Wenlei Xie" <wenlei....@gmail.com>, "Da Vinci Machine Project" 
> <mlvm-dev@openjdk.java.net>
> Envoyé: Mardi 20 Février 2018 00:14:42
> Objet: Re: Why is LambdaMetafactory 10% slower than a static MethodHandle but 
> 80% faster than a non-static MethodHandle?

>> Sorry if it's a dumb question, but why nonStaticMethodHandle cannot get
>> inlined here? -- In the benchmark it's always the same line with the
>> same final MethodHandle variable, can JIT based on some profiling info
>> to inline it (similar to the function object generated by
>> LambdaMetafactory). -- Or it cannot sine InvokeExact's
>> PolymorphicSignature makes it quite special?
> 
> Yes, method handle invokers are special and ordinary type profiling
> (class-based) doesn't work for them.
> 
> There was an idea to implement value profiling for MH invokers: record
> individual MethodHandle instances observed at invoker call sites and use
> that to guide devirtualizaiton & inlining decisions. But it looked way
> too specialized to be beneficial in practice.

Here is a code that does exactly that,
https://gist.github.com/forax/7bf08669f58804991fd45656a671c381

[...]

> Best regards,
> Vladimir Ivanov

Rémi

>> On Mon, Feb 19, 2018 at 4:00 AM, Vladimir Ivanov
>> <vladimir.x.iva...@oracle.com <mailto:vladimir.x.iva...@oracle.com>> wrote:
>> 
>>     Geoffrey,
>> 
>>     In both staticMethodHandle & lambdaMetafactory Dog::getName is
>>     inlined, but using different mechanisms.
>> 
>>     In staticMethodHandle target method is statically known [1], but in
>>     case of lambdaMetafactory [2] compiler has to rely on profiling info
>>     to devirtualize Function::apply(). The latter requires exact type
>>     check on the receiver at runtime and that explains the difference
>>     you are seeing.
>> 
>>     But comparing that with nonStaticMethodHandle is not fair: there's
>>     no inlining happening there.
>> 
>>     If you want a fair comparison, then you have to measure with
>>     polluted profile so no inlining happens. In that case [3] non-static
>>     MethodHandles are on par (or even slightly faster):
>> 
>>     LMF._4_lmf_fs  avgt   10  20.020 ± 0.635  ns/op
>>     LMF._4_lmf_mhs avgt   10  18.360 ± 0.181  ns/op
>> 
>>     (scores for 3 invocations in a row.)
>> 
>>     Best regards,
>>     Vladimir Ivanov
>> 
>>     [1] 715  126    b        org.lmf.LMF::_1_staticMethodHandle (11 bytes)
>>     ...
>>          @ 37
>>       java.lang.invoke.DirectMethodHandle$Holder::invokeVirtual (14
>>     bytes)   force inline by annotation
>>            @ 1   java.lang.invoke.DirectMethodHandle::internalMemberName
>>     (8 bytes)   force inline by annotation
>>            @ 10   org.lmf.LMF$Dog::getName (5 bytes)   accessor
>> 
>> 
>> 
>> 
>>     [2] 678  117    b        org.lmf.LMF::_2_lambdaMetafactory (14 bytes)
>>     @ 8   org.lmf.LMF$$Lambda$37/552160541::apply (8 bytes)   inline (hot)
>>       \-> TypeProfile (6700/6700 counts) = org/lmf/LMF$$Lambda$37
>>        @ 4   org.lmf.LMF$Dog::getName (5 bytes)   accessor
>> 
>> 
>>     [3] http://cr.openjdk.java.net/~vlivanov/misc/LMF.java
>>     <http://cr.openjdk.java.net/~vlivanov/misc/LMF.java>
>> 
>>          static Function make() throws Throwable {
>>              CallSite site = LambdaMetafactory.metafactory(LOOKUP,
>>                      "apply",
>>                      MethodType.methodType(Function.class),
>>                      MethodType.methodType(Object.class, Object.class),
>>                      LOOKUP.findVirtual(Dog.class, "getName",
>>     MethodType.methodType(String.class)),
>>                      MethodType.methodType(String.class, Dog.class));
>>              return (Function) site.getTarget().invokeExact();
>>          }
>> 
>>          private Function[] fs = new Function[] {
>>              make(), make(), make()
>>          };
>> 
>>          private MethodHandle[] mhs = new MethodHandle[] {
>>              nonStaticMethodHandle,
>>              nonStaticMethodHandle,
>>              nonStaticMethodHandle
>>          };
>> 
>>          @Benchmark
>>          public Object _4_lmf_fs() throws Throwable {
>>              Object r = null;
>>              for (Function f : fs {
>>                  r = f.apply(dogObject);
>>              }
>>              return r;
>>          }
>> 
>>          @Benchmark
>>          public Object _4_lmf_mh() throws Throwable {
>>              Object r = null;
>>              for (MethodHandle mh : mhs) {
>>                  r = mh.invokeExact(dogObject);
>>              }
>>              return r;
>> 
>>          }
>> 
>>     On 2/19/18 1:42 PM, Geoffrey De Smet wrote:
>> 
>>         Hi guys,
>> 
>>         I ran the following JMH benchmark on JDK 9 and JDK 8.
>>         Source code and detailed results below.
>> 
>>         Benchmark on JDK 9        Score
>>         staticMethodHandle          2.770
>>         lambdaMetafactory          3.052    // 10% slower
>>         nonStaticMethodHandle   5.250    // 90% slower
>> 
>>         Why is LambdaMetafactory 10% slower than a static MethodHandle
>>         but 80% faster than a non-static MethodHandle?
>> 
>> 
>>         Source code (copy paste ready)
>>         ====================
>> 
>>         import java.lang.invoke.CallSite;
>>         import java.lang.invoke.LambdaMetafactory;
>>         import java.lang.invoke.MethodHandle;
>>         import java.lang.invoke.MethodHandles;
>>         import java.lang.invoke.MethodType;
>>         import java.util.concurrent.TimeUnit;
>>         import java.util.function.Function;
>> 
>>         import org.openjdk.jmh.annotations.Be
>>         <http://org.openjdk.jmh.annotations.Be>nchmark;
>>         import org.openjdk.jmh.annotations.Be
>>         <http://org.openjdk.jmh.annotations.Be>nchmarkMode;
>>         import org.openjdk.jmh.annotations.Fo
>>         <http://org.openjdk.jmh.annotations.Fo>rk;
>>         import org.openjdk.jmh.annotations.Me
>>         <http://org.openjdk.jmh.annotations.Me>asurement;
>>         import org.openjdk.jmh.annotations.Mo
>>         <http://org.openjdk.jmh.annotations.Mo>de;
>>         import org.openjdk.jmh.annotations.OutputTimeUnit;
>>         import org.openjdk.jmh.annotations.Sc
>>         <http://org.openjdk.jmh.annotations.Sc>ope;
>>         import org.openjdk.jmh.annotations.St
>>         <http://org.openjdk.jmh.annotations.St>ate;
>>         import org.openjdk.jmh.annotations.Warmup;
>> 
>>         //Benchmark on JDK 9     Mode  Cnt  Score   Error  Units
>>         //staticMethodHandle     avgt   30  2.770 ± 0.023  ns/op // Baseline
>>         //lambdaMetafactory      avgt   30  3.052 ± 0.004  ns/op // 10%
>>         slower
>>         //nonStaticMethodHandle  avgt   30  5.250 ± 0.137  ns/op // 90%
>>         slower
>> 
>>         //Benchmark on JDK 8     Mode  Cnt  Score   Error  Units
>>         //staticMethodHandle     avgt   30  2.772 ± 0.022  ns/op // Baseline
>>         //lambdaMetafactory      avgt   30  3.060 ± 0.007  ns/op // 10%
>>         slower
>>         //nonStaticMethodHandle  avgt   30  5.037 ± 0.022  ns/op // 81%
>>         slower
>> 
>>         @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
>>         @Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
>>         @Fork(3)
>>         @BenchmarkMode(Mode.AverageTime)
>>         @OutputTimeUnit(TimeUnit.NANOSECONDS)
>>         @State(Scope.Thread)
>>         public class LamdaMetafactoryWeirdPerformance {
>> 
>>               //
>>         
>> ************************************************************************
>>               // Set up of the 3 approaches.
>>               //
>>         
>> ************************************************************************
>> 
>>               // Unusable for Java framework developers. Only usable by
>>         JVM language developers. Baseline.
>>               private static final MethodHandle staticMethodHandle;
>> 
>>               // Usuable for Java framework developers. 30% slower
>>               private final Function lambdaMetafactoryFunction;
>> 
>>               // Usuable for Java framework developers. 100% slower
>>               private final MethodHandle nonStaticMethodHandle;
>> 
>>               static {
>>                   // Static MethodHandle setup
>>                   try {
>>                       staticMethodHandle = MethodHandles.lookup()
>>                               .findVirtual(Dog.class, "getName",
>>         MethodType.methodType(String.class))
>>                              
>>         .asType(MethodType.methodType(Object.class, Object.class));
>>                   } catch (NoSuchMethodException |
>>         IllegalAccessException e) {
>>                       throw new IllegalStateException(e);
>>                   }
>>               }
>> 
>>               public LamdaMetafactoryWeirdPerformance() {
>>                   try {
>>                       MethodHandles.Lookup lookup = MethodHandles.lookup();
>> 
>>                       // LambdaMetafactory setup
>>                       CallSite site = LambdaMetafactory.metafactory(lookup,
>>                               "apply",
>>                               MethodType.methodType(Function.class),
>>                               MethodType.methodType(Object.class,
>>         Object.class),
>>                               lookup.findVirtual(Dog.class, "getName",
>>         MethodType.methodType(String.class)),
>>                               MethodType.methodType(String.class,
>>         Dog.class));
>>                       lambdaMetafactoryFunction = (Function)
>>         site.getTarget().invokeExact();
>> 
>>                       // Non-static MethodHandle setup
>>                       nonStaticMethodHandle = lookup
>>                               .findVirtual(Dog.class, "getName",
>>         MethodType.methodType(String.class))
>>                              
>>         .asType(MethodType.methodType(Object.class, Object.class));
>>                   } catch (Throwable e) {
>>                       throw new IllegalStateException(e);
>>                   }
>>               }
>> 
>>               //
>>         
>> ************************************************************************
>>               // Benchmark
>>               //
>>         
>> ************************************************************************
>> 
>>               private Object dogObject = new Dog("Fido");
>> 
>> 
>>               @Benchmark
>>               public Object _1_staticMethodHandle() throws Throwable {
>>                   return staticMethodHandle.invokeExact(dogObject);
>>               }
>> 
>>               @Benchmark
>>               public Object _2_lambdaMetafactory() {
>>                   return lambdaMetafactoryFunction.apply(dogObject);
>>               }
>> 
>>               @Benchmark
>>               public Object _3_nonStaticMethodHandle() throws Throwable {
>>                   return nonStaticMethodHandle.invokeExact(dogObject);
>>               }
>> 
>>               private static class Dog {
>>                   private String name;
>> 
>>                   public Dog(String name) {
>>         this.name <http://this.name> = name;
>>                   }
>> 
>>                   public String getName() {
>>                       return name;
>>                   }
>> 
>>               }
>> 
>>         }
>> 
>> 
>>         With kind regards,
>>         Geoffrey De Smet
>> 
>>         _______________________________________________
>>         mlvm-dev mailing list
>>         mlvm-dev@openjdk.java.net <mailto:mlvm-dev@openjdk.java.net>
>>         http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
>>         <http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev>
>> 
>>     _______________________________________________
>>     mlvm-dev mailing list
>>     mlvm-dev@openjdk.java.net <mailto:mlvm-dev@openjdk.java.net>
>>     http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
>>     <http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev>
>> 
>> 
>> 
>> 
>> --
>> Best Regards,
>> Wenlei Xie (谢文磊)
>> 
>> Email: wenlei....@gmail.com <mailto:wenlei....@gmail.com>
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev@openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to