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.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
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 = name;
        }

        public String getName() {
            return name;
        }

    }

}


With kind regards,
Geoffrey De Smet

_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to