Skip to content

Commit 977200a

Browse files
author
Y. Srinivas Ramakrishna
committedAug 26, 2024
8338780: GenShen: Fix up some comments
Reviewed-by: kdnilsen
1 parent 12af9f6 commit 977200a

File tree

4 files changed

+42
-80
lines changed

4 files changed

+42
-80
lines changed
 

‎src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp

+29-29
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
* questions.
2323
*
2424
*/
25-
#include "precompiled.hpp"
2625

26+
#include "precompiled.hpp"
2727

2828
#include "gc/shared/gcCause.hpp"
2929
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
@@ -205,6 +205,34 @@ static double saturate(double value, double min, double max) {
205205
return MAX2(MIN2(value, max), min);
206206
}
207207

208+
// Rationale:
209+
// The idea is that there is an average allocation rate and there are occasional abnormal bursts (or spikes) of
210+
// allocations that exceed the average allocation rate. What do these spikes look like?
211+
//
212+
// 1. At certain phase changes, we may discard large amounts of data and replace it with large numbers of newly
213+
// allocated objects. This "spike" looks more like a phase change. We were in steady state at M bytes/sec
214+
// allocation rate and now we're in a "reinitialization phase" that looks like N bytes/sec. We need the "spike"
215+
// accommodation to give us enough runway to recalibrate our "average allocation rate".
216+
//
217+
// 2. The typical workload changes. "Suddenly", our typical workload of N TPS increases to N+delta TPS. This means
218+
// our average allocation rate needs to be adjusted. Once again, we need the "spike" accomodation to give us
219+
// enough runway to recalibrate our "average allocation rate".
220+
//
221+
// 3. Though there is an "average" allocation rate, a given workload's demand for allocation may be very bursty. We
222+
// allocate a bunch of LABs during the 5 ms that follow completion of a GC, then we perform no more allocations for
223+
// the next 150 ms. It seems we want the "spike" to represent the maximum divergence from average within the
224+
// period of time between consecutive evaluation of the should_start_gc() service. Here's the thinking:
225+
//
226+
// a) Between now and the next time I ask whether should_start_gc(), we might experience a spike representing
227+
// the anticipated burst of allocations. If that would put us over budget, then we should start GC immediately.
228+
// b) Between now and the anticipated depletion of allocation pool, there may be two or more bursts of allocations.
229+
// If there are more than one of these bursts, we can "approximate" that these will be separated by spans of
230+
// time with very little or no allocations so the "average" allocation rate should be a suitable approximation
231+
// of how this will behave.
232+
//
233+
// For cases 1 and 2, we need to "quickly" recalibrate the average allocation rate whenever we detect a change
234+
// in operation mode. We want some way to decide that the average rate has changed, while keeping average
235+
// allocation rate computation independent.
208236
bool ShenandoahAdaptiveHeuristics::should_start_gc() {
209237
size_t capacity = _space_info->soft_max_capacity();
210238
size_t available = _space_info->soft_available();
@@ -238,34 +266,6 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() {
238266
return true;
239267
}
240268
}
241-
// Rationale:
242-
// The idea is that there is an average allocation rate and there are occasional abnormal bursts (or spikes) of
243-
// allocations that exceed the average allocation rate. What do these spikes look like?
244-
//
245-
// 1. At certain phase changes, we may discard large amounts of data and replace it with large numbers of newly
246-
// allocated objects. This "spike" looks more like a phase change. We were in steady state at M bytes/sec
247-
// allocation rate and now we're in a "reinitialization phase" that looks like N bytes/sec. We need the "spike"
248-
// accommodation to give us enough runway to recalibrate our "average allocation rate".
249-
//
250-
// 2. The typical workload changes. "Suddenly", our typical workload of N TPS increases to N+delta TPS. This means
251-
// our average allocation rate needs to be adjusted. Once again, we need the "spike" accomodation to give us
252-
// enough runway to recalibrate our "average allocation rate".
253-
//
254-
// 3. Though there is an "average" allocation rate, a given workload's demand for allocation may be very bursty. We
255-
// allocate a bunch of LABs during the 5 ms that follow completion of a GC, then we perform no more allocations for
256-
// the next 150 ms. It seems we want the "spike" to represent the maximum divergence from average within the
257-
// period of time between consecutive evaluation of the should_start_gc() service. Here's the thinking:
258-
//
259-
// a) Between now and the next time I ask whether should_start_gc(), we might experience a spike representing
260-
// the anticipated burst of allocations. If that would put us over budget, then we should start GC immediately.
261-
// b) Between now and the anticipated depletion of allocation pool, there may be two or more bursts of allocations.
262-
// If there are more than one of these bursts, we can "approximate" that these will be separated by spans of
263-
// time with very little or no allocations so the "average" allocation rate should be a suitable approximation
264-
// of how this will behave.
265-
//
266-
// For cases 1 and 2, we need to "quickly" recalibrate the average allocation rate whenever we detect a change
267-
// in operation mode. We want some way to decide that the average rate has changed. Make average allocation rate
268-
// computations an independent effort.
269269
// Check if allocation headroom is still okay. This also factors in:
270270
// 1. Some space to absorb allocation spikes (ShenandoahAllocSpikeFactor)
271271
// 2. Accumulated penalties from Degenerated and Full GC

‎src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ class ShenandoahAdaptiveHeuristics : public ShenandoahHeuristics {
140140
// source of feedback to adjust trigger parameters.
141141
TruncatedSeq _available;
142142

143+
// A conservative minimum threshold of free space that we'll try to maintain when possible.
144+
// For example, we might trigger a concurrent gc if we are likely to drop below
145+
// this threshold, or we might consider this when dynamically resizing generations
146+
// in the generational case. Controlled by global flag ShenandoahMinFreeThreshold.
143147
size_t min_free_threshold();
144148
};
145149

‎src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp

+2-31
Original file line numberDiff line numberDiff line change
@@ -40,36 +40,10 @@ ShenandoahGlobalHeuristics::ShenandoahGlobalHeuristics(ShenandoahGlobalGeneratio
4040
void ShenandoahGlobalHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset,
4141
RegionData* data, size_t size,
4242
size_t actual_free) {
43-
// The logic for cset selection in adaptive is as follows:
44-
//
45-
// 1. We cannot get cset larger than available free space. Otherwise we guarantee OOME
46-
// during evacuation, and thus guarantee full GC. In practice, we also want to let
47-
// application to allocate something. This is why we limit CSet to some fraction of
48-
// available space. In non-overloaded heap, max_cset would contain all plausible candidates
49-
// over garbage threshold.
50-
//
51-
// 2. We should not get cset too low so that free threshold would not be met right
52-
// after the cycle. Otherwise we get back-to-back cycles for no reason if heap is
53-
// too fragmented. In non-overloaded non-fragmented heap min_garbage would be around zero.
54-
//
55-
// Therefore, we start by sorting the regions by garbage. Then we unconditionally add the best candidates
56-
// before we meet min_garbage. Then we add all candidates that fit with a garbage threshold before
57-
// we hit max_cset. When max_cset is hit, we terminate the cset selection. Note that in this scheme,
58-
// ShenandoahGarbageThreshold is the soft threshold which would be ignored until min_garbage is hit.
59-
60-
// In generational mode, the sort order within the data array is not strictly descending amounts of garbage. In
61-
// particular, regions that have reached tenure age will be sorted into this array before younger regions that contain
62-
// more garbage. This represents one of the reasons why we keep looking at regions even after we decide, for example,
63-
// to exclude one of the regions because it might require evacuation of too much live data.
64-
65-
66-
6743
// Better select garbage-first regions
6844
QuickSort::sort<RegionData>(data, (int) size, compare_by_garbage);
6945

70-
size_t cur_young_garbage = add_preselected_regions_to_collection_set(cset, data, size);
71-
72-
choose_global_collection_set(cset, data, size, actual_free, cur_young_garbage);
46+
choose_global_collection_set(cset, data, size, actual_free, 0 /* cur_young_garbage */);
7347

7448
log_cset_composition(cset);
7549
}
@@ -126,10 +100,7 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti
126100

127101
for (size_t idx = 0; idx < size; idx++) {
128102
ShenandoahHeapRegion* r = data[idx].get_region();
129-
if (cset->is_preselected(r->index())) {
130-
fatal("There should be no preselected regions during GLOBAL GC");
131-
continue;
132-
}
103+
assert(!cset->is_preselected(r->index()), "There should be no preselected regions during GLOBAL GC");
133104
bool add_region = false;
134105
if (r->is_old() || (r->age() >= tenuring_threshold)) {
135106
size_t new_cset = old_cur_cset + r->get_live_data_bytes();

‎src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp

+7-20
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,14 @@ ShenandoahYoungHeuristics::ShenandoahYoungHeuristics(ShenandoahYoungGeneration*
4242
void ShenandoahYoungHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset,
4343
RegionData* data, size_t size,
4444
size_t actual_free) {
45-
// The logic for cset selection in adaptive is as follows:
45+
// See comments in ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata():
46+
// we do the same here, but with the following adjustments for generational mode:
4647
//
47-
// 1. We cannot get cset larger than available free space. Otherwise we guarantee OOME
48-
// during evacuation, and thus guarantee full GC. In practice, we also want to let
49-
// application to allocate something. This is why we limit CSet to some fraction of
50-
// available space. In non-overloaded heap, max_cset would contain all plausible candidates
51-
// over garbage threshold.
52-
//
53-
// 2. We should not get cset too low so that free threshold would not be met right
54-
// after the cycle. Otherwise we get back-to-back cycles for no reason if heap is
55-
// too fragmented. In non-overloaded non-fragmented heap min_garbage would be around zero.
56-
//
57-
// Therefore, we start by sorting the regions by garbage. Then we unconditionally add the best candidates
58-
// before we meet min_garbage. Then we add all candidates that fit with a garbage threshold before
59-
// we hit max_cset. When max_cset is hit, we terminate the cset selection. Note that in this scheme,
60-
// ShenandoahGarbageThreshold is the soft threshold which would be ignored until min_garbage is hit.
61-
62-
// In generational mode, the sort order within the data array is not strictly descending amounts of garbage. In
63-
// particular, regions that have reached tenure age will be sorted into this array before younger regions that contain
64-
// more garbage. This represents one of the reasons why we keep looking at regions even after we decide, for example,
65-
// to exclude one of the regions because it might require evacuation of too much live data.
48+
// In generational mode, the sort order within the data array is not strictly descending amounts
49+
// of garbage. In particular, regions that have reached tenure age will be sorted into this
50+
// array before younger regions that typically contain more garbage. This is one reason why,
51+
// for example, we continue examining regions even after rejecting a region that has
52+
// more live data than we can evacuate.
6653

6754
// Better select garbage-first regions
6855
QuickSort::sort<RegionData>(data, (int) size, compare_by_garbage);

2 commit comments

Comments
 (2)

earthling-amzn commented on Sep 16, 2024

@earthling-amzn
Contributor

/backport shenandoah-jdk21u

openjdk[bot] commented on Sep 16, 2024

@openjdk[bot]

@earthling-amzn the backport was successfully created on the branch backport-earthling-amzn-977200a0-master in my personal fork of openjdk/shenandoah-jdk21u. To create a pull request with this backport targeting openjdk/shenandoah-jdk21u:master, just click the following link:

➡️ Create pull request

The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:

Hi all,

This pull request contains a backport of commit 977200a0 from the openjdk/shenandoah repository.

The commit being backported was authored by Y. Srinivas Ramakrishna on 26 Aug 2024 and was reviewed by Kelvin Nilsen.

Thanks!

If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/shenandoah-jdk21u:

$ git fetch https://github.com/openjdk-bots/shenandoah-jdk21u.git backport-earthling-amzn-977200a0-master:backport-earthling-amzn-977200a0-master
$ git checkout backport-earthling-amzn-977200a0-master
# make changes
$ git add paths/to/changed/files
$ git commit --message 'Describe additional changes made'
$ git push https://github.com/openjdk-bots/shenandoah-jdk21u.git backport-earthling-amzn-977200a0-master
Please sign in to comment.