Skip to content

Commit 3832240

Browse files
committed
8348594: Shenandoah: Do not penalize for degeneration when not the fault of triggering heuristic
Reviewed-by: phh, wkemper
1 parent 2a90b90 commit 3832240

12 files changed

+82
-4
lines changed

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() {
240240
log_debug(gc)("should_start_gc? available: %zu, soft_max_capacity: %zu"
241241
", allocated: %zu", available, capacity, allocated);
242242

243+
if (_start_gc_is_pending) {
244+
return true;
245+
}
246+
243247
// Track allocation rate even if we decide to start a cycle for other reasons.
244248
double rate = _allocation_rate.sample(allocated);
245249
_last_trigger = OTHER;
@@ -249,6 +253,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() {
249253
log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)",
250254
byte_size_in_proper_unit(available), proper_unit_for_byte_size(available),
251255
byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold));
256+
accept_trigger_with_type(OTHER);
252257
return true;
253258
}
254259

@@ -261,6 +266,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() {
261266
_gc_times_learned + 1, max_learn,
262267
byte_size_in_proper_unit(available), proper_unit_for_byte_size(available),
263268
byte_size_in_proper_unit(init_threshold), proper_unit_for_byte_size(init_threshold));
269+
accept_trigger_with_type(OTHER);
264270
return true;
265271
}
266272
}
@@ -292,7 +298,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() {
292298
byte_size_in_proper_unit(spike_headroom), proper_unit_for_byte_size(spike_headroom),
293299
byte_size_in_proper_unit(penalties), proper_unit_for_byte_size(penalties),
294300
byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom));
295-
_last_trigger = RATE;
301+
accept_trigger_with_type(RATE);
296302
return true;
297303
}
298304

@@ -303,11 +309,16 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() {
303309
byte_size_in_proper_unit(rate), proper_unit_for_byte_size(rate),
304310
byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom),
305311
_spike_threshold_sd);
306-
_last_trigger = SPIKE;
312+
accept_trigger_with_type(SPIKE);
307313
return true;
308314
}
309315

310-
return ShenandoahHeuristics::should_start_gc();
316+
if (ShenandoahHeuristics::should_start_gc()) {
317+
_start_gc_is_pending = true;
318+
return true;
319+
} else {
320+
return false;
321+
}
311322
}
312323

313324
void ShenandoahAdaptiveHeuristics::adjust_last_trigger_parameters(double amount) {

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ class ShenandoahAdaptiveHeuristics : public ShenandoahHeuristics {
145145
// this threshold, or we might consider this when dynamically resizing generations
146146
// in the generational case. Controlled by global flag ShenandoahMinFreeThreshold.
147147
size_t min_free_threshold();
148+
149+
inline void accept_trigger_with_type(Trigger trigger_type) {
150+
_last_trigger = trigger_type;
151+
ShenandoahHeuristics::accept_trigger();
152+
}
148153
};
149154

150155
#endif // SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHADAPTIVEHEURISTICS_HPP

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void ShenandoahAggressiveHeuristics::choose_collection_set_from_regiondata(Shena
5252

5353
bool ShenandoahAggressiveHeuristics::should_start_gc() {
5454
log_trigger("Start next cycle immediately");
55+
accept_trigger();
5556
return true;
5657
}
5758

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ bool ShenandoahCompactHeuristics::should_start_gc() {
6161
log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)",
6262
byte_size_in_proper_unit(available), proper_unit_for_byte_size(available),
6363
byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold));
64+
accept_trigger();
6465
return true;
6566
}
6667

@@ -69,6 +70,7 @@ bool ShenandoahCompactHeuristics::should_start_gc() {
6970
log_trigger("Allocated since last cycle (%zu%s) is larger than allocation threshold (%zu%s)",
7071
byte_size_in_proper_unit(bytes_allocated), proper_unit_for_byte_size(bytes_allocated),
7172
byte_size_in_proper_unit(threshold_bytes_allocated), proper_unit_for_byte_size(threshold_bytes_allocated));
73+
accept_trigger();
7274
return true;
7375
}
7476

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ int ShenandoahHeuristics::compare_by_garbage(RegionData a, RegionData b) {
4646
}
4747

4848
ShenandoahHeuristics::ShenandoahHeuristics(ShenandoahSpaceInfo* space_info) :
49+
_start_gc_is_pending(false),
50+
_declined_trigger_count(0),
51+
_most_recent_declined_trigger_count(0),
4952
_space_info(space_info),
5053
_region_data(nullptr),
5154
_guaranteed_gc_interval(0),
@@ -184,10 +187,14 @@ void ShenandoahHeuristics::record_cycle_end() {
184187
}
185188

186189
bool ShenandoahHeuristics::should_start_gc() {
190+
if (_start_gc_is_pending) {
191+
return true;
192+
}
187193
// Perform GC to cleanup metaspace
188194
if (has_metaspace_oom()) {
189195
// Some of vmTestbase/metaspace tests depend on following line to count GC cycles
190196
log_trigger("%s", GCCause::to_string(GCCause::_metadata_GC_threshold));
197+
accept_trigger();
191198
return true;
192199
}
193200

@@ -196,10 +203,11 @@ bool ShenandoahHeuristics::should_start_gc() {
196203
if (last_time_ms > _guaranteed_gc_interval) {
197204
log_trigger("Time since last GC (%.0f ms) is larger than guaranteed interval (%zu ms)",
198205
last_time_ms, _guaranteed_gc_interval);
206+
accept_trigger();
199207
return true;
200208
}
201209
}
202-
210+
decline_trigger();
203211
return false;
204212
}
205213

@@ -211,6 +219,12 @@ void ShenandoahHeuristics::adjust_penalty(intx step) {
211219
assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100,
212220
"In range before adjustment: %zd", _gc_time_penalties);
213221

222+
if ((_most_recent_declined_trigger_count <= Penalty_Free_Declinations) && (step > 0)) {
223+
// Don't penalize if heuristics are not responsible for a negative outcome. Allow Penalty_Free_Declinations following
224+
// previous GC for self calibration without penalty.
225+
step = 0;
226+
}
227+
214228
intx new_val = _gc_time_penalties + step;
215229
if (new_val < 0) {
216230
new_val = 0;

src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class ShenandoahHeuristics : public CHeapObj<mtGC> {
6969
static const intx Degenerated_Penalty = 10; // how much to penalize average GC duration history on Degenerated GC
7070
static const intx Full_Penalty = 20; // how much to penalize average GC duration history on Full GC
7171

72+
// How many times can I decline a trigger opportunity without being penalized for excessive idle span before trigger?
73+
static const size_t Penalty_Free_Declinations = 16;
74+
7275
#ifdef ASSERT
7376
enum UnionTag {
7477
is_uninitialized, is_garbage, is_live_data
@@ -78,6 +81,18 @@ class ShenandoahHeuristics : public CHeapObj<mtGC> {
7881
protected:
7982
static const uint Moving_Average_Samples = 10; // Number of samples to store in moving averages
8083

84+
bool _start_gc_is_pending; // True denotes that GC has been triggered, so no need to trigger again.
85+
size_t _declined_trigger_count; // This counts how many times since previous GC finished that this
86+
// heuristic has answered false to should_start_gc().
87+
size_t _most_recent_declined_trigger_count;
88+
; // This represents the value of _declined_trigger_count as captured at the
89+
// moment the most recent GC effort was triggered. In case the most recent
90+
// concurrent GC effort degenerates, the value of this variable allows us to
91+
// differentiate between degeneration because heuristic was overly optimistic
92+
// in delaying the trigger vs. degeneration for other reasons (such as the
93+
// most recent GC triggered "immediately" after previous GC finished, but the
94+
// free headroom has already been depleted).
95+
8196
class RegionData {
8297
private:
8398
ShenandoahHeapRegion* _region;
@@ -167,6 +182,16 @@ class ShenandoahHeuristics : public CHeapObj<mtGC> {
167182

168183
void adjust_penalty(intx step);
169184

185+
inline void accept_trigger() {
186+
_most_recent_declined_trigger_count = _declined_trigger_count;
187+
_declined_trigger_count = 0;
188+
_start_gc_is_pending = true;
189+
}
190+
191+
inline void decline_trigger() {
192+
_declined_trigger_count++;
193+
}
194+
170195
public:
171196
ShenandoahHeuristics(ShenandoahSpaceInfo* space_info);
172197
virtual ~ShenandoahHeuristics();
@@ -185,6 +210,10 @@ class ShenandoahHeuristics : public CHeapObj<mtGC> {
185210

186211
virtual bool should_start_gc();
187212

213+
inline void cancel_trigger_request() {
214+
_start_gc_is_pending = false;
215+
}
216+
188217
virtual bool should_degenerate_cycle();
189218

190219
virtual void record_success_concurrent();

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ ShenandoahPassiveHeuristics::ShenandoahPassiveHeuristics(ShenandoahSpaceInfo* sp
3636

3737
bool ShenandoahPassiveHeuristics::should_start_gc() {
3838
// Never do concurrent GCs.
39+
decline_trigger();
3940
return false;
4041
}
4142

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ bool ShenandoahStaticHeuristics::should_start_gc() {
5555
log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)",
5656
byte_size_in_proper_unit(available), proper_unit_for_byte_size(available),
5757
byte_size_in_proper_unit(threshold_available), proper_unit_for_byte_size(threshold_available));
58+
accept_trigger();
5859
return true;
5960
}
6061
return ShenandoahHeuristics::should_start_gc();

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ bool ShenandoahYoungHeuristics::should_start_gc() {
119119
if (old_generation->is_preparing_for_mark() || old_generation->is_concurrent_mark_in_progress()) {
120120
size_t old_time_elapsed = size_t(old_heuristics->elapsed_cycle_time() * 1000);
121121
if (old_time_elapsed < ShenandoahMinimumOldTimeMs) {
122+
// Do not decline_trigger() when waiting for minimum quantum of Old-gen marking. It is not at our discretion
123+
// to trigger at this time.
122124
return false;
123125
}
124126
}
@@ -140,6 +142,7 @@ bool ShenandoahYoungHeuristics::should_start_gc() {
140142
// Detect unsigned arithmetic underflow
141143
assert(promo_potential < heap->capacity(), "Sanity");
142144
log_trigger("Expedite promotion of " PROPERFMT, PROPERFMTARGS(promo_potential));
145+
accept_trigger();
143146
return true;
144147
}
145148

@@ -150,9 +153,11 @@ bool ShenandoahYoungHeuristics::should_start_gc() {
150153
// candidates, but has not completed. There is no point in trying to start the young cycle before the old
151154
// cycle completes.
152155
log_trigger("Expedite mixed evacuation of %zu regions", mixed_candidates);
156+
accept_trigger();
153157
return true;
154158
}
155159

160+
// Don't decline_trigger() here That was done in ShenandoahAdaptiveHeuristics::should_start_gc()
156161
return false;
157162
}
158163

src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ void ShenandoahControlThread::run_service() {
131131
// GC is starting, bump the internal ID
132132
update_gc_id();
133133

134+
heuristics->cancel_trigger_request();
135+
134136
heap->reset_bytes_allocated_since_gc_start();
135137

136138
MetaspaceCombinedStats meta_sizes = MetaspaceUtils::get_combined_statistics();

0 commit comments

Comments
 (0)