Name: yyT116575 Date: 01/29/2001
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-RC)
Java HotSpot(TM) Client VM (build 1.3.0-RC, mixed mode)
Problem observed on
* JDK 1.3RC, on Solaris 2.6
* JDK 1.3 Release, on Redhat Linux 6.2, kernel 2.2.16
In some circumstances, a loop which
* performs a test and then
* executes an empty function
will run slower than a loop which
* performs a test and then
* executes a function which performs the same test
This problem was first observed attempting to perform a benchmark using
variations of the LinPack benchmark. The following Java source, when compiled,
demonstrates this issue. In the program output,
"Orig" Is the loop which simply calls the empty function;
"Mod" Is the loop which performs the test, then calls a function which performs
the same test; and
"Opt" Is the loop which performs the test, then calls an empty function.
We observed that "Mod" is faster than "Opt", according to our timer, even though
"Opt" executes less code. This behavior is repeatable. We tried varying the
parameters and the order of execution, with no change.
While this doesn't affect the usability of the Java Runtime, we feel it reflects
a bug in the runtime system or JIT compiler that ought to be addressed.
--- Begin Code:
import java.io.*;
class MethodTest {
public static void doSomething() {
flag = false;
throw new Error();
}
public static void main(String[] args) throws Exception {
flag = false;
MethodTest m = new MethodTest();
Thread.sleep(2000);
System.out.println("Opt");
m.doopt();
Thread.sleep(2000);
System.out.println("Mod");
m.domod();
Thread.sleep(2000);
System.out.println("Orig");
m.do0();
Thread.sleep(2000);
System.out.println("Mod");
m.domod();
Thread.sleep(2000);
System.out.println("Opt");
m.doopt();
Thread.sleep(2000);
System.out.println("Orig");
m.do0();
}
Timer sametimer;
Timer othertimer;
MethodTest mt;
public static volatile boolean flag = false;
static final int METHOD_CALLS = 1000000;
public void do0() {
int i;
sametimer = new Timer();
sametimer.mark();
for(i = 0; i < METHOD_CALLS; i++) {
empty0();
}
sametimer.record();
sametimer.report();
}
public void domod() {
int i;
if( flag )
doSomething();
sametimer = new Timer();
sametimer.mark();
for(i = 0; i < METHOD_CALLS; i++) {
if( flag )
doSomething();
empty1();
}
sametimer.record();
sametimer.report();
}
public void doopt() {
int i;
if( flag )
doSomething();
sametimer = new Timer();
sametimer.mark();
for(i = 0; i < METHOD_CALLS; i++) {
if( flag )
doSomething();
empty0();
}
sametimer.record();
sametimer.report();
}
public void empty0() { }
public void empty1() {
if( flag )
doSomething();
}
}
class Timer {
private long base_time;
private long elapsed_time;
private static final long UNIT = 1000;
public Timer() {
clear();
}
public void mark() {
base_time = System.currentTimeMillis();
}
public void clear() {
elapsed_time = 0;
}
public void record() {
elapsed_time += (System.currentTimeMillis() - base_time);
}
public float elapsed() {
return ((float) elapsed_time) / UNIT;
}
public void report(PrintStream pstream) {
float elapsed_seconds = elapsed();
pstream.println("Time " + elapsed_seconds + " sec");
}
public void report() {
report(System.out);
}
}
--- End Code. ---
(Review ID: 115926)
======================================================================