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

Failure to optimize methods that unconditionally throw

    XMLWordPrintable

Details

    • Enhancement
    • Resolution: Unresolved
    • P3
    • tbd
    • 7, 9, 10
    • hotspot
    • generic
    • generic

    Description

      While trying to improve ArrayList performance for

      5103956: (coll) Suggested improvement to speed up ArrayList<E> get and set calls

      I encountered an anomaly in server compiler optimization.

      Basically, since the performance of ArrayList.get() and set() is critical,
      we were willing to perform code micro-tweaks to make hotspot optimizers happy.

      In particular, for error-handling, we had ArrayList.rangeCheck:

          private void rangeCheck(int index) {
              if (index >= size)
                  throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
          }

      We refactored this to make the client compiler happier.

      All of the possible refactorings gave equal performance under the server compiler,
      except one. Here are 3 refactorings:
       
             if (index >= size)
                  throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
       
          private String outOfBoundsMsg(int index) {
      return "Index: "+index+", Size: "+size;
          }
       

      ----------

                if (index >= size)
                  throw outOfBoundsException(index);
       
          private IndexOutOfBoundsException outOfBoundsException(int index) {
      return new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
          }

      ----------

              if (index >= size)
                  outOfBounds(index);
       
          private void outOfBounds(int index) {
      throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
          }

      ----------

      The refactoring using outOfBounds is dramatically slower on my microbenchmark
      than the others. Using j2se/test/java/util/ArrayList/RangeCheckMicroBenchmark.java
      I get, e.g. on solaris-amd64:

      ==> javac -Xlint:all RangeCheckMicroBenchmark.java
      ==> java -server -esa -ea RangeCheckMicroBenchmark
      Method Millis Ratio
      get 53 1.000
      set 48 0.907
      get/set 188 3.487
      add/remove at end 1360 25.210

      vs.

      ==> javac -Xlint:all RangeCheckMicroBenchmark.java
      ==> java -server -esa -ea RangeCheckMicroBenchmark
      Method Millis Ratio
      get 180 1.000
      set 363 2.006
      get/set 514 2.844
      add/remove at end 1227 6.784

      Notice the up-to-factor-of-8 decrease in performance. A big penalty for
      just moving some code around.

      I'm not a hotspot engineer, but it looks like methods that unconditionally
      throw confuse the optimizer. But such methods are typical of attempts to
      move error handling into a separate method, and is effective at speeding
      up the client compiler, so users are likely to do this sort of thing.
      The server compiler needs to examine outOfBounds and understand that it throws,
      but not inline it. Maybe.

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              martin Martin Buchholz
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Imported:
                Indexed: