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

C1/C2 compiler support for blackholes



    • CSR
    • Resolution: Withdrawn
    • P4
    • 16
    • hotspot
    • None
    • behavioral
    • minimal
    • add/remove/modify command line option


      (This is the retroactive CSR request, after the post-integration questions raised about it. Neither me or reviewers anticipated them at the time of review. Apologies for not catching that earlier. We can still change the implementation if CSR questions need to be resolved. See the start of discussion here: https://github.com/openjdk/jdk/pull/1203#issuecomment-739577111)


      Add a special support for so called "blackholes", the methods that are specially treated as having one special effect, and one effect only: keeping the arguments alive. This is important for the reliable and precise nano-benchmarking. Blackholes are defined with explicit HotSpot JVM flag -XX:CompileCommand=blackhole,<method>.


      The ability to avoid dead-code elimination is critical for benchmarking. JMH achieves this by providing a Java-based Blackhole.consume method. It unfortunately comes with several major performance drawbacks: call costs dominate nanobenchmarks, the work spent in Blackhole.consume dominates nanobenchmarks too, argument preparation for call makes different argument types behave differently. Compiler support for Blackholes is very useful for nano-benchmarks, as demonstrated by the experiments.


      Current C1/C2 JIT compilers implementation is able to receive the "blackhole" command from the user, and inline the method with removing its body, but keeping the incoming arguments alive. The CSR-related question is how to communicate that command to JVM.

      Current implementation reuses the CompilerOracle facilities, available via -XX:CompileCommand HotSpot JVM flag. This eliminates the need to specify the public Java API, and also limits the accesibility/exposure of the new feature. JMH is able to use this feature by explicitly enabling it with -XX:CompileCommand=blackhole,org.openjdk.jmh.infra.Blackhole::consume. JMH already uses a lot of CompileCommands to ask for unusual things from the Hotspot JVMs, like inline/dontinlne/exclude, etc.

      The upside of exposing the functionality as a command-line option is it has much lower level of commitment associated with it. If there's enough motivation/justification to graduate it into public Java API, it can be done later when there's enough confidence that it's the right fit there. See the "Alternatives" for more discussion.

      This CSR comes from two points:

      1. CompileCommand is the product flag. Therefore, the change introduces a new behavior to the externally available product flag. Arguably, the spirit of the flag is diagnostic/experimental, but it's "letter" is product, due to historical reasons. [This is resolved by adopting Alternative 1, JDK-8257848]

      2. -XX:CompileCommand=blackhole,<method> changes the semantics of the target method by eliminating its body. The only other -XX:CompileCommand=* that does intrusive changes like this is BreakAt, which stops execution at method entry. This looks like low risk, as -XX:CompileCommand is the low-level compiler request, and we should expect users know what they are doing when requesting it (likewise for BreakAt). Similarly, the user controlling the HotSpot JVM invocation line can Xbootclasspath/patch-module the code out with similar semantics changing effects. [This can be resolved by adopting Alternative 2, JDK-8258619]


      Alternative 1. [Adopted with JDK-8257848]. Require -XX:+UnlockDiagnosticVMOptions when using -XX:CompileCommand=blackhole,<method>. I believe it would make the change under discussion "experimental", and thus it would fall out of scope for CSR. It would require minimal adjustments to VM implementation, VM tests, JMH-side support.

      Alternative 2. [Prototyped as JDK-8258619]. Limit "blackholing" to the empty methods. Empty methods have no expected side effects, thus method body is not "eliminated", and there is no direct behavioral change. It is still a performance change in the sense that non-blackholed empty method can still be inlined and its inputs dead-code eliminated. However, this comes with major drawbacks in testing, as figuring out the method is indeed blackholed is much harder without directly observable elimination effects -- current jtreg tests assert blackholing works by testing method body is gone. Plus, it has the major drawback in JMH, where using such VM facility would require significant re-engineering of Blackhole support in JMH itself, probably introducing much more intrusive JDK-specific hacks and risks introducing methodological bugs in already intricate code in JMH.

      Alternative 3. Remove additions to -XX:CompileCommand, and instead intrinsify the JMH methods directly. Unfortunately, this goes against the formal requirement that JVM only intrinsifies the "trusted" code from within the JDK, and thus intrinsifying 3rd-party code is unlikely to be accepted by VM teams. That said, this is the strategy that Graal uses today: https://github.com/oracle/graal/blob/744654c108178d531c99fc802f451b55b72a48c9/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java#L1492.

      Alternative 4. Introduce Unsafe.blackhole methods, and intrinsify them. Unfortunately, benchmark harnesses like JMH are the 3rd party code as far as JDK is concerned, which means using them requires linking to either sun.misc.Unsafe (which would extend the surface of "public" Unsafe, that we are unwilling to do), or jdk.internal.vm.Unsafe (which would require breaking in with elevated module system privileges).

      Alternative 5. Introduce blackhole methods in Whitebox API. Unfortunately, the experience with Whitebox API in jcstress (which uses it to gain access for deoptimization) tells that linking against frequently changing Whitebox is very tedious -- the interface there is too fluid. Additionally, this would require intrinsifying the Whitebox methods themselves, which again raises the question about intrinsifying the methods formally outside of JDK (while there are native methods defined in JVM in ./src/hotspot/share/prims/whitebox.cpp, Whitebox Java entries are in ./test/lib/sun/hotspot/WhiteBox.java).

      Alternative 6. Introduce public methods in the platform APIs. As stated in the Solution, this does not look appealing at this phase in compiler support work. Not overexposing the blackhole support allows wider testing with JMH, while retaining the right to retract it at any time if problems show up. Rushing to introduce the public API at this point would risk introducing the problematic API before understanding all the problems with its implementation.


      There is no formal specification for -XX:CompileCommand option, the change adds new sub-behavior in product macro-flag.


        Issue Links



              shade Aleksey Shipilev
              shade Aleksey Shipilev
              Volker Simonis
              0 Vote for this issue
              9 Start watching this issue