8372543: Shenandoah: undercalculated the available size when soft max takes effect#28622
8372543: Shenandoah: undercalculated the available size when soft max takes effect#28622rgithubli wants to merge 5 commits intoopenjdk:masterfrom
Conversation
|
👋 Welcome back rgithubli! A progress list of the required criteria for merging this PR into |
|
@rgithubli 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 details. After integration, the commit message for the final commit will be: 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 207 new commits pushed to the
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. As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@earthling-amzn, @kdnilsen) but any other Committer may sponsor as well. ➡️ To flag this PR as ready for integration with the above commit message, type |
|
@rgithubli The following labels will be automatically applied to this pull request:
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. |
Webrevs
|
earthling-amzn
left a comment
There was a problem hiding this comment.
A few nits. Thank you for adding a test case for this!
src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp
Outdated
Show resolved
Hide resolved
| size_t min_threshold = min_free_threshold(); | ||
| if (available < min_threshold) { | ||
| log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)", | ||
| log_trigger("Free (Soft mutator free) (%zu%s) is below minimum threshold (%zu%s)", |
There was a problem hiding this comment.
Changing this will break some log parsers, do we really need this?
There was a problem hiding this comment.
Talked offline. Free is overloaded in logs. Sometimes it means soft free, sometimes it means total free. Make it as Free (Soft) here.
src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
Outdated
Show resolved
Hide resolved
| assert(max_capacity() >= ShenandoahHeap::heap()->soft_max_capacity(), "Max capacity must be greater than soft max capacity."); | ||
| size_t soft_tail = max_capacity() - ShenandoahHeap::heap()->soft_max_capacity(); | ||
| return (available > soft_tail) ? (available - soft_tail) : 0; | ||
| size_t ShenandoahGlobalGeneration::soft_available_exclude_evac_reserve() const { |
There was a problem hiding this comment.
Two questions:
- How is this override different from the default implementation now?
- Should we not also take the minimum of this value and
free_set()->available()as we do elsewhere?
There was a problem hiding this comment.
- Good call. No functional differences except for a safety assert:
assert(max_capacity() >= soft_max, which isn't that necessary since the app wouldn't start if this wasn't true: code. Will remove the override. - I don't think it's needed for global.
free_set()->available()(space reserved for mutators) could be smaller thanmutator_soft_maxwhen there's an old gen taking space. If there's no generation, themutator_soft_maxshould always be less or equal thanfree_set()->available().
| size_t ShenandoahGeneration::soft_available() const { | ||
| size_t result = available(ShenandoahHeap::heap()->soft_max_capacity()); | ||
| size_t ShenandoahGeneration::soft_available_exclude_evac_reserve() const { | ||
| size_t result = available(ShenandoahHeap::heap()->soft_max_capacity() * (100.0 - ShenandoahEvacReserve) / 100); |
There was a problem hiding this comment.
I'm a little uncomfortable with this approach. It's mostly a question of how we name it. The evac reserve is not always this value. In particular, we may shrink the young evac reserves after we have selected the cset. Also of concern is that if someone invokes this function on old_generation(), it looks like they'll get a bogus (not meaningful) value.
I think I'd be more comfortable with naming this to something like "mutator_available_when_gc_is_idle()". If we keep it virtual, then OldGeneration should override with "assert(false, "Not relevant to old generation")
There was a problem hiding this comment.
Talked offline. Rename this to soft_mutator_available
| size_t min_threshold = min_free_threshold(); | ||
| if (available < min_threshold) { | ||
| log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)", | ||
| log_trigger("Free (Soft) (%zu%s) is below minimum threshold (%zu%s)", |
There was a problem hiding this comment.
Forgot to use log format macros PROPERFMT & PROPERFMTARGS here. Will update.
| size_t ShenandoahGeneration::soft_available() const { | ||
| size_t result = available(ShenandoahHeap::heap()->soft_max_capacity()); | ||
| size_t ShenandoahGeneration::soft_available_exclude_evac_reserve() const { | ||
| size_t result = available(ShenandoahHeap::heap()->soft_max_capacity() * (100.0 - ShenandoahEvacReserve) / 100); |
|
/integrate |
|
@rgithubli |
|
Looks good, thanks! /sponsor |
|
Going to push as commit b1e8c4e.
Your commit was automatically rebased without conflicts. |
|
@pengxiaolong @rgithubli Pushed as commit b1e8c4e. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
Detailed math and repro see https://bugs.openjdk.org/browse/JDK-8372543.
Currently in shenandoah, when deciding whether to have gc, how we calculate available size is:
The if condition
available - soft_tailwill be reduced to:-(ShenandoahEvacReserve/100) * Xmx - used + soft_max, which means when soft max is the same, the larger Xmx is, the less free size the app would have and the more gc it would have, which does not make sense, especially for the case where the app is mostly idle. This caused one of our internal customers experienced frequent gc with minimal workload, when soft max heap size was set way lower than Xmx.Suggested fix: when deciding when to trigger gc, use logic similar to below:
Tests:
StableLiveSet.javain https://bugs.openjdk.org/browse/JDK-8372543. Without fix, tip had ~2910 times gc in 20 sec with-XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive -XX:SoftMaxHeapSize=512m -Xmx31gjvm args. With the fix, only 18 times in 20 sec.This change also improved gc logging:
Before:
After:
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/28622/head:pull/28622$ git checkout pull/28622Update a local copy of the PR:
$ git checkout pull/28622$ git pull https://git.openjdk.org/jdk.git pull/28622/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 28622View PR using the GUI difftool:
$ git pr show -t 28622Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/28622.diff
Using Webrev
Link to Webrev Comment