Few questions about invokeDynamic
assembling signals
assembling.signals at yandex.ru
Tue Nov 9 03:12:34 PST 2010
Remi, with your suggestion and the workaround the bug (by returning int),
here the updated "benchmark". Works, but still much slower than usual reflection.
The new code is under doDynSyntaxSpread() and displayed as "invoke dynamic syntax: spread".
Output is at the end.
= = = = = = = = = =
CODE
= = = = = = = = = =
import java.lang.reflect.*;
import java.text.*;
import java.dyn.*;
/*
* CAN ONLY BE COMPILED AND RAN OUTSIDE NETBEANS
*/
public class _BenchmarkDyn_onefile {
static abstract class Test {
final String name;
Test(String name) {
this.name = name;
}
abstract void run()
throws Throwable;
}
private final static int N_REPEATS = 10;
private final static long INNER_LOOP = 2 * 1000 * 1000;
private static long counter = 0;
private final static Object[] CACHED_ARGS_ARRAY = new Object[2];
private final static Method method;
private final static MethodHandle mhNormal;
private final static MethodHandle mhSpread;
private volatile static int DEOPTIMIZED_INT = System.getProperties().size();
public static int staticMethod(int i1, int i2) {
counter += i1;
counter += i2;
return 0;
}
private static int deoptimizedInt() {
return DEOPTIMIZED_INT;
}
static {
try {
method = _BenchmarkDyn_onefile.class.getMethod(
"staticMethod", int.class, int.class);
Linkage.registerBootstrapMethod("bootstrap");
mhNormal = MethodHandles.lookup().findStatic(
_BenchmarkDyn_onefile.class, "staticMethod",
MethodType.methodType(int.class, int.class, int.class));
mhSpread = MethodHandles.spreadArguments(mhNormal,
MethodType.methodType(int.class, Object[].class));
} catch (Exception ex) {
throw new Error(ex);
}
}
private static CallSite bootstrap(Class<?> declaring, String name, MethodType type) {
CallSite cs = new CallSite();
System.out.println(declaring + "." + name + " : " + type);
switch (name) {
case "nonSpread":
cs.setTarget(mhNormal);
break;
case "spread":
cs.setTarget(mhSpread);
break;
default:
throw new IllegalArgumentException(name);
}
return cs;
}
private static void doUsual() {
if (deoptimizedInt() >= 0) {
staticMethod(-1, +2);
}
}
private static void doDynSyntaxUsual()
throws Throwable {
if (deoptimizedInt() >= 0) {
int x;
x = (int) InvokeDynamic.nonSpread((int) -1, (int) +2);
}
}
private static void doDynSyntaxSpread()
throws Throwable {
if (deoptimizedInt() >= 0) {
// bug: when using on a M.H. without args, null is allowed for invokeVarargs, but fails
CACHED_ARGS_ARRAY[0] = -1;
CACHED_ARGS_ARRAY[1] = 2;
int x;
x = (int) InvokeDynamic.spread(CACHED_ARGS_ARRAY);
}
}
private static void doDynApiExactUsual()
throws Throwable {
if (deoptimizedInt() >= 0) {
int x;
x = (int) mhNormal.invokeExact((int) -1, (int) +2);
}
}
private static void doDynApiExectSpread()
throws Throwable {
if (deoptimizedInt() >= 0) {
CACHED_ARGS_ARRAY[0] = -1;
CACHED_ARGS_ARRAY[1] = 2;
// invokeExact and invokeGeneric both equally "fast"
int x;
x = (int) mhSpread.invokeExact(CACHED_ARGS_ARRAY);
}
}
private static void doReflect()
throws Throwable {
if (deoptimizedInt() >= 0) {
CACHED_ARGS_ARRAY[0] = -1;
CACHED_ARGS_ARRAY[1] = 2;
method.invoke(null, CACHED_ARGS_ARRAY);
}
}
private static void tests(Test[] tt) {
DecimalFormat format = new DecimalFormat("#0.00");
System.out.println("doing " + INNER_LOOP + " loop iterations "
+ N_REPEATS + " times...\n");
double[] times = new double[tt.length];
for (int t = 0; t < N_REPEATS; ++t) {
for (int i = 0; i < tt.length; ++i) {
times[i] += test(tt[i]);
}
System.out.print(".");
System.out.flush();
}
System.out.println("done!\n");
for (int i = 0; i < tt.length; ++i) {
System.out.println(tt[i].name + "\n\t" + format.format(times[i]) + "s");
}
}
private static double test(Test t) {
counter = 0;
long start = System.currentTimeMillis();
try {
t.run();
} catch (Throwable thr) {
throw new Error(thr);
}
long end = System.currentTimeMillis();
if (counter != INNER_LOOP) {
throw new AssertionError("counter != " + INNER_LOOP);
}
return (end - start) / 1000.0;
}
public static void main(String... args) {
Test[] tt = new Test[]{
new Test("usual method invocation") {
@Override
void run()
throws Throwable {
for (long i = 0; i < INNER_LOOP; ++i) {
doUsual();
}
}
},
new Test("invoke dynamic syntax: usual") {
@Override
void run()
throws Throwable {
for (long i = 0; i < INNER_LOOP; ++i) {
doDynSyntaxUsual();
}
}
},
new Test("invoke dynamic syntax: spread") {
@Override
void run()
throws Throwable {
for (long i = 0; i < INNER_LOOP; ++i) {
doDynSyntaxSpread();
}
}
},
new Test("invoke dynamic api: invokeExact usual") {
@Override
void run()
throws Throwable {
for (long i = 0; i < INNER_LOOP; ++i) {
doDynApiExactUsual();
}
}
},
new Test("invoke dynamic api: invokeExact spread") {
@Override
void run()
throws Throwable {
for (long i = 0; i < INNER_LOOP; ++i) {
doDynApiExectSpread();
}
}
},
new Test("reflection: using Method.invoke(...)") {
@Override
void run()
throws Throwable {
for (long i = 0; i < INNER_LOOP; ++i) {
doReflect();
}
}
} };
tests(tt);
}
}
= = = = = = = = = =
OUTPUT
= = = = = = = = = =
doing 2000000 loop iterations 10 times...
class javabenchmarks._BenchmarkDyn_onefile.nonSpread : (int,int)int
class javabenchmarks._BenchmarkDyn_onefile.spread : (java.lang.Object[])int
.........done!
usual method invocation
0.07s
invoke dynamic syntax: usual
0.09s
invoke dynamic syntax: spread
4.79s
invoke dynamic api: invokeExact usual
0.52s
invoke dynamic api: invokeExact spread
8.15s
reflection: using Method.invoke(...)
0.88s
More information about the mlvm-dev
mailing list