-
-
Save raphw/881e1745996f9d314ab0 to your computer and use it in GitHub Desktop.
package benchmark; | |
import org.openjdk.jmh.annotations.*; | |
import java.lang.invoke.MethodHandle; | |
import java.lang.invoke.MethodHandles; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.InvocationTargetException; | |
import java.util.concurrent.TimeUnit; | |
@State(Scope.Thread) | |
@BenchmarkMode(Mode.AverageTime) | |
@OutputTimeUnit(TimeUnit.NANOSECONDS) | |
public class FieldBenchmark { | |
private String value = "foo"; | |
private int primitiveValue = 42; | |
enum Access { | |
INSTANCE; | |
private String value = "bar"; | |
} | |
private Field reflective, reflectiveAccessible, reflectivePrimitive, reflectiveAccessiblePrimitive, reflectiveAccessiblePrivate; | |
private MethodHandle methodHandle, methodHandleUnreflected, methodHandlePrimitive, methodHandleUnreflectedPrimitive, methodHandleUnreflectedPrivate; | |
private static final MethodHandle METHOD_HANDLE_INLINE, METHOD_HANDLE_UNREFLECTED_INLINE, METHOD_HANDLE_PRIMITIVE_INLINE, METHOD_HANDLE_UNREFLECTED_PRIMITIVE, METHOD_HANDLE_UNREFLECTED_PRIVATE; | |
static { | |
try { | |
METHOD_HANDLE_INLINE = MethodHandles.lookup().findGetter(FieldBenchmark.class, "value", String.class); | |
METHOD_HANDLE_UNREFLECTED_INLINE = MethodHandles.lookup().unreflectGetter(FieldBenchmark.class.getDeclaredField("value")); | |
METHOD_HANDLE_PRIMITIVE_INLINE = MethodHandles.lookup().findGetter(FieldBenchmark.class, "primitiveValue", int.class); | |
METHOD_HANDLE_UNREFLECTED_PRIMITIVE = MethodHandles.lookup().unreflectGetter(FieldBenchmark.class.getDeclaredField("primitiveValue")); | |
Field reflectiveAccessiblePrivate = Access.class.getDeclaredField("value"); | |
reflectiveAccessiblePrivate.setAccessible(true); | |
METHOD_HANDLE_UNREFLECTED_PRIVATE = MethodHandles.lookup().unreflectGetter(reflectiveAccessiblePrivate); | |
} catch (Exception e) { | |
throw new AssertionError(); | |
} | |
} | |
@Setup | |
public void setup() throws Exception { | |
reflective = FieldBenchmark.class.getDeclaredField("value"); | |
reflectiveAccessible = FieldBenchmark.class.getDeclaredField("value"); | |
reflectiveAccessible.setAccessible(true); | |
reflectivePrimitive = FieldBenchmark.class.getDeclaredField("primitiveValue"); | |
reflectiveAccessiblePrimitive = FieldBenchmark.class.getDeclaredField("primitiveValue"); | |
reflectiveAccessiblePrimitive.setAccessible(true); | |
methodHandle = MethodHandles.lookup().findGetter(FieldBenchmark.class, "value", String.class); | |
methodHandleUnreflected = MethodHandles.lookup().unreflectGetter(reflective); | |
methodHandlePrimitive = MethodHandles.lookup().findGetter(FieldBenchmark.class, "primitiveValue", int.class); | |
methodHandleUnreflectedPrimitive = MethodHandles.lookup().unreflectGetter(reflectivePrimitive); | |
reflectiveAccessiblePrivate = Access.class.getDeclaredField("value"); | |
reflectiveAccessiblePrivate.setAccessible(true); | |
methodHandleUnreflectedPrivate = MethodHandles.lookup().unreflectGetter(reflectiveAccessiblePrivate); | |
} | |
@Benchmark | |
public Object normal() { | |
return value; | |
} | |
@Benchmark | |
public Object reflection() throws InvocationTargetException, IllegalAccessException { | |
return reflective.get(this); | |
} | |
@Benchmark | |
public Object reflectionAccessible() throws InvocationTargetException, IllegalAccessException { | |
return reflectiveAccessible.get(this); | |
} | |
@Benchmark | |
public Object handle() throws Throwable { | |
return methodHandle.invoke(this); | |
} | |
@Benchmark | |
public Object handleExact() throws Throwable { | |
return (String) methodHandle.invokeExact(this); | |
} | |
@Benchmark | |
public Object handleUnreflected() throws Throwable { | |
return methodHandleUnreflected.invoke(this); | |
} | |
@Benchmark | |
public Object handleUnreflectedExact() throws Throwable { | |
return (String) methodHandleUnreflected.invokeExact(this); | |
} | |
@Benchmark | |
public int primitive() { | |
return primitiveValue; | |
} | |
@Benchmark | |
public int reflectionPrimitive() throws InvocationTargetException, IllegalAccessException { | |
return (int) reflectivePrimitive.get(this); | |
} | |
@Benchmark | |
public int reflectionAccessiblePrimitive() throws InvocationTargetException, IllegalAccessException { | |
return (int) reflectiveAccessiblePrimitive.get(this); | |
} | |
@Benchmark | |
public int reflectionSpecializedPrimitive() throws InvocationTargetException, IllegalAccessException { | |
return reflectivePrimitive.getInt(this); | |
} | |
@Benchmark | |
public int reflectionAccessibleSpecializedPrimitive() throws InvocationTargetException, IllegalAccessException { | |
return reflectiveAccessiblePrimitive.getInt(this); | |
} | |
@Benchmark | |
public int handlePrimitive() throws Throwable { | |
return (int) methodHandlePrimitive.invoke(this); | |
} | |
@Benchmark | |
public int handleExactPrimitive() throws Throwable { | |
return (int) methodHandlePrimitive.invokeExact(this); | |
} | |
@Benchmark | |
public int handleUnreflectedPrimitive() throws Throwable { | |
return (int) methodHandleUnreflectedPrimitive.invoke(this); | |
} | |
@Benchmark | |
public int handleUnreflectedExactPrimitive() throws Throwable { | |
return (int) methodHandleUnreflectedPrimitive.invokeExact(this); | |
} | |
@Benchmark | |
public String privateNormal() { | |
return Access.INSTANCE.value; // accessor method | |
} | |
@Benchmark | |
public Object reflectionAccessiblePrivate() throws Exception { | |
return reflectiveAccessiblePrivate.get(Access.INSTANCE); | |
} | |
@Benchmark | |
public String handleUnreflectedPrivate() throws Throwable { | |
return (String) methodHandleUnreflectedPrivate.invokeExact((Access) Access.INSTANCE); | |
} | |
@Benchmark | |
public Object handleInline() throws Throwable { | |
return METHOD_HANDLE_INLINE.invoke(this); | |
} | |
@Benchmark | |
public Object handleExactInline() throws Throwable { | |
return (String) METHOD_HANDLE_INLINE.invokeExact(this); | |
} | |
@Benchmark | |
public Object handleUnreflectedInline() throws Throwable { | |
return METHOD_HANDLE_UNREFLECTED_INLINE.invoke(this); | |
} | |
@Benchmark | |
public Object handleUnreflectedExactInline() throws Throwable { | |
return (String) METHOD_HANDLE_UNREFLECTED_INLINE.invokeExact(this); | |
} | |
@Benchmark | |
public int handlePrimitiveInline() throws Throwable { | |
return (int) METHOD_HANDLE_PRIMITIVE_INLINE.invoke(this); | |
} | |
@Benchmark | |
public int handleExactPrimitiveInline() throws Throwable { | |
return (int) METHOD_HANDLE_PRIMITIVE_INLINE.invokeExact(this); | |
} | |
@Benchmark | |
public int handleUnreflectedPrimitiveInline() throws Throwable { | |
return (int) METHOD_HANDLE_UNREFLECTED_PRIMITIVE.invoke(this); | |
} | |
@Benchmark | |
public int handleUnreflectedExactPrimitiveInline() throws Throwable { | |
return (int) METHOD_HANDLE_UNREFLECTED_PRIMITIVE.invokeExact(this); | |
} | |
@Benchmark | |
public String handleUnreflectedPrivateInline() throws Throwable { | |
return (String) METHOD_HANDLE_UNREFLECTED_PRIVATE.invokeExact((Access) Access.INSTANCE); | |
} | |
} |
package benchmark; | |
import org.openjdk.jmh.annotations.*; | |
import java.lang.invoke.MethodHandle; | |
import java.lang.invoke.MethodHandles; | |
import java.lang.invoke.MethodType; | |
import java.lang.reflect.Method; | |
import java.util.concurrent.TimeUnit; | |
@State(Scope.Thread) | |
@BenchmarkMode(Mode.AverageTime) | |
@OutputTimeUnit(TimeUnit.NANOSECONDS) | |
public class InvocationBenchmark { | |
private String s1 = "foo", s2 = "bar", s3 = "qux", s4 = "baz"; | |
private String method(String a, String b, String c, String d) { | |
return a + b + c + d; | |
} | |
private int i1 = 1, i2 = 2, i3 = 3, i4 = 4; | |
private int methodPrimitive(int a, int b, int c, int d) { | |
return a + b + c + d; | |
} | |
enum Access { | |
INSTANCE; | |
private String method(String a, String b, String c, String d) { | |
return a + b + c + d; | |
} | |
} | |
private Method method, methodAccessible, methodPrimitive, methodAccessiblePrimitive, methodAccessiblePrivate; | |
private MethodHandle methodHandle, methodHandleUnreflected, methodHandlePrimitive, methodHandleUnreflectedPrimitive, methodHandleUnreflectedPrivate; | |
private static final MethodHandle METHOD_HANDLE_INLINE, METHOD_HANDLE_UNREFLECTED_INLINE, METHOD_HANDLE_PRIMITIVE_INLINE, METHOD_HANDLE_UNREFLECTED_PRIMITIVE_INLINE, METHOD_HANDLE_UNREFLECTED_PRIVATE_INLINE; | |
static { | |
try { | |
Method methodAccessible = InvocationBenchmark.class.getDeclaredMethod("method", String.class, String.class, String.class, String.class); | |
methodAccessible.setAccessible(true); | |
METHOD_HANDLE_INLINE = MethodHandles.lookup().findVirtual(InvocationBenchmark.class, "method", | |
MethodType.methodType(String.class, String.class, String.class, String.class, String.class)); | |
METHOD_HANDLE_UNREFLECTED_INLINE = MethodHandles.lookup().unreflect(methodAccessible); | |
Method methodAccessiblePrimitive = InvocationBenchmark.class.getDeclaredMethod("methodPrimitive", int.class, int.class, int.class, int.class); | |
methodAccessiblePrimitive.setAccessible(true); | |
METHOD_HANDLE_PRIMITIVE_INLINE = MethodHandles.lookup().findVirtual(InvocationBenchmark.class, "methodPrimitive", | |
MethodType.methodType(int.class, int.class, int.class, int.class, int.class)); | |
METHOD_HANDLE_UNREFLECTED_PRIMITIVE_INLINE = MethodHandles.lookup().unreflect(methodAccessiblePrimitive); | |
Method methodAccessiblePrivate = Access.class.getDeclaredMethod("method", String.class, String.class, String.class, String.class); | |
methodAccessiblePrivate.setAccessible(true); | |
METHOD_HANDLE_UNREFLECTED_PRIVATE_INLINE = MethodHandles.lookup().unreflect(methodAccessiblePrivate); | |
} catch (Exception e) { | |
throw new AssertionError(); | |
} | |
} | |
@Setup | |
public void setUp() throws Exception { | |
method = InvocationBenchmark.class.getDeclaredMethod("method", String.class, String.class, String.class, String.class); | |
methodAccessible = InvocationBenchmark.class.getDeclaredMethod("method", String.class, String.class, String.class, String.class); | |
methodAccessible.setAccessible(true); | |
methodHandle = MethodHandles.lookup().findVirtual(InvocationBenchmark.class, "method", | |
MethodType.methodType(String.class, String.class, String.class, String.class, String.class)); | |
methodHandleUnreflected = MethodHandles.lookup().unreflect(methodAccessible); | |
methodPrimitive = InvocationBenchmark.class.getDeclaredMethod("methodPrimitive", int.class, int.class, int.class, int.class); | |
methodAccessiblePrimitive = InvocationBenchmark.class.getDeclaredMethod("methodPrimitive", int.class, int.class, int.class, int.class); | |
methodAccessiblePrimitive.setAccessible(true); | |
methodHandlePrimitive = MethodHandles.lookup().findVirtual(InvocationBenchmark.class, "methodPrimitive", | |
MethodType.methodType(int.class, int.class, int.class, int.class, int.class)); | |
methodHandleUnreflectedPrimitive = MethodHandles.lookup().unreflect(methodAccessiblePrimitive); | |
methodAccessiblePrivate = Access.class.getDeclaredMethod("method", String.class, String.class, String.class, String.class); | |
methodAccessiblePrivate.setAccessible(true); | |
methodHandleUnreflectedPrivate = MethodHandles.lookup().unreflect(methodAccessiblePrivate); | |
} | |
@Benchmark | |
public Object normal() throws Exception { | |
return method(s1, s2, s3, s4); | |
} | |
@Benchmark | |
public Object reflection() throws Exception { | |
return method.invoke(this, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public Object reflectionAccessible() throws Exception { | |
return methodAccessible.invoke(this, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public Object handle() throws Throwable { | |
return methodHandle.invoke(this, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public Object handleExact() throws Throwable { | |
return (String) methodHandle.invokeExact(this, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public Object handleUnreflectedExact() throws Throwable { | |
return (String) methodHandleUnreflected.invokeExact(this, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public int primitive() { | |
return methodPrimitive(i1, i2, i3, i4); | |
} | |
@Benchmark | |
public int reflectionPrimitive() throws Throwable { | |
return (int) methodPrimitive.invoke(this, i1, i2, i3, i4); | |
} | |
@Benchmark | |
public int reflectionAccessiblePrimitive() throws Throwable { | |
return (int) methodAccessiblePrimitive.invoke(this, i1, i2, i3, i4); | |
} | |
@Benchmark | |
public int handlePrimitive() throws Throwable { | |
return (int) methodHandlePrimitive.invoke(this, i1, i2, i3, i4); | |
} | |
@Benchmark | |
public int handlePrimitiveBoxed() throws Throwable { | |
return (Integer) methodHandlePrimitive.invoke(this, Integer.valueOf(i1), Integer.valueOf(i2), Integer.valueOf(i3), Integer.valueOf(i4)); | |
} | |
@Benchmark | |
public int handlePrimitiveExact() throws Throwable { | |
return (int) methodHandlePrimitive.invokeExact(this, i1, i2, i3, i4); | |
} | |
@Benchmark | |
public Object handleUnreflectedPrimitiveExact() throws Throwable { | |
return (int) methodHandleUnreflectedPrimitive.invokeExact(this, i1, i2, i3, i4); | |
} | |
@Benchmark | |
public Object privateNormal() throws Exception { | |
return Access.INSTANCE.method(s1, s2, s3, s4); // accessor method indirection | |
} | |
@Benchmark | |
public Object reflectionAccessiblePrivate() throws Exception { | |
return methodAccessiblePrivate.invoke(Access.INSTANCE, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public Object handleUnreflectedExactPrivate() throws Throwable { | |
return (String) methodHandleUnreflectedPrivate.invokeExact(Access.INSTANCE, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public Object handleInline() throws Throwable { | |
return METHOD_HANDLE_INLINE.invoke(this, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public Object handleExactInline() throws Throwable { | |
return (String) METHOD_HANDLE_INLINE.invokeExact(this, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public Object handleUnreflectedExactInline() throws Throwable { | |
return (String) METHOD_HANDLE_UNREFLECTED_INLINE.invokeExact(this, s1, s2, s3, s4); | |
} | |
@Benchmark | |
public int handlePrimitiveInline() throws Throwable { | |
return (int) METHOD_HANDLE_PRIMITIVE_INLINE.invoke(this, i1, i2, i3, i4); | |
} | |
@Benchmark | |
public int handlePrimitiveBoxedInline() throws Throwable { | |
return (Integer) METHOD_HANDLE_PRIMITIVE_INLINE.invoke(this, Integer.valueOf(i1), Integer.valueOf(i2), Integer.valueOf(i3), Integer.valueOf(i4)); | |
} | |
@Benchmark | |
public int handlePrimitiveExactInline() throws Throwable { | |
return (int) METHOD_HANDLE_UNREFLECTED_PRIMITIVE_INLINE.invokeExact(this, i1, i2, i3, i4); | |
} | |
@Benchmark | |
public int handleUnreflectedPrimitiveExactInline() throws Throwable { | |
return (int) METHOD_HANDLE_UNREFLECTED_PRIMITIVE_INLINE.invokeExact(this, i1, i2, i3, i4); | |
} | |
@Benchmark | |
public Object handleUnreflectedExactPrivateInline() throws Throwable { | |
return (String) METHOD_HANDLE_UNREFLECTED_PRIVATE_INLINE.invokeExact(Access.INSTANCE, s1, s2, s3, s4); | |
} | |
} |
package benchmark; | |
import org.openjdk.jmh.annotations.*; | |
import java.lang.invoke.MethodHandle; | |
import java.lang.invoke.MethodHandles; | |
import java.lang.invoke.MethodType; | |
import java.lang.reflect.Method; | |
import java.util.concurrent.TimeUnit; | |
@State(Scope.Thread) | |
@BenchmarkMode(Mode.AverageTime) | |
@OutputTimeUnit(TimeUnit.NANOSECONDS) | |
public class LookupBenchmark { | |
private String name = "method"; | |
private MethodHandles.Lookup lookup; | |
private MethodType methodType; | |
private Class<?> returnType = void.class, declaringType = LookupBenchmark.class; | |
void method() { | |
/* empty */ | |
} | |
@Setup | |
public void setUp() throws Exception { | |
lookup = MethodHandles.lookup(); | |
methodType = MethodType.methodType(void.class); | |
} | |
@Benchmark | |
public Method reflection() throws Exception { | |
return declaringType.getDeclaredMethod(name); | |
} | |
@Benchmark | |
public MethodHandle handle() throws Exception { | |
return MethodHandles.lookup().findVirtual(declaringType, name, MethodType.methodType(returnType)); | |
} | |
@Benchmark | |
public MethodHandle handlePreLookedUp() throws Exception { | |
return lookup.findVirtual(declaringType, name, methodType); | |
} | |
} |
Benchmark Mode Cnt Score Error Units | |
b.FieldBenchmark.normal avgt 20 2,558 ± 0,031 ns/op | |
b.FieldBenchmark.primitive avgt 20 2,116 ± 0,092 ns/op | |
b.FieldBenchmark.privateNormal avgt 20 2,514 ± 0,016 ns/op | |
b.FieldBenchmark.reflection avgt 20 5,855 ± 0,164 ns/op | |
b.FieldBenchmark.reflectionAccessible avgt 20 5,515 ± 0,013 ns/op | |
b.FieldBenchmark.reflectionAccessiblePrimitive avgt 20 5,742 ± 0,033 ns/op | |
b.FieldBenchmark.reflectionAccessiblePrivate avgt 20 5,484 ± 0,089 ns/op | |
b.FieldBenchmark.reflectionAccessibleSpecializedPrimitive avgt 20 5,850 ± 0,050 ns/op | |
b.FieldBenchmark.reflectionPrimitive avgt 20 5,783 ± 0,131 ns/op | |
b.FieldBenchmark.reflectionSpecializedPrimitive avgt 20 5,765 ± 0,030 ns/op | |
b.FieldBenchmark.handle avgt 20 6,367 ± 0,167 ns/op | |
b.FieldBenchmark.handleExact avgt 20 7,154 ± 0,128 ns/op | |
b.FieldBenchmark.handleInline avgt 20 5,289 ± 0,143 ns/op | |
b.FieldBenchmark.handleExactInline avgt 20 2,523 ± 0,015 ns/op | |
b.FieldBenchmark.handlePrimitive avgt 20 5,545 ± 0,061 ns/op | |
b.FieldBenchmark.handleExactPrimitive avgt 20 5,558 ± 0,043 ns/op | |
b.FieldBenchmark.handlePrimitiveInline avgt 20 2,043 ± 0,055 ns/op | |
b.FieldBenchmark.handleExactPrimitiveInline avgt 20 2,023 ± 0,029 ns/op | |
b.FieldBenchmark.handleUnreflected avgt 20 6,151 ± 0,040 ns/op | |
b.FieldBenchmark.handleUnreflectedExact avgt 20 7,097 ± 0,025 ns/op | |
b.FieldBenchmark.handleUnreflectedInline avgt 20 5,314 ± 0,067 ns/op | |
b.FieldBenchmark.handleUnreflectedExactInline avgt 20 2,513 ± 0,005 ns/op | |
b.FieldBenchmark.handleUnreflectedPrimitive avgt 20 5,643 ± 0,047 ns/op | |
b.FieldBenchmark.handleUnreflectedExactPrimitive avgt 20 5,544 ± 0,035 ns/op | |
b.FieldBenchmark.handleUnreflectedPrimitiveInline avgt 20 2,047 ± 0,026 ns/op | |
b.FieldBenchmark.handleUnreflectedExactPrimitiveInline avgt 20 2,013 ± 0,015 ns/op | |
b.FieldBenchmark.handleUnreflectedPrivate avgt 20 7,249 ± 0,053 ns/op | |
b.FieldBenchmark.handleUnreflectedPrivateInline avgt 20 2,558 ± 0,032 ns/op | |
# Run on Windows 8.1, x86-64 with Java1.8.0_25 |
Benchmark Mode Cnt Score Error Units | |
b.InvocationBenchmark.normal avgt 20 28,364 ± 1,378 ns/op | |
b.InvocationBenchmark.primitive avgt 20 2,469 ± 0,011 ns/op | |
b.InvocationBenchmark.privateNormal avgt 20 27,122 ± 0,158 ns/op | |
b.InvocationBenchmark.reflection avgt 20 31,026 ± 0,213 ns/op | |
b.InvocationBenchmark.reflectionPrimitive avgt 20 29,537 ± 2,152 ns/op | |
b.InvocationBenchmark.reflectionAccessible avgt 20 30,420 ± 0,216 ns/op | |
b.InvocationBenchmark.reflectionAccessiblePrimitive avgt 20 28,582 ± 1,160 ns/op | |
b.InvocationBenchmark.reflectionAccessiblePrivate avgt 20 33,566 ± 3,674 ns/op | |
b.InvocationBenchmark.handle avgt 20 32,195 ± 2,448 ns/op | |
b.InvocationBenchmark.handleExact avgt 20 36,736 ± 0,908 ns/op | |
b.InvocationBenchmark.handleInline avgt 20 33,549 ± 3,397 ns/op | |
b.InvocationBenchmark.handleExactInline avgt 20 27,241 ± 0,114 ns/op | |
b.InvocationBenchmark.handlePrimitive avgt 20 8,525 ± 0,055 ns/op | |
b.InvocationBenchmark.handlePrimitiveBoxed avgt 20 10,443 ± 0,370 ns/op | |
b.InvocationBenchmark.handlePrimitiveExact avgt 20 8,237 ± 0,025 ns/op | |
b.InvocationBenchmark.handlePrimitiveInline avgt 20 2,467 ± 0,006 ns/op | |
b.InvocationBenchmark.handlePrimitiveBoxedInline avgt 20 9,966 ± 0,036 ns/op | |
b.InvocationBenchmark.handlePrimitiveExactInline avgt 20 2,462 ± 0,007 ns/op | |
b.InvocationBenchmark.handleUnreflectedExact avgt 20 30,176 ± 0,239 ns/op | |
b.InvocationBenchmark.handleUnreflectedExactPrivate avgt 20 29,882 ± 0,152 ns/op | |
b.InvocationBenchmark.handleUnreflectedPrimitiveExact avgt 20 8,765 ± 0,250 ns/op | |
b.InvocationBenchmark.handleUnreflectedExactInline avgt 20 28,594 ± 3,065 ns/op | |
b.InvocationBenchmark.handleUnreflectedExactPrivateInline avgt 20 39,853 ± 6,530 ns/op | |
b.InvocationBenchmark.handleUnreflectedPrimitiveExactInline avgt 20 2,539 ± 0,035 ns/op | |
# Run on Windows 8.1, x86-64 with Java1.8.0_25 |
Benchmark Mode Cnt Score Error Units | |
b.LookupBenchmark.reflection avgt 20 151,434 ± 15,701 ns/op | |
b.LookupBenchmark.handle avgt 20 913,461 ± 144,966 ns/op | |
b.LookupBenchmark.handlePreLookedUp avgt 20 784,532 ± 105,980 ns/op | |
# Run on Windows 8.1, x86-64 with Java1.8.0_25 |
You are right. However, soring a method handle in a static field takes away the possibility of determining a method handle dynamically. This way, you could for example not use the handles in order to avoid the costs of reflection. Only when invoking methods with primitive values, exact invocation can be faster than reflection thanks to the synthetic descriptors and the avoided boxing that come with them.
where can I find the org.openjdk.jmh.annotation jar for JDK?
where can I find the org.openjdk.jmh.annotation jar for JDK?
Here is a link to the repository, clone it for yourself, and then build yourself the necessary module
It might be interesting to add benchmarks for using the LambdaMetafactory to generate lambdas as functional interface implementations.
For example, in InvocationBenchmark
, you could add
static interface QuadString {
String method(String a, String b, String c, String d);
}
static interface QuadInt {
int methodPrimitive(int a, int b, int c, int d);
}
...
private QuadString lambdaString;
private QuadInt lambdaInt;
...
@Setup
public void setUp() throws Throwable {
...
final MethodHandles.Lookup lookup = MethodHandles.lookup();
final MethodHandle quadMh = lookup.unreflect(method);
lambdaString = (QuadString) LambdaMetafactory.metafactory(lookup,
"method",
MethodType.methodType(QuadString.class, InvocationBenchmark.class),
MethodType.methodType(String.class, String.class, String.class, String.class, String.class),
quadMh,
MethodType.methodType(String.class, String.class, String.class, String.class, String.class))
.getTarget()
.bindTo(this)
.invoke();
final MethodHandle primitiveMh = lookup.unreflect(methodPrimitive);
lambdaInt = (QuadInt) LambdaMetafactory.metafactory(lookup,
"methodPrimitive",
MethodType.methodType(QuadInt.class, InvocationBenchmark.class),
MethodType.methodType(int.class, int.class, int.class, int.class, int.class),
primitiveMh,
MethodType.methodType(int.class, int.class, int.class, int.class, int.class))
.getTarget()
.bindTo(this)
.invoke();
}
...
@Benchmark
public Object lambda() {
return lambdaString.method(s1, s2, s3, s4);
}
@Benchmark
public int lambdaPrimitive() {
return lambdaInt.methodPrimitive(i1, i2, i3, i4);
}
This approach, even with jdk 8, seems to get <1ns performance penalty compared to directly calling the method.
I've not played with fields, but presumably same approach applies, and there the jdk Supplier functional interface should work (with some primitive specialties also).
That would indeed be interesting, maybe I will add it if I find the time.
MHs should be assigned to static final fields so the JIT can inline them.
In some circumstances instance final fields work too if -XX:+TrustFinalNonStaticFields is enabled and the compiler can link that instance to another constant.