RFR: 8314599: [GenShen] Couple adaptive tenuring and generation size budgeting [v3]
Kelvin Nilsen
kdnilsen at openjdk.org
Mon Oct 6 23:19:50 UTC 2025
On Mon, 6 Oct 2025 15:36:59 GMT, William Kemper <wkemper at openjdk.org> wrote:
>> Notable changes:
>> * Improvements to logging
>> * More accurate tracking of promotion failures
>> * Use shared allocation for promotions only when the size is above the maximum plab size (not the minimum size)
>> * Use census information gathered during mark to size promotion reserves and old generation
>>
>> With these changes, GenShen is expected to have fewer promotion failures and this is indeed the case. As a result of this, we expect less time to be spent in concurrent marking and update refs for young collections. We may also expect shorter concurrent evacuation phases because GenShen will have fewer densely packed regions stuck in the young generation. With more objects being promoted, we also expect to see longer remembered set scan times. This is generally the case across all benchmarks, but we do also see some counter-intuitive results.
>>
>> Here we are comparing 20 executions (10 on x86, 10 on aarch64) of the changes in the PR (experiment) against 20 executions of the same benchmarks results from tip. This is a summary of statistically significant changes of more than 5% across all benchmarks:
>>
>>
>> Concurrent Evacuation: 7 improvements, 3 regressions
>> • Best improvements: extremem-large-45g (-29.6%), neo4j-analytics (-26.9%)
>> • Worst regression: xalan (+53.7%)
>>
>> Concurrent Marking: 15 improvements, 1 regression
>> • Best improvements: hyperalloc_a2048_o4096 (-30.1%), crypto.rsa (-27.3%)
>> • Only regression: serial (+8.9%)
>>
>> Concurrent Scan Remembered Set: 7 improvements, 2 regressions
>> • Best improvements: xalan (-49.4%), pmd (-49.0%), crypto.rsa (-41.8%)
>> • Worst regression: extremem-phased (+52.4%)
>>
>> Concurrent Update Refs: 5 improvements, 4 regressions
>> • Best improvements: crypto.rsa (-36.4%), mnemonics (-28.4%)
>> • Worst regression: xalan (+89.4%)
>
> William Kemper has updated the pull request incrementally with one additional commit since the last revision:
>
> Fix windows build more
I'm thinking that there should be a change to heap->rebuild_freeset() that adds get_promotion_potential() to the reserve for OldCollector. We did not previously make this reserve because we were only counting data that was to be promoted in place.
This may have the effect of triggering a bit sooner than in existing master. We could subtract out the pip_promo_reserve() if we want to keep track of that separately, because that doesn't need to be reserved.
Once the cset is constructed, we will shrink the reserves because at that point, we'll know better how much we really plan to evacuate into old.
src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp line 62:
> 60:
> 61: size_t ShenandoahCollectionSet::get_live_bytes_in_young_regions() const {
> 62: return _young_bytes_to_evacuate - _young_bytes_to_promote;
I'm wondering if these new names properly reflect the intention. It seems get_live_byte_in_young_regions() really means get_live_bytes_that_we_intend_to_evacuate_to_young(). (This number does not include _live_bytes_in_young_regions() that we expect to evacuate to old.)
src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp line 294:
> 292: // We have to be careful in the event that SOEP is set to 100 by the user.
> 293: assert(ShenandoahOldEvacRatioPercent <= 100, "Error");
> 294: const size_t ratio_of_old_in_collection_set = (maximum_young_evacuation_reserve * ShenandoahOldEvacRatioPercent) / (100 - ShenandoahOldEvacRatioPercent);
It looks like we may get divide-by-zero in the above of ShenandoahOldEvacRatioPercent equals 100
src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp line 481:
> 479: // promotions than fit in reserved memory, they will be deferred until a future GC pass.
> 480: size_t total_promotion_reserve = young_advance_promoted_reserve_used + excess_old;
> 481: old_generation->set_promoted_reserve(total_promotion_reserve);
Can you clarify why we no longer need this set_promoted_reserve() call? (just in a PR comment probably, not necessarily a code comment.)
src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp line 305:
> 303: }
> 304: // else, we leave copy equal to nullptr, signaling a promotion failure below if appropriate.
> 305: // We choose not to promote objects smaller than PLAB::min_size() by way of shared allocations, as this is too
I think this comment describes original behavior. With new behavior, comment should say PLAB::max_size()
-------------
PR Review: https://git.openjdk.org/jdk/pull/27632#pullrequestreview-3307715360
PR Review Comment: https://git.openjdk.org/jdk/pull/27632#discussion_r2408855784
PR Review Comment: https://git.openjdk.org/jdk/pull/27632#discussion_r2408865186
PR Review Comment: https://git.openjdk.org/jdk/pull/27632#discussion_r2408949510
PR Review Comment: https://git.openjdk.org/jdk/pull/27632#discussion_r2408922323
More information about the hotspot-gc-dev
mailing list