Last active
December 14, 2016 08:39
-
-
Save schmitch/df9596699716788d37a52e2ceed2c3a2 to your computer and use it in GitHub Desktop.
Main.java perf problems
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Outcome: c.schmitt - MacBook Pro (Retina, 15", Ende 2013) - macOS 10.12.1 | |
sbt "jmh:run -i 10 -wi 10 -f1 -t1" | |
[info] Benchmark Mode Cnt Score Error Units | |
[info] Main.testMethod thrpt 10 19538048,171 ± 2224217,470 ops/s | |
[info] Main.testMethodHandleIntSupplierUnreflect thrpt 10 6735285,753 ± 281407,613 ops/s | |
[info] Main.testMethodHandleUnreflect thrpt 10 28706699,796 ± 755897,511 ops/s | |
[info] Main.testMethodHandleUnreflectListSize thrpt 10 20084867,818 ± 449023,818 ops/s | |
[info] Main.testMethodHandleUnreflectSimple thrpt 10 28637750,180 ± 685004,308 ops/s | |
[info] Main.testMethodHandleUnreflectSimpleArguments thrpt 10 5267296,404 ± 71604,568 ops/s | |
[info] Main.testMethodHandleUnreflectSimpleExact thrpt 10 28942872,351 ± 217140,908 ops/s | |
[info] Main.testMethodHandleVirtual thrpt 10 28358600,382 ± 597161,522 ops/s | |
[info] Main.testMethodHandleVirtualArguments thrpt 10 5308500,677 ± 236293,160 ops/s | |
*/ | |
package bla; | |
import org.openjdk.jmh.annotations.Benchmark; | |
import org.openjdk.jmh.annotations.Scope; | |
import org.openjdk.jmh.annotations.State; | |
import java.lang.invoke.MethodHandle; | |
import java.lang.invoke.MethodHandles; | |
import java.lang.invoke.MethodType; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Modifier; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.List; | |
import java.util.function.Function; | |
import java.util.function.IntSupplier; | |
@State(value = Scope.Benchmark) | |
public class Main { | |
private static final MethodHandle handle1; | |
private static final MethodHandle handle2; | |
private static final Method method; | |
private static final Function<Integer, String> f = (Integer s) -> "hello " + s; | |
private static final IntSupplier is = () -> 1; | |
public static Method fun(Class<?> actionFunction) { | |
Method actionMethod = null; | |
for (Method m : actionFunction.getMethods()) { | |
// Here I assume that we are always passing a `actionFunction` type that: | |
// 1) defines exactly one abstract method, and | |
// 2) the abstract method is the method that we want to invoke. | |
// This works fine with the current implementation of `PathPatternMatcher`, but I wouldn't be | |
// surprised if it breaks in the future, which is why this comment exists. | |
// Also, the former implementation (which was checking for the first non default method), was | |
// not working when using a `java.util.function.Function` type (Function.identity was being | |
// returned, instead of Function.apply). | |
if (Modifier.isAbstract(m.getModifiers())) { | |
actionMethod = m; | |
} | |
} | |
return actionMethod; | |
} | |
static { | |
try { | |
handle1 = t1(f, Function.class); | |
handle2 = t2(is, IntSupplier.class); | |
method = fun(Function.class); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
public static <T> MethodHandle t1(T action, Class<?> actionFunction) { | |
try { | |
final MethodHandles.Lookup lookup = MethodHandles.lookup(); | |
return lookup.findVirtual(actionFunction, "apply", | |
MethodType.methodType(Object.class, Object.class)); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
throw new RuntimeException(e); | |
} | |
} | |
public static <T> MethodHandle t2(T action, Class<?> actionFunction) { | |
try { | |
final MethodHandles.Lookup lookup = MethodHandles.lookup(); | |
return lookup.unreflect(fun(actionFunction)); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
throw new RuntimeException(e); | |
} | |
} | |
@Benchmark | |
public void testMethod() throws Throwable { | |
String ignored = (String) method.invoke(f, 1000); | |
} | |
@Benchmark | |
public void testMethodHandleVirtualArguments() throws Throwable { | |
String ignored = (String) ((Object) handle1.invokeWithArguments(f, (Object) 1000)); | |
} | |
@Benchmark | |
public void testMethodHandleVirtual() throws Throwable { | |
String ignored = (String) ((Object) handle1.invoke(f, (Object) 1000)); | |
} | |
@Benchmark | |
public void testMethodHandleUnreflectListSize() throws Throwable { | |
List<Object> li = Collections.singletonList(1000); | |
int s = li.size(); | |
if (s == 0) { | |
String ignored = (String) handle1.invoke(f); | |
} else if (s == 1) { | |
String ignored = (String) handle1.invoke(f, li.get(0)); | |
} else if (s == 2) { | |
String ignored = (String) handle1.invoke(f, li.get(0), li.get(1)); | |
} else if (s == 3) { | |
String ignored = (String) handle1.invoke(f, li.get(0), li.get(1), li.get(2)); | |
} else { | |
ArrayList<Object> al = new ArrayList<>(li); | |
al.add(0, f); | |
String ignored = (String) handle1.invokeWithArguments(al); | |
} | |
} | |
@Benchmark | |
public void testMethodHandleUnreflectSimple() throws Throwable { | |
String ignored = (String) ((Object) handle1.invoke(f, (Object) 1000)); | |
} | |
@Benchmark | |
public void testMethodHandleUnreflectSimpleExact() throws Throwable { | |
String ignored = (String) ((Object) handle1.invokeExact(f, (Object) 1000)); | |
} | |
@Benchmark | |
public void testMethodHandleUnreflectSimpleArguments() throws Throwable { | |
String ignored = (String) handle1.invokeWithArguments(f, (Object) 1000); | |
} | |
@Benchmark | |
public void testMethodHandleUnreflect() throws Throwable { | |
String ignored = (String) ((Object) handle1.invokeExact(f, (Object) 1000)); | |
} | |
@Benchmark | |
public void testMethodHandleIntSupplierUnreflect() throws Throwable { | |
int ignored = (int) handle2.invokeWithArguments(is); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment