RFR: 8324241: Always record evol_method deps to avoid excessive method flushing [v4]

Aleksey Shipilev shade at openjdk.org
Fri Jan 26 09:48:31 UTC 2024


On Wed, 24 Jan 2024 14:48:52 GMT, Volker Simonis <simonis at openjdk.org> wrote:

>> Currently we don't record dependencies on redefined methods (i.e. `evol_method` dependencies) in JIT compiled methods if none of the `can_redefine_classes`, `can_retransform_classes` or `can_generate_breakpoint_events` JVMTI capabalities is set. This means that if a JVMTI agent which requests one of these capabilities is dynamically attached, all the methods which have been JIT compiled until that point, will be marked for deoptimization and flushed from the code cache. For large, warmed-up applications this mean deoptimization and instant recompilation of thousands if not then-thousands of methods, which can lead to dramatic performance/latency drop-downs for several minutes.
>> 
>> One could argue that dynamic agent attach is now deprecated anyway (see [JEP 451: Prepare to Disallow the Dynamic Loading of Agents](https://openjdk.org/jeps/451)) and this problem could be solved by making the recording of `evol_method` dependencies dependent on the new `-XX:+EnableDynamicAgentLoading` flag isntead of the concrete JVMTI capabilities (because the presence of the flag indicates that an agent will be loaded eventually).
>> 
>> But there a single, however important exception to this rule and that's JFR. JFR is advertised as low overhead profiler which can be enabled in production at any time. However, when JFR is started dynamically (e.g. through JCMD or JMX) it will silently load a HotSpot internl JVMTI agent which requests the `can_retransform_classes` and retransforms some classes. This will inevitably trigger the deoptimization of all compiled methods as described above.
>> 
>> I'd therefor like to propose to *always* and unconditionally record `evol_method` dependencies in JIT compiled code by exporting the relevant properties right at startup in `init_globals()`:
>> ```c++
>>  jint init_globals() {
>>    management_init();
>>    JvmtiExport::initialize_oop_storage();
>> +#if INCLUDE_JVMTI
>> +  JvmtiExport::set_can_hotswap_or_post_breakpoint(true);
>> +  JvmtiExport::set_all_dependencies_are_recorded(true);
>> +#endif
>> 
>> 
>> My measurements indicate that the overhead of doing so is minimal (around 1% increase of nmethod size) and justifies the benefit. E.g. a Spring Petclinic application started with `-Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation` compiles about ~11500 methods (~9000 with C1 and ~2500 with C2) resulting in an aggregated nmethod size of around ~40bm. Additionally recording `evol_method` dependencies only increases this size be about 400kb....
>
> Volker Simonis has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Made the flag experimental and added an assertion to set_can_hotswap_or_post_breakpoint()

I am good with these changes, only a few stylistic nits.

I am on the fence where the default for this flag should stand. The 1% loss in nmethod size is probably okay, given that we gained as much with denser code improvements like [JDK-8319406](https://bugs.openjdk.org/browse/JDK-8319406). Maybe there are some tricks in dependency encoding that would drive this down even more.

src/hotspot/share/prims/jvmtiExport.hpp line 159:

> 157:     // recorded from that point on.
> 158:     assert(!_can_hotswap_or_post_breakpoint || on, "sanity check");
> 159:     _can_hotswap_or_post_breakpoint = (on != 0);

Pre-existing: wild that this code checks `!= 0` against `bool`, when it could have just used the bool directly, like the new assert does. I see no reason to keep `!= 0` here.

src/hotspot/share/runtime/globals.hpp line 2016:

> 2014:                 "Unconditionally record nmethod dependencies on class "     \
> 2015:                 "rewriting/transformation independently of the JVMTI "      \
> 2016:                 " can_{retransform/redefine}_classes capabilities.")        \

Probably match the indenting of previous delcarations?

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

Marked as reviewed by shade (Reviewer).

PR Review: https://git.openjdk.org/jdk/pull/17509#pullrequestreview-1845365087
PR Review Comment: https://git.openjdk.org/jdk/pull/17509#discussion_r1467418701
PR Review Comment: https://git.openjdk.org/jdk/pull/17509#discussion_r1467415176


More information about the hotspot-compiler-dev mailing list