A DESCRIPTION OF THE REQUEST :
When carrying out a computation using immutable objects over a loop then escape analysis can significantly improve the speed by reducing the amount of intermediate objects created when chaining various operations together.
But when such an immediate object is carried over to the next loop iteration it seems that the compiler does not perform scalar-replacement for the one that is carried.
It should be easy to see in the test-case that the slot used to carry the data will not be referenced in a later point in the loop, so the last result should be allocated to the same stack slot.
In other words, stack slots used for scalar replacement should be treated more like registers and re-used when the objects they replace won't be used any further.
Tested with jdk7ea b144
JUSTIFICATION :
This improvement would make stack allocation more robust and thus provide a greater speedup when using immutable objects to carry out a chain of calculations spanning more than one loop iteration.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Approach B in the provided source-code should be faster than or as fast as A since it does not involve a copying operation and the cross product should be directly assigned to the slot for the variable r.
ACTUAL -
Approach A is faster
---------- BEGIN SOURCE ----------
public class Testcase {
private static final class Vector {
int a, b, c;
public Vector(int a, int b, int c) {
this.a = a;this.b = b;this.c = c;
}
Vector cross(Vector o) {
return new Vector(a*o.b,b*o.c,c*o.a);
}
void copyFrom(Vector other) {
a = other.a;b = other.b;c = other.c;
}
}
static void test() {
int x = 0;
Vector r = new Vector(1,2,3);
long nano = System.nanoTime();
for(int i=0;i<100000000;i++)
{
Vector a = new Vector(i,i+1,i+2);
Vector b = new Vector(i,i-1,i-2);
Vector t = r.cross(a).cross(b);
// r.copyFrom(t); // Approach A
r = t; // Approach B
}
System.out.println((System.nanoTime()- nano)/(1000*1000));
System.out.println("ignore me "+r.a+" "+x);
}
public static void main(String[] args) {
for(int i=0;i<10;i++)
test();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
For calculations using short-lived wrapper objects the workaround is using a mix of immutable and mutable operations. See "Approach A" in the provided example.
When carrying out a computation using immutable objects over a loop then escape analysis can significantly improve the speed by reducing the amount of intermediate objects created when chaining various operations together.
But when such an immediate object is carried over to the next loop iteration it seems that the compiler does not perform scalar-replacement for the one that is carried.
It should be easy to see in the test-case that the slot used to carry the data will not be referenced in a later point in the loop, so the last result should be allocated to the same stack slot.
In other words, stack slots used for scalar replacement should be treated more like registers and re-used when the objects they replace won't be used any further.
Tested with jdk7ea b144
JUSTIFICATION :
This improvement would make stack allocation more robust and thus provide a greater speedup when using immutable objects to carry out a chain of calculations spanning more than one loop iteration.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Approach B in the provided source-code should be faster than or as fast as A since it does not involve a copying operation and the cross product should be directly assigned to the slot for the variable r.
ACTUAL -
Approach A is faster
---------- BEGIN SOURCE ----------
public class Testcase {
private static final class Vector {
int a, b, c;
public Vector(int a, int b, int c) {
this.a = a;this.b = b;this.c = c;
}
Vector cross(Vector o) {
return new Vector(a*o.b,b*o.c,c*o.a);
}
void copyFrom(Vector other) {
a = other.a;b = other.b;c = other.c;
}
}
static void test() {
int x = 0;
Vector r = new Vector(1,2,3);
long nano = System.nanoTime();
for(int i=0;i<100000000;i++)
{
Vector a = new Vector(i,i+1,i+2);
Vector b = new Vector(i,i-1,i-2);
Vector t = r.cross(a).cross(b);
// r.copyFrom(t); // Approach A
r = t; // Approach B
}
System.out.println((System.nanoTime()- nano)/(1000*1000));
System.out.println("ignore me "+r.a+" "+x);
}
public static void main(String[] args) {
for(int i=0;i<10;i++)
test();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
For calculations using short-lived wrapper objects the workaround is using a mix of immutable and mutable operations. See "Approach A" in the provided example.
- relates to
-
JDK-6853701 Scalar replacement (escape analysis) fails for simple test case
- Open