RFR: 8252505: C1/C2 compiler support for blackholes [v22]

Aleksey Shipilev shade at openjdk.java.net
Fri Dec 4 07:55:09 UTC 2020


> JMH uses the [`Blackhole::consume`](https://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-core/src/main/java/org/openjdk/jmh/infra/Blackhole.java#l153) methods to avoid dead-code elimination of the code that produces benchmark values. It now relies on producing opaque side-effects and breaking inlining. While it was proved useful for many years, it unfortunately comes with several major drawbacks:
>  
>   1. Call costs dominate nanobenchmarks. On TR 3970X, the call cost is several nanoseconds.
>   2. The work spent in Blackhole.consume dominates nanobenchmarks too. It takes about a nanosecond on TR 3970X.
>   3. Argument preparation for call makes different argument types behave differently. This is prominent on architectures where calling conventions for passing e.g. floating-point arguments require elaborate dance.
> 
> Supporting this directly in compilers would improve nanobenchmark fidelity.
> 
> Instead of introducing public APIs or special-casing JMH methods in JVM, we can hook a new command to compiler control, and let JMH sign up its Blackhole methods for it with `-XX:CompileCommand=blackhole,org.openjdk.jmh.infra.Blackhole::consume`. This is being prototyped as [CODETOOLS-7902762](https://bugs.openjdk.java.net/browse/CODETOOLS-7902762). It makes Blackholes behave [substantially better](http://cr.openjdk.java.net/~shade/8252505/bh-old-vs-new.png).
> 
> C1 code is platform-independent, and it handles blackhole via the intrinsics paths, lowering it to nothing.
> 
> C2 code is more complicated. There were four attempts to implement this, and what you see in the PR is the final attempt.
> 
> [First attempt](http://cr.openjdk.java.net/~shade/8252505/webrev.01/) was to introduce fake store like `StoreV` ("store void"), and then lower them to nothing. It runs into a series of funky problems: you would like to have at least two shapes of the store to match the store type width not to confuse the optimizer, or even have the whole mirror of `Store*` hierarchy. Additionally, optimizer tweaks were needed. The awkward problem of GC barrier verification showed up: if `StoreV*` is a subclass of `Store*`, then verificators rightfully expect GC barriers before them. If we emit GC, then we need to handle walking over `StoreV*` nodes in optimizers. 
> 
> [Second attempt](http://cr.openjdk.java.net/~shade/8252505/webrev.04/) was to introduce the special `Blackhole` node that consumes the values -- basically like C1 implementation does it. Alas, the many attempts to make sure the new node is not DCE'd failed. Roland looked at it, and suggested that there seems to be no way to model the effects we are after: consume the value, but have no observable side effects. So, suggested we instead put the boolean flag onto `CallJavaNode`, and then match it to nothing in `.ad`. 
> 
> ...which is the essence of the third attempt. Drag the blackhole through C2 as if it has call-like side effects, and then emit nothing. Instead of boolean flag, the subsequent iteration introduced a full new `CallBlackhole` node, that is a call as far as optimizers are concerned, and then it is matched to nothing in `.ad`. 
> 
> The fourth, and hopefully final attempt is in this PR. It makes the `Blackhole` the subclass of `MemBar`, and use the same `Matcher` path as `Op_MemCPUOrder`: it does not match to anything, but it survives until matching, and keeps arguments alive. Additionally, C1 and C2 hooks are now using the synthetic `_blackhole` intrinsic, similarly to existing `_compiledLambdaForm`. It avoids introducing new nodes in C1. It also seems to require the least fiddling with C2 internals.

Aleksey Shipilev has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains 39 commits:

 - Cleanup LibraryCallKit::inline_blackhole
 - Simplify tests
 - Merge branch 'master' into JDK-8252505-blackholes
 - Fix C2 _blackhole: polls arguments count from caller, not callee
 - Print warning on non-void blackhole methods
 - Fix release build
 - Merge branch 'master' into JDK-8252505-blackholes
 - Handle null-checks in intrinsics to maintain the semantics
 - Blackhole takes precedence over all other intrinsics
 - Print Blackhole format
 - ... and 29 more: https://git.openjdk.java.net/jdk/compare/d08c612b...64962bc3

-------------

Changes: https://git.openjdk.java.net/jdk/pull/1203/files
 Webrev: https://webrevs.openjdk.java.net/?repo=jdk&pr=1203&range=21
  Stats: 1503 lines in 30 files changed: 1501 ins; 0 del; 2 mod
  Patch: https://git.openjdk.java.net/jdk/pull/1203.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/1203/head:pull/1203

PR: https://git.openjdk.java.net/jdk/pull/1203


More information about the hotspot-dev mailing list