-
Enhancement
-
Resolution: Unresolved
-
P4
-
11, 17, 21, 25
-
x86_64
-
generic
ADDITIONAL SYSTEM INFORMATION :
Problem in any Java version, up until 23.0.1 If you execute the same Java bytecode with GraalVM 23.0.1 it works as expected. Note that I'm NOT using native-image. I'm executing the same Java class (bytecode) with Oracle JVM 23 and GraalJVM 23.
A DESCRIPTION OF THE PROBLEM :
The difference in performance is 30x. It looks like the HotSpot of the Oracle JVMs is not optimizing/compiling/inlining a simple and small arithmetic method correctly. All Graal JVMs are.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the provided source code (single, simple and small java class with everything needed)
2. Execute the Java class with Oracle JVM 23 => see the printed average latency around 200 nanoseconds
3. Execute the Java class with Graal JVM 23 => see the printed average latency around 7 nanoseconds
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The Oracle JVM 23 should optimize the method the same way the Graal JVM 23 is doing. There is no reason for this method not to be optimized. It is very small and only performs simple math operations. It feels like a bug or a bad decision that the Oracle JVM is doing.
ACTUAL -
The Oracle JVM 23 performs poorly. The Graal JVM 23 performs well.
---------- BEGIN SOURCE ----------
package com.coralblocks.coralbench.bug;
public class OracleJvm23MathBug {
// simple and small amount of math
// =====> should be optimized/compiled/inlined for sure!
private static final long doSomething(int load, int i) {
long x = 0;
for (int j = 0; j < load; j++) {
long pow = (i % 8) * (i % 16);
if (i % 2 == 0) {
x += pow;
} else {
x -= pow;
}
}
return x;
}
/*
* Execute this with OpenJDK/Zulu/Oracle JVM 23 => average 215 nanoseconds
* Now execute this with Graal23 JVM 23 => average 7 nanoseconds
*
* This bug can be observed in any platform (I tested on Linux and Mac)
*
* $ java -version
* java version "23.0.1" 2024-10-15
* Java(TM) SE Runtime Environment (build 23.0.1+11-39)
* Java HotSpot(TM) 64-Bit Server VM (build 23.0.1+11-39, mixed mode, sharing)
*
* $ java -cp target/coralbench-all.jar com.coralblocks.coralbench.bug.OracleJvm23MathBug
* Value computed: -550000000000
* Measurements: 10000000| Avg Time: 215 nanos | Min Time: 83 nanos | Max Time: 199750 nanos
*
* $ java -version
* java version "23.0.1" 2024-10-15
* Java(TM) SE Runtime Environment Oracle GraalVM 23.0.1+11.1 (build 23.0.1+11-jvmci-b01)
* Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 23.0.1+11.1 (build 23.0.1+11-jvmci-b01, mixed mode, sharing)
*
* $ java -cp target/coralbench-all.jar com.coralblocks.coralbench.bug.OracleJvm23MathBug
* Value computed: -550000000000
* Measurements: 10000000| Avg Time: 7 nanos | Min Time: 0 nanos | Max Time: 178625 nanos
*/
public static final void main(String[] args) {
final int iterations = 10_000_000;
final int load = 10_000;
NanoBench bench = new NanoBench();
long computed = 0;
for (int i = 0; i < iterations; i++) {
bench.mark();
computed += doSomething(load, i);
bench.measure();
}
System.out.println("Value computed: " + computed);
bench.printResults();
}
private static class NanoBench {
private int measurements;
private long totalTime, minTime, maxTime, time;
private final StringBuilder sb = new StringBuilder(128);
NanoBench() {
reset();
}
public final void reset() {
totalTime = time = measurements = 0;
maxTime = Long.MIN_VALUE;
minTime = Long.MAX_VALUE;
}
public final void mark() {
time = System.nanoTime();
}
public final void measure() {
long lastNanoTime = System.nanoTime() - time;
totalTime += lastNanoTime;
minTime = lastNanoTime < minTime ? lastNanoTime : minTime;
maxTime = lastNanoTime > maxTime ? lastNanoTime : maxTime;
measurements++;
}
public final void printResults() {
sb.setLength(0);
sb.append("Measurements: ").append(measurements);
sb.append("| Avg Time: ").append((long) (totalTime / (double) measurements)).append(" nanos");
sb.append(" | Min Time: ").append(minTime).append(" nanos");
sb.append(" | Max Time: ").append(maxTime).append(" nanos\n\n");
for (int i = 0; i < sb.length(); i++) System.out.print(sb.charAt(i));
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
No workaround for Oracle JVMs. We would need to switch to a Graal JVM.
FREQUENCY : always
Problem in any Java version, up until 23.0.1 If you execute the same Java bytecode with GraalVM 23.0.1 it works as expected. Note that I'm NOT using native-image. I'm executing the same Java class (bytecode) with Oracle JVM 23 and GraalJVM 23.
A DESCRIPTION OF THE PROBLEM :
The difference in performance is 30x. It looks like the HotSpot of the Oracle JVMs is not optimizing/compiling/inlining a simple and small arithmetic method correctly. All Graal JVMs are.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the provided source code (single, simple and small java class with everything needed)
2. Execute the Java class with Oracle JVM 23 => see the printed average latency around 200 nanoseconds
3. Execute the Java class with Graal JVM 23 => see the printed average latency around 7 nanoseconds
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The Oracle JVM 23 should optimize the method the same way the Graal JVM 23 is doing. There is no reason for this method not to be optimized. It is very small and only performs simple math operations. It feels like a bug or a bad decision that the Oracle JVM is doing.
ACTUAL -
The Oracle JVM 23 performs poorly. The Graal JVM 23 performs well.
---------- BEGIN SOURCE ----------
package com.coralblocks.coralbench.bug;
public class OracleJvm23MathBug {
// simple and small amount of math
// =====> should be optimized/compiled/inlined for sure!
private static final long doSomething(int load, int i) {
long x = 0;
for (int j = 0; j < load; j++) {
long pow = (i % 8) * (i % 16);
if (i % 2 == 0) {
x += pow;
} else {
x -= pow;
}
}
return x;
}
/*
* Execute this with OpenJDK/Zulu/Oracle JVM 23 => average 215 nanoseconds
* Now execute this with Graal23 JVM 23 => average 7 nanoseconds
*
* This bug can be observed in any platform (I tested on Linux and Mac)
*
* $ java -version
* java version "23.0.1" 2024-10-15
* Java(TM) SE Runtime Environment (build 23.0.1+11-39)
* Java HotSpot(TM) 64-Bit Server VM (build 23.0.1+11-39, mixed mode, sharing)
*
* $ java -cp target/coralbench-all.jar com.coralblocks.coralbench.bug.OracleJvm23MathBug
* Value computed: -550000000000
* Measurements: 10000000| Avg Time: 215 nanos | Min Time: 83 nanos | Max Time: 199750 nanos
*
* $ java -version
* java version "23.0.1" 2024-10-15
* Java(TM) SE Runtime Environment Oracle GraalVM 23.0.1+11.1 (build 23.0.1+11-jvmci-b01)
* Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 23.0.1+11.1 (build 23.0.1+11-jvmci-b01, mixed mode, sharing)
*
* $ java -cp target/coralbench-all.jar com.coralblocks.coralbench.bug.OracleJvm23MathBug
* Value computed: -550000000000
* Measurements: 10000000| Avg Time: 7 nanos | Min Time: 0 nanos | Max Time: 178625 nanos
*/
public static final void main(String[] args) {
final int iterations = 10_000_000;
final int load = 10_000;
NanoBench bench = new NanoBench();
long computed = 0;
for (int i = 0; i < iterations; i++) {
bench.mark();
computed += doSomething(load, i);
bench.measure();
}
System.out.println("Value computed: " + computed);
bench.printResults();
}
private static class NanoBench {
private int measurements;
private long totalTime, minTime, maxTime, time;
private final StringBuilder sb = new StringBuilder(128);
NanoBench() {
reset();
}
public final void reset() {
totalTime = time = measurements = 0;
maxTime = Long.MIN_VALUE;
minTime = Long.MAX_VALUE;
}
public final void mark() {
time = System.nanoTime();
}
public final void measure() {
long lastNanoTime = System.nanoTime() - time;
totalTime += lastNanoTime;
minTime = lastNanoTime < minTime ? lastNanoTime : minTime;
maxTime = lastNanoTime > maxTime ? lastNanoTime : maxTime;
measurements++;
}
public final void printResults() {
sb.setLength(0);
sb.append("Measurements: ").append(measurements);
sb.append("| Avg Time: ").append((long) (totalTime / (double) measurements)).append(" nanos");
sb.append(" | Min Time: ").append(minTime).append(" nanos");
sb.append(" | Max Time: ").append(maxTime).append(" nanos\n\n");
for (int i = 0; i < sb.length(); i++) System.out.print(sb.charAt(i));
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
No workaround for Oracle JVMs. We would need to switch to a Graal JVM.
FREQUENCY : always
- relates to
-
JDK-8346989 Deoptimization and re-compilation cycle with C2 compiled code
- Open