Blocks :
|
|
Duplicate :
|
|
Relates :
|
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.
|