-
Type:
Enhancement
-
Resolution: Unresolved
-
Priority:
P4
-
Affects Version/s: 7, 9, 10
-
Component/s: hotspot
-
Cause Known
-
generic
-
generic
In the following program, the second loop executes 4-5 times slower than the first loop
even though the code is identical.
Looking at the generated code generated on SPARC, the actual body of the loops gets optimized away so the only difference is in the code generated for the loop
interation count. In the second loop, both the iteration count and loop limit
are spilled and reloaded each iteration of the loop. In the first loop, the iteration
count is kept in a register but the limit is spilled. There are more than
enough registers to hold both.
public class Bug {
public static final long ITERATIONS = 100000000L;
static boolean equalsEmpty(String s) {
return s.equals("");
}
static void warmUp() {
String equalsOperand = "";
String lengthOperand = "";
boolean equalsResult = true;
boolean lengthResult = true;
System.out.println("Beginning warmup ...");
for (long i = 0; i < 5000; i += 1) {
doLoops(5000);
}
for (long i = 0; i < 5000; i += 1) {
doLoops(5000);
}
for (long i = 0; i < 5000; i += 1) {
doLoops(5000);
}
System.out.println("Warmed up");
}
static long loop1Time;
static long loop2Time;
static void doTiming(long iterations) {
doLoops(iterations);
System.out.println("loop1: " + Long.toString(loop1Time));
System.out.println("loop2: " + Long.toString(loop2Time));
}
static void doLoops(long iterations) {
String loop1Operand = "";
String loop2Operand = "";
boolean loop1Result = true;
boolean loop2Result = true;
long loop1Begin = 0L;
long loop1End = 0L;
long loop2Begin = 0L;
long loop2End = 0L;
loop1Begin = System.currentTimeMillis();
for (long i = 0; i < iterations; i += 1) {
loop1Result |= equalsEmpty(loop1Operand);
}
loop1End = System.currentTimeMillis();
loop1Time = loop1End - loop1Begin;
loop2Begin = System.currentTimeMillis();
for (long i = 0; i < iterations; i++) {
loop2Result |= equalsEmpty(loop2Operand);
}
loop2End = System.currentTimeMillis();
loop2Time = loop2End - loop2Begin;
}
public static void main(String[] args) {
System.out.println("Begin test, ITERATIONS = " + ITERATIONS);
// Warm up
warmUp();
// Timing runs
doTiming(ITERATIONS);
doTiming(ITERATIONS);
doTiming(ITERATIONS);
doTiming(ITERATIONS);
doTiming(ITERATIONS);
}
}
even though the code is identical.
Looking at the generated code generated on SPARC, the actual body of the loops gets optimized away so the only difference is in the code generated for the loop
interation count. In the second loop, both the iteration count and loop limit
are spilled and reloaded each iteration of the loop. In the first loop, the iteration
count is kept in a register but the limit is spilled. There are more than
enough registers to hold both.
public class Bug {
public static final long ITERATIONS = 100000000L;
static boolean equalsEmpty(String s) {
return s.equals("");
}
static void warmUp() {
String equalsOperand = "";
String lengthOperand = "";
boolean equalsResult = true;
boolean lengthResult = true;
System.out.println("Beginning warmup ...");
for (long i = 0; i < 5000; i += 1) {
doLoops(5000);
}
for (long i = 0; i < 5000; i += 1) {
doLoops(5000);
}
for (long i = 0; i < 5000; i += 1) {
doLoops(5000);
}
System.out.println("Warmed up");
}
static long loop1Time;
static long loop2Time;
static void doTiming(long iterations) {
doLoops(iterations);
System.out.println("loop1: " + Long.toString(loop1Time));
System.out.println("loop2: " + Long.toString(loop2Time));
}
static void doLoops(long iterations) {
String loop1Operand = "";
String loop2Operand = "";
boolean loop1Result = true;
boolean loop2Result = true;
long loop1Begin = 0L;
long loop1End = 0L;
long loop2Begin = 0L;
long loop2End = 0L;
loop1Begin = System.currentTimeMillis();
for (long i = 0; i < iterations; i += 1) {
loop1Result |= equalsEmpty(loop1Operand);
}
loop1End = System.currentTimeMillis();
loop1Time = loop1End - loop1Begin;
loop2Begin = System.currentTimeMillis();
for (long i = 0; i < iterations; i++) {
loop2Result |= equalsEmpty(loop2Operand);
}
loop2End = System.currentTimeMillis();
loop2Time = loop2End - loop2Begin;
}
public static void main(String[] args) {
System.out.println("Begin test, ITERATIONS = " + ITERATIONS);
// Warm up
warmUp();
// Timing runs
doTiming(ITERATIONS);
doTiming(ITERATIONS);
doTiming(ITERATIONS);
doTiming(ITERATIONS);
doTiming(ITERATIONS);
}
}