Details
-
Bug
-
Resolution: Unresolved
-
P3
-
18
-
x86_64
-
windows_10
Description
ADDITIONAL SYSTEM INFORMATION :
MacOS with openjdk 13.0.2 but also WIndows 10 with open jdk 11.0.2 up to openjdk 18,
$ java --version
openjdk 18 2022-03-22
OpenJDK Runtime Environment (build 18+36-2087)
OpenJDK 64-Bit Server VM (build 18+36-2087, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
The performance of code like `IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y)` can have a 10-fold difference in performance when 3 instances of such an expressions are run.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
In the code below, a crude performance evaluation is made of streaming and reducing an array of integers.
Repeated calls to `IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y)` are made and the performance is quite good, not far from that of a native loop.
But If the statements on line 10 and 11 are commented out or the value n2 is changed to 3 or 4, then the performance drops ten-fold and permanently.
It seems that as soon as 3 different `IntStream.of(as).reduce(...)` instructions are involved the performance drops and never recovers.
It looks like a bug in the JVM optimizer that incorrectly switches to a different mode of execution that is much worse. I actually don't know the JVM works inside, but the performance drop is not something you want to happen.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The performance after uncommenting the lines should be similar to what you see in the original case, or should eventually reach a similar level.
ACTUAL -
A 10-fold drop in performance is observed and remains as long as the program runs.
---------- BEGIN SOURCE ----------
package perf;
import java.util.Random;
import java.util.stream.IntStream;
public class IntStreamTest2 {
public static void test(int len){
// final int[] bs = new int[len];
// IntStream.of(bs).reduce(0, (x, y) -> 0);
// IntStream.of(bs).reduce(0, (x, y) -> 1);
final int[] as = new int[len];
int max = 0;
Random random = new Random(0);
for( int i=0 ; i<len ; i++ ) {
as[i] = random.nextInt(1_000_000);
max = Math.max(max, as[i]);
}
// repeats of the whole sequence
int n2 = 1000;
// number of different reduce expressions
int n1 = 2;
// repeats of the same reduce formula
int n0 = 1;
for (int i = 0; i < n2; i++) {
for (int j = 0; j < n1; j++) {
for (int k = 0; k < n0; k++) {
long t0 = System.currentTimeMillis();
int result = 0;
if (j == 0) result = IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y);
if (j == 1) result = IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y);
if (j == 2) result = IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y);
if (j == 3) result = IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y);
long t1 = System.currentTimeMillis();
long time = t1 - t0;
System.out.format("%d %d %d: %d, %d ms %s\n", i, j, k, result, time, result != max ? "Calculation error." : "");
}
if( n0 > 1 ) System.out.println();
}
}
}
public static void main(String[] args) {
test(300_000_000);
}
}
---------- END SOURCE ----------
FREQUENCY : always
MacOS with openjdk 13.0.2 but also WIndows 10 with open jdk 11.0.2 up to openjdk 18,
$ java --version
openjdk 18 2022-03-22
OpenJDK Runtime Environment (build 18+36-2087)
OpenJDK 64-Bit Server VM (build 18+36-2087, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
The performance of code like `IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y)` can have a 10-fold difference in performance when 3 instances of such an expressions are run.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
In the code below, a crude performance evaluation is made of streaming and reducing an array of integers.
Repeated calls to `IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y)` are made and the performance is quite good, not far from that of a native loop.
But If the statements on line 10 and 11 are commented out or the value n2 is changed to 3 or 4, then the performance drops ten-fold and permanently.
It seems that as soon as 3 different `IntStream.of(as).reduce(...)` instructions are involved the performance drops and never recovers.
It looks like a bug in the JVM optimizer that incorrectly switches to a different mode of execution that is much worse. I actually don't know the JVM works inside, but the performance drop is not something you want to happen.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The performance after uncommenting the lines should be similar to what you see in the original case, or should eventually reach a similar level.
ACTUAL -
A 10-fold drop in performance is observed and remains as long as the program runs.
---------- BEGIN SOURCE ----------
package perf;
import java.util.Random;
import java.util.stream.IntStream;
public class IntStreamTest2 {
public static void test(int len){
// final int[] bs = new int[len];
// IntStream.of(bs).reduce(0, (x, y) -> 0);
// IntStream.of(bs).reduce(0, (x, y) -> 1);
final int[] as = new int[len];
int max = 0;
Random random = new Random(0);
for( int i=0 ; i<len ; i++ ) {
as[i] = random.nextInt(1_000_000);
max = Math.max(max, as[i]);
}
// repeats of the whole sequence
int n2 = 1000;
// number of different reduce expressions
int n1 = 2;
// repeats of the same reduce formula
int n0 = 1;
for (int i = 0; i < n2; i++) {
for (int j = 0; j < n1; j++) {
for (int k = 0; k < n0; k++) {
long t0 = System.currentTimeMillis();
int result = 0;
if (j == 0) result = IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y);
if (j == 1) result = IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y);
if (j == 2) result = IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y);
if (j == 3) result = IntStream.of(as).reduce(0, (x, y) -> x > y ? x : y);
long t1 = System.currentTimeMillis();
long time = t1 - t0;
System.out.format("%d %d %d: %d, %d ms %s\n", i, j, k, result, time, result != max ? "Calculation error." : "");
}
if( n0 > 1 ) System.out.println();
}
}
}
public static void main(String[] args) {
test(300_000_000);
}
}
---------- END SOURCE ----------
FREQUENCY : always