Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8077247

Exponential performance regression Java 8 compiler compared to Java 7 compiler

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P3
    • Resolution: Duplicate
    • Affects Version/s: 8u40
    • Fix Version/s: 9
    • Component/s: tools
    • Labels:
    • Subcomponent:
    • CPU:
      x86_64
    • OS:
      linux

      Description

      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.

      1. Test.java
        1 kB
        Pardeep Sharma
      2. Test2.java
        1 kB
        Pardeep Sharma

        Issue Links

          Activity

          Hide
          pardesha Pardeep Sharma added a comment -
          1) Run the attached test cases (Test.java and Test2.java)

          2) Tested this on Linux-X64 and could reproduce the issue. There is a performance degradation from JDK 7 to 8, and 9 (7u80, 8u40, 9 ea b57)

          ****************************************************************************************
          Test.java
          (7u80): (8u40) (9 ea b57)
          real 3m1.81s real 5m30.87s real 4m8.84s
          user 0m1.26s user 1m44.39s user 1m36.28s
          sys 0m0.07s sys 0m0.07s sys 0m0.48s

          Test2.java
          (7u80): (8u40) (9 ea b57)
          real 2m58.51s real 10m12.54s real 9m9.51s
          user 0m1.24s user 9m31.20s user 8m54.83s
          sys 0m0.07s sys 0m0.97s sys 0m0.77s

          ******************************************************************************************
          Show
          pardesha Pardeep Sharma added a comment - 1) Run the attached test cases (Test.java and Test2.java) 2) Tested this on Linux-X64 and could reproduce the issue. There is a performance degradation from JDK 7 to 8, and 9 (7u80, 8u40, 9 ea b57) **************************************************************************************** Test.java (7u80): (8u40) (9 ea b57) real 3m1.81s real 5m30.87s real 4m8.84s user 0m1.26s user 1m44.39s user 1m36.28s sys 0m0.07s sys 0m0.07s sys 0m0.48s Test2.java (7u80): (8u40) (9 ea b57) real 2m58.51s real 10m12.54s real 9m9.51s user 0m1.24s user 9m31.20s user 8m54.83s sys 0m0.07s sys 0m0.97s sys 0m0.77s ******************************************************************************************
          Hide
          vromero Vicente Arturo Romero Zaldivar added a comment - - edited
          TA javac:

          Test.java
          real 0m1.157s
          user 0m2.856s
          sys 0m0.155s

          Test2.java
          real 0m1.227s
          user 0m2.926s
          sys 0m0.156s

          Amazing! we knew that the TA approach (http://hg.openjdk.java.net/tiered-attrib/dev/langtools) was faster than javac8 but faster than javac7!!! that's another dimension :)
          Show
          vromero Vicente Arturo Romero Zaldivar added a comment - - edited TA javac: Test.java real 0m1.157s user 0m2.856s sys 0m0.155s Test2.java real 0m1.227s user 0m2.926s sys 0m0.156s Amazing! we knew that the TA approach ( http://hg.openjdk.java.net/tiered-attrib/dev/langtools ) was faster than javac8 but faster than javac7!!! that's another dimension :)
          Hide
          vromero Vicente Arturo Romero Zaldivar added a comment -
          So the solution for this regression is being implemented as part of the tiered attribution (TA) project: http://openjdk.java.net/jeps/215
          Show
          vromero Vicente Arturo Romero Zaldivar added a comment - So the solution for this regression is being implemented as part of the tiered attribution (TA) project: http://openjdk.java.net/jeps/215
          Hide
          mcimadamore Maurizio Cimadamore added a comment -
          A test for this has been added as part of the changeset for JDK-8078093.
          Show
          mcimadamore Maurizio Cimadamore added a comment - A test for this has been added as part of the changeset for JDK-8078093 .

            People

            • Assignee:
              vromero Vicente Arturo Romero Zaldivar
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: