Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8156071: List.of: reduce array copying during creation #449

Conversation

stuart-marks
Copy link
Member

@stuart-marks stuart-marks commented Oct 1, 2020

Plumb new internal static factory method to trust the array passed in, avoiding unnecessary copying. JMH results for the benchmark show about 15% improvement for the cases that were optimized, namely the 3 to 10 fixed arg cases.

# VM options: -verbose:gc -XX:+UseParallelGC -Xms4g -Xmx4g --enable-preview -verbose:gc -XX:+UsePara
llelGC -Xms4g -Xmx4g -Xint
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 2 s each

WITHOUT varargs optimization:

Benchmark Mode Cnt Score Error Units
ListArgs.list00 thrpt 15 6019.539 ± 144.040 ops/ms
ListArgs.list01 thrpt 15 1985.009 ± 40.606 ops/ms
ListArgs.list02 thrpt 15 1854.812 ± 17.488 ops/ms
ListArgs.list03 thrpt 15 963.866 ± 10.262 ops/ms
ListArgs.list04 thrpt 15 908.116 ± 6.278 ops/ms
ListArgs.list05 thrpt 15 848.607 ± 16.701 ops/ms
ListArgs.list06 thrpt 15 822.282 ± 8.905 ops/ms
ListArgs.list07 thrpt 15 780.057 ± 11.214 ops/ms
ListArgs.list08 thrpt 15 745.295 ± 19.204 ops/ms
ListArgs.list09 thrpt 15 704.596 ± 14.003 ops/ms
ListArgs.list10 thrpt 15 696.436 ± 4.914 ops/ms
ListArgs.list11 thrpt 15 661.908 ± 11.041 ops/ms

WITH varargs optimization:

Benchmark Mode Cnt Score Error Units
ListArgs.list00 thrpt 15 6172.298 ± 62.736 ops/ms
ListArgs.list01 thrpt 15 1987.724 ± 45.468 ops/ms
ListArgs.list02 thrpt 15 1843.419 ± 10.693 ops/ms
ListArgs.list03 thrpt 15 1126.946 ± 30.952 ops/ms
ListArgs.list04 thrpt 15 1050.440 ± 17.859 ops/ms
ListArgs.list05 thrpt 15 999.275 ± 23.656 ops/ms
ListArgs.list06 thrpt 15 948.844 ± 19.615 ops/ms
ListArgs.list07 thrpt 15 897.541 ± 15.531 ops/ms
ListArgs.list08 thrpt 15 853.359 ± 18.755 ops/ms
ListArgs.list09 thrpt 15 826.394 ± 8.284 ops/ms
ListArgs.list10 thrpt 15 779.231 ± 4.104 ops/ms
ListArgs.list11 thrpt 15 650.888 ± 3.948 ops/ms


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed

Issue

  • JDK-8156071: List.of: reduce array copying during creation

Reviewers

Download

$ git fetch https://git.openjdk.java.net/jdk pull/449/head:pull/449
$ git checkout pull/449

@bridgekeeper
Copy link

bridgekeeper bot commented Oct 1, 2020

👋 Welcome back smarks! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk openjdk bot added the rfr Pull request is ready for review label Oct 1, 2020
@openjdk
Copy link

openjdk bot commented Oct 1, 2020

@stuart-marks The following labels will be automatically applied to this pull request:

  • core-libs
  • security

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing lists. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added security security-dev@openjdk.org core-libs core-libs-dev@openjdk.org labels Oct 1, 2020
@mlbridge
Copy link

mlbridge bot commented Oct 1, 2020

Webrevs

@stuart-marks
Copy link
Member Author

stuart-marks commented Oct 2, 2020

After a hint from @cl4es I ran the benchmarks with -prof gc. The allocation rate is reduced by about 40% per operation in the cases where the optimization was applied.

WITHOUT varargs optimization:

ListArgs.list00:·gc.alloc.rate.norm thrpt 5 ≈ 10⁻⁴ B/op
ListArgs.list01:·gc.alloc.rate.norm thrpt 5 24.000 ± 0.001 B/op
ListArgs.list02:·gc.alloc.rate.norm thrpt 5 24.000 ± 0.001 B/op
ListArgs.list03:·gc.alloc.rate.norm thrpt 5 80.000 ± 0.001 B/op
ListArgs.list04:·gc.alloc.rate.norm thrpt 5 80.036 ± 0.309 B/op
ListArgs.list05:·gc.alloc.rate.norm thrpt 5 96.037 ± 0.316 B/op
ListArgs.list06:·gc.alloc.rate.norm thrpt 5 96.038 ± 0.326 B/op
ListArgs.list07:·gc.alloc.rate.norm thrpt 5 112.042 ± 0.361 B/op
ListArgs.list08:·gc.alloc.rate.norm thrpt 5 112.043 ± 0.367 B/op
ListArgs.list09:·gc.alloc.rate.norm thrpt 5 128.045 ± 0.385 B/op
ListArgs.list10:·gc.alloc.rate.norm thrpt 5 128.046 ± 0.391 B/op
ListArgs.list11:·gc.alloc.rate.norm thrpt 5 144.047 ± 0.406 B/op

WITH varargs optimization:

ListArgs.list00:·gc.alloc.rate.norm thrpt 5 ≈ 10⁻⁴ B/op
ListArgs.list01:·gc.alloc.rate.norm thrpt 5 24.000 ± 0.001 B/op
ListArgs.list02:·gc.alloc.rate.norm thrpt 5 24.000 ± 0.001 B/op
ListArgs.list03:·gc.alloc.rate.norm thrpt 5 48.000 ± 0.001 B/op
ListArgs.list04:·gc.alloc.rate.norm thrpt 5 48.000 ± 0.001 B/op
ListArgs.list05:·gc.alloc.rate.norm thrpt 5 56.000 ± 0.001 B/op
ListArgs.list06:·gc.alloc.rate.norm thrpt 5 56.000 ± 0.001 B/op
ListArgs.list07:·gc.alloc.rate.norm thrpt 5 64.000 ± 0.001 B/op
ListArgs.list08:·gc.alloc.rate.norm thrpt 5 64.000 ± 0.001 B/op
ListArgs.list09:·gc.alloc.rate.norm thrpt 5 72.000 ± 0.001 B/op
ListArgs.list10:·gc.alloc.rate.norm thrpt 5 72.000 ± 0.001 B/op
ListArgs.list11:·gc.alloc.rate.norm thrpt 5 144.050 ± 0.427 B/op

Copy link
Member

@PaulSandoz PaulSandoz left a comment

Looks good, i wondered why the performance results were so slow then i looked more closely and saw "-Xint" was used. I usually don't ascribe much value to micro benchmarks run in interpreter only mode, but hey any shaving off startup time is welcome. Less allocation is definitely welcome (although i do wish C2 was better at eliding redundant array initialization and allocation).

@openjdk
Copy link

openjdk bot commented Oct 2, 2020

@stuart-marks This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for more details.

After integration, the commit message for the final commit will be:

8156071: List.of: reduce array copying during creation

Reviewed-by: psandoz, redestad

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 56 new commits pushed to the master branch:

  • ea27a54: 8224509: Incorrect alignment in CDS related allocation code on 32-bit platforms
  • 4d29116: 8253433: Remove -XX:+Debugging product option
  • 81dae70: 8253948: Memory leak in ImageFileReader
  • 65cab55: 8253971: ZGC: Flush mark stacks after processing concurrent roots
  • 19219a9: 8253960: Memory leak in Java_java_lang_ClassLoader_defineClass0()
  • 5d4a135: 8253842: [JVMCI] Allow implicit exception to dispatch to other address in jvmci compilers.
  • 289ae79: 8252998: ModuleWrapper.gmk doesn't consult include path
  • 9604ee8: 8248238: Implementation: JEP 388: Windows AArch64 Support
  • 1c2754b: 8253269: The CheckCommonColors test should provide more info on failure
  • d296708: 8253606: Need to add missed constructor to the SwingEventMonitor
  • ... and 46 more: https://git.openjdk.java.net/jdk/compare/e5ba020ee9212a61004cf41492fc96518139f7ae...master

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Oct 2, 2020
@stuart-marks
Copy link
Member Author

stuart-marks commented Oct 5, 2020

/reviewer credit redestad

@openjdk
Copy link

openjdk bot commented Oct 5, 2020

@stuart-marks
Reviewer redestad successfully credited.

@stuart-marks
Copy link
Member Author

stuart-marks commented Oct 5, 2020

/integrate

@openjdk openjdk bot closed this Oct 5, 2020
@openjdk openjdk bot added integrated Pull request has been integrated and removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Oct 5, 2020
@openjdk
Copy link

openjdk bot commented Oct 5, 2020

@stuart-marks Since your change was applied there have been 56 commits pushed to the master branch:

  • ea27a54: 8224509: Incorrect alignment in CDS related allocation code on 32-bit platforms
  • 4d29116: 8253433: Remove -XX:+Debugging product option
  • 81dae70: 8253948: Memory leak in ImageFileReader
  • 65cab55: 8253971: ZGC: Flush mark stacks after processing concurrent roots
  • 19219a9: 8253960: Memory leak in Java_java_lang_ClassLoader_defineClass0()
  • 5d4a135: 8253842: [JVMCI] Allow implicit exception to dispatch to other address in jvmci compilers.
  • 289ae79: 8252998: ModuleWrapper.gmk doesn't consult include path
  • 9604ee8: 8248238: Implementation: JEP 388: Windows AArch64 Support
  • 1c2754b: 8253269: The CheckCommonColors test should provide more info on failure
  • d296708: 8253606: Need to add missed constructor to the SwingEventMonitor
  • ... and 46 more: https://git.openjdk.java.net/jdk/compare/e5ba020ee9212a61004cf41492fc96518139f7ae...master

Your commit was automatically rebased without conflicts.

Pushed as commit 88d75c9.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@amaembo
Copy link
Contributor

amaembo commented Oct 6, 2020

Sorry to be late to the party. I thought that all reviews labeled with core-libs should be mirrored to core-libs-dev mailing list but I haven't seen it there :(

Please note that the integrated implementation exposes listFromTrustedArray to everybody. No dirty unsafe reflection is necessary, only single unchecked cast:

  static <T> List<T> untrustedArrayToList(T[] array) {
    @SuppressWarnings("unchecked")
    Function<List<T>, List<T>> finisher = 
        (Function<List<T>, List<T>>) Collectors.<T>toUnmodifiableList().finisher();
    ArrayList<T> list = new ArrayList<>() {
      @Override
      public Object[] toArray() {
        return array;
      }
    };
    return finisher.apply(list);
  }

This might be qualified as a security issue.

@amaembo
Copy link
Contributor

amaembo commented Oct 6, 2020

This could be fixed by adding a classword check to the finisher, like this:

                                   list -> {
                                        if (list.getClass() != ArrayList.class) {
                                            throw new IllegalArgumentException();
                                        }
                                        return (List<T>) SharedSecrets.getJavaUtilCollectionAccess()
                                           .listFromTrustedArray(list.toArray());
                                   },

@stuart-marks
Copy link
Member Author

stuart-marks commented Oct 6, 2020

Thanks for pointing this out. I've filed bug JDK-8254090. I think we're ok as long as this gets fixed before JDK 16 ships.

I think the notification messages for this did end up on core-libs-dev, but perhaps there were some email delays over the weekend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-libs core-libs-dev@openjdk.org integrated Pull request has been integrated security security-dev@openjdk.org
4 participants