I was working on the next tutorial for the Java Mint Blog, and in writing some new small programs realized that boxing and unboxing has a pretty large impact. It is much better to use primitive types. That also implies that we can’t use generics for the staged function.
This generic ILambda
with R=Double, P=Double
has bad performance:
Code extends ILambda
<| new ILambda
public Double apply(Double param) {
return `(spower(<|param|>,17));
}
} |>;
ILambda
This non-generic ILambda_double_double
where return type and parameter type are fixed to primitive double
is much better:
Code extends ILambda_double_double> primCodePowerOf17 =
<| new ILambda_double_double() {
public double apply(double param) {
return `(spower(<|param|>,17));
}
} |>;
% mint BoxingUnboxingExpense power(2, 17) 10818348 stagedPowerOf17.apply(2.0) 10452177 primStagedPowerOf17.apply(2.0) 43746
This is for 200 million iterations. With boxing/unboxing overhead, the staged function barely breaks even.
I rewrote the benchmarking code to put less emphasis on the boxing/unboxing and re-ran our benchmarks. A lot of them stayed the same, but some power and fib_let gained another factor of two!
power 9.066x (up from 4.552) fib_let 8.834x (up from 4.107) eval-fact 10.384x (up from 8.390) loop-unroll 1.580x (slightly up from 1.439) power_let 5.703x (about same) partial-loop-unroll 0.965x (about same, 0.942x) serialize 18.433x (about same) mmult 0.913x (slightly down from 1.180) mmult-sparse 1.134x (slightly down from 1.469) eval-fib 9.911x (slightly down 10.210)