Skip to content

Instantly share code, notes, and snippets.

@tokrug
Created September 1, 2020 19:20
Show Gist options
  • Save tokrug/7ff58f014aee05470525c5c4ae6528b4 to your computer and use it in GitHub Desktop.
Save tokrug/7ff58f014aee05470525c5c4ae6528b4 to your computer and use it in GitHub Desktop.
Reflections / Method handle / Lambda metafactory benchmark
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
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.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
@Fork(value = 2, warmups = 4)
@Warmup(iterations = 5, time = 5000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 5000, timeUnit = TimeUnit.MILLISECONDS)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public class MethodHandleBenchmark {
@State(Scope.Benchmark)
public static class BenchmarkState {
public TestClass instance;
public Method reflectionMethod;
public MethodHandle originalHandle;
public MethodHandle methodHandle;
public Supplier<String> lambda;
@Setup(Level.Trial)
public void setUp()
throws Throwable {
instance = new TestClass("asdf");
reflectionMethod = TestClass.class.getMethod("getName");
Lookup lookup = MethodHandles.lookup();
originalHandle = lookup.unreflect(reflectionMethod);
methodHandle = originalHandle.bindTo(instance);
CallSite callSite = LambdaMetafactory.metafactory(lookup,
// name of the method defined in the target functional interface
"get",
// implemented type and captured objects
MethodType.methodType(Supplier.class, TestClass.class),
// type erasure, Supplier will return an Object
MethodType.methodType(Object.class),
originalHandle,
// must inclue real target parameter types, return type can be Object.class
MethodType.methodType(String.class));
lambda = (Supplier<String>) callSite.getTarget().bindTo(instance).invoke();
}
}
@Benchmark
public void reflections(Blackhole blackhole, BenchmarkState state)
throws InvocationTargetException, IllegalAccessException {
blackhole.consume(state.reflectionMethod.invoke(state.instance));
}
@Benchmark
public void directAccess(Blackhole blackhole, BenchmarkState state) {
blackhole.consume(state.instance.getName());
}
@Benchmark
public void methodHandle(Blackhole blackhole, BenchmarkState state) throws Throwable {
blackhole.consume(state.methodHandle.invoke());
}
@Benchmark
public void lambda(Blackhole blackhole, BenchmarkState state) {
blackhole.consume(state.lambda.get());
}
}
public class TestClass {
private final String name;
public TestClass(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment