Skip to content

Commit 75f8e49

Browse files
author
William Kemper
committed
8338780: GenShen: Fix up some comments
Backport-of: 977200a0c073e90754f56730477d0fa32fd7ec9a
1 parent 2a1b731 commit 75f8e49

File tree

4 files changed

+42
-80
lines changed

4 files changed

+42
-80
lines changed

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

Lines changed: 29 additions & 29 deletions
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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 2 additions & 31 deletions
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, false);
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

Lines changed: 7 additions & 20 deletions
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, false);

0 commit comments

Comments
 (0)