-
Bug
-
Resolution: Duplicate
-
P3
-
8u40
-
x86_64
-
linux
FULL PRODUCT VERSION :
$ ~/apps/jdk1.7.0_51/bin/java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
$ ~/apps/jdk1.8.0_31/bin/java -version
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
$ ~/apps/jdk1.8.0_40/bin/java -version
java version "1.8.0_40-ea"
Java(TM) SE Runtime Environment (build 1.8.0_40-ea-b23)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux se-185 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u1 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
See Test.java as an example that shows the problem. It is stripped down from the original code, to showcase the problem.
The JDK 7 compiler compiles this very fast. JDK 8 compilers seem to perform exponentially more work, and compilation time blows up. This to me is a severe performance regression, making it practically impossible to perform runtime in-memory code compilation.
For 9 'add' calls, as in Test.java, this is the performance:
$ time ~/apps/jdk1.7.0_51/bin/javac Test.java
real 0m0.418s
user 0m0.632s
sys 0m0.024s
(official Oracle JDK 7u51)
$ time ~/apps/jdk1.8.0_31/bin/javac Test.java
real 0m39.573s
user 0m43.199s
sys 0m0.204s
(official Oracle JDK 8u31)
$ time ~/apps/jdk1.8.0_40/bin/javac Test.java
real 0m37.020s
user 0m41.343s
sys 0m0.204s
(JDK 8u40 Early Access Releases, 8u40 Build b23)
Changing this to 10 'add' calls, as in Test2.java, this is the performance:
$ time ~/apps/jdk1.7.0_51/bin/javac Test2.java
real 0m0.427s
user 0m0.628s
sys 0m0.024s
$ time ~/apps/jdk1.8.0_31/bin/javac Test2.java
real 3m43.917s
user 3m49.058s
sys 0m0.440s
$ time ~/apps/jdk1.8.0_40/bin/javac Test2.java
real 3m34.365s
user 3m38.582s
sys 0m0.456s
It looks like the Java 8 compiler tries for each 'add' call all overloads of the 'add' method, resulting in 5^9=1,953,125 or 5^10=9,765,625 variants to try. This is an exponential blowup.
It should be noted that the Eclipse Luna JDT Java 8 compiler has no issues with this code, and compiles it very fast.
I looked, but could not find an existing bug report for this performance degradation.
REGRESSION. Last worked in version 7u65
ADDITIONAL REGRESSION INFORMATION:
See version information in earlier 'Development Kit or Runtime version' field.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
[Test.java]
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test {
public static void main(String[] args) {
int x = add(add(add(add(add(add(add(add(add(1, 2), 3), 4), 5), 6), 7), 8), 9), 10);
System.out.println(x);
}
public static int add(int x, int y) {
long rslt = (long)x + (long)y;
if (Integer.MIN_VALUE <= rslt && rslt <= Integer.MAX_VALUE) {
return (int)rslt;
}
String msg = String.format("Integer overflow: %d + %d.", x, y);
throw new IllegalArgumentException(msg);
}
public static double add(double x, double y) {
double rslt = x + y;
if (Double.isInfinite(rslt)) {
String msg = String.format("Real overflow: %s + %s.", x, y);
throw new IllegalArgumentException(msg);
}
return (rslt == -0.0) ? 0.0 : rslt;
}
public static <T> List<T> add(List<T> x, List<T> y) {
List<T> rslt = new ArrayList<>(x.size() + y.size());
rslt.addAll(x);
rslt.addAll(y);
return rslt;
}
public static String add(String x, String y) {
return x + y;
}
public static <K, V> Map<K, V> add(Map<K, V> x, Map<K, V> y) {
Map<K, V> rslt = new HashMap<>(x);
rslt.putAll(y);
return rslt;
}
}
[Test2.java]
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test2 {
public static void main(String[] args) {
int x = add(add(add(add(add(add(add(add(add(add(1, 2), 3), 4), 5), 6), 7), 8), 9), 10), 11);
System.out.println(x);
}
public static int add(int x, int y) {
long rslt = (long)x + (long)y;
if (Integer.MIN_VALUE <= rslt && rslt <= Integer.MAX_VALUE) {
return (int)rslt;
}
String msg = String.format("Integer overflow: %d + %d.", x, y);
throw new IllegalArgumentException(msg);
}
public static double add(double x, double y) {
double rslt = x + y;
if (Double.isInfinite(rslt)) {
String msg = String.format("Real overflow: %s + %s.", x, y);
throw new IllegalArgumentException(msg);
}
return (rslt == -0.0) ? 0.0 : rslt;
}
public static <T> List<T> add(List<T> x, List<T> y) {
List<T> rslt = new ArrayList<>(x.size() + y.size());
rslt.addAll(x);
rslt.addAll(y);
return rslt;
}
public static String add(String x, String y) {
return x + y;
}
public static <K, V> Map<K, V> add(Map<K, V> x, Map<K, V> y) {
Map<K, V> rslt = new HashMap<>(x);
rslt.putAll(y);
return rslt;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Renaming the 'add' methods to 'add_int', 'add_double', 'add_string', etc. Makes code generation a bit more involved, though.
$ ~/apps/jdk1.7.0_51/bin/java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
$ ~/apps/jdk1.8.0_31/bin/java -version
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
$ ~/apps/jdk1.8.0_40/bin/java -version
java version "1.8.0_40-ea"
Java(TM) SE Runtime Environment (build 1.8.0_40-ea-b23)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux se-185 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u1 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
See Test.java as an example that shows the problem. It is stripped down from the original code, to showcase the problem.
The JDK 7 compiler compiles this very fast. JDK 8 compilers seem to perform exponentially more work, and compilation time blows up. This to me is a severe performance regression, making it practically impossible to perform runtime in-memory code compilation.
For 9 'add' calls, as in Test.java, this is the performance:
$ time ~/apps/jdk1.7.0_51/bin/javac Test.java
real 0m0.418s
user 0m0.632s
sys 0m0.024s
(official Oracle JDK 7u51)
$ time ~/apps/jdk1.8.0_31/bin/javac Test.java
real 0m39.573s
user 0m43.199s
sys 0m0.204s
(official Oracle JDK 8u31)
$ time ~/apps/jdk1.8.0_40/bin/javac Test.java
real 0m37.020s
user 0m41.343s
sys 0m0.204s
(JDK 8u40 Early Access Releases, 8u40 Build b23)
Changing this to 10 'add' calls, as in Test2.java, this is the performance:
$ time ~/apps/jdk1.7.0_51/bin/javac Test2.java
real 0m0.427s
user 0m0.628s
sys 0m0.024s
$ time ~/apps/jdk1.8.0_31/bin/javac Test2.java
real 3m43.917s
user 3m49.058s
sys 0m0.440s
$ time ~/apps/jdk1.8.0_40/bin/javac Test2.java
real 3m34.365s
user 3m38.582s
sys 0m0.456s
It looks like the Java 8 compiler tries for each 'add' call all overloads of the 'add' method, resulting in 5^9=1,953,125 or 5^10=9,765,625 variants to try. This is an exponential blowup.
It should be noted that the Eclipse Luna JDT Java 8 compiler has no issues with this code, and compiles it very fast.
I looked, but could not find an existing bug report for this performance degradation.
REGRESSION. Last worked in version 7u65
ADDITIONAL REGRESSION INFORMATION:
See version information in earlier 'Development Kit or Runtime version' field.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
[Test.java]
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test {
public static void main(String[] args) {
int x = add(add(add(add(add(add(add(add(add(1, 2), 3), 4), 5), 6), 7), 8), 9), 10);
System.out.println(x);
}
public static int add(int x, int y) {
long rslt = (long)x + (long)y;
if (Integer.MIN_VALUE <= rslt && rslt <= Integer.MAX_VALUE) {
return (int)rslt;
}
String msg = String.format("Integer overflow: %d + %d.", x, y);
throw new IllegalArgumentException(msg);
}
public static double add(double x, double y) {
double rslt = x + y;
if (Double.isInfinite(rslt)) {
String msg = String.format("Real overflow: %s + %s.", x, y);
throw new IllegalArgumentException(msg);
}
return (rslt == -0.0) ? 0.0 : rslt;
}
public static <T> List<T> add(List<T> x, List<T> y) {
List<T> rslt = new ArrayList<>(x.size() + y.size());
rslt.addAll(x);
rslt.addAll(y);
return rslt;
}
public static String add(String x, String y) {
return x + y;
}
public static <K, V> Map<K, V> add(Map<K, V> x, Map<K, V> y) {
Map<K, V> rslt = new HashMap<>(x);
rslt.putAll(y);
return rslt;
}
}
[Test2.java]
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test2 {
public static void main(String[] args) {
int x = add(add(add(add(add(add(add(add(add(add(1, 2), 3), 4), 5), 6), 7), 8), 9), 10), 11);
System.out.println(x);
}
public static int add(int x, int y) {
long rslt = (long)x + (long)y;
if (Integer.MIN_VALUE <= rslt && rslt <= Integer.MAX_VALUE) {
return (int)rslt;
}
String msg = String.format("Integer overflow: %d + %d.", x, y);
throw new IllegalArgumentException(msg);
}
public static double add(double x, double y) {
double rslt = x + y;
if (Double.isInfinite(rslt)) {
String msg = String.format("Real overflow: %s + %s.", x, y);
throw new IllegalArgumentException(msg);
}
return (rslt == -0.0) ? 0.0 : rslt;
}
public static <T> List<T> add(List<T> x, List<T> y) {
List<T> rslt = new ArrayList<>(x.size() + y.size());
rslt.addAll(x);
rslt.addAll(y);
return rslt;
}
public static String add(String x, String y) {
return x + y;
}
public static <K, V> Map<K, V> add(Map<K, V> x, Map<K, V> y) {
Map<K, V> rslt = new HashMap<>(x);
rslt.putAll(y);
return rslt;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Renaming the 'add' methods to 'add_int', 'add_double', 'add_string', etc. Makes code generation a bit more involved, though.
- duplicates
-
JDK-8078093 Severe compiler performance regression Java 7 to 8 for nested method invocations
-
- Closed
-
- is blocked by
-
JDK-8051946 JEP 215: Tiered Attribution for javac
-
- Closed
-
- relates to
-
JDK-8078093 Severe compiler performance regression Java 7 to 8 for nested method invocations
-
- Closed
-