Skip to content

Commit 501fa20

Browse files
author
William Kemper
committed
8368501: Shenandoah: GC progress evaluation does not use generation
Reviewed-by: ysr
1 parent 37b725d commit 501fa20

File tree

4 files changed

+42
-73
lines changed

4 files changed

+42
-73
lines changed

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,7 @@ void ShenandoahDegenGC::op_degenerated() {
115115
}
116116
#endif
117117

118-
ShenandoahMetricsSnapshot metrics;
119-
metrics.snap_before();
118+
ShenandoahMetricsSnapshot metrics(heap->free_set());
120119

121120
switch (_degen_point) {
122121
// The cases below form the Duff's-like device: it describes the actual GC cycle,
@@ -308,10 +307,8 @@ void ShenandoahDegenGC::op_degenerated() {
308307
Universe::verify();
309308
}
310309

311-
metrics.snap_after();
312-
313310
// Decide if this cycle made good progress, and, if not, should it upgrade to a full GC.
314-
const bool progress = metrics.is_good_progress(_generation);
311+
const bool progress = metrics.is_good_progress();
315312
ShenandoahCollectorPolicy* policy = heap->shenandoah_policy();
316313
policy->record_degenerated(_generation->is_young(), _abbreviated, progress);
317314
if (progress) {

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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,21 +104,18 @@ void ShenandoahFullGC::entry_full(GCCause::Cause cause) {
104104
}
105105

106106
void ShenandoahFullGC::op_full(GCCause::Cause cause) {
107-
ShenandoahMetricsSnapshot metrics;
108-
metrics.snap_before();
107+
ShenandoahHeap* const heap = ShenandoahHeap::heap();
108+
109+
ShenandoahMetricsSnapshot metrics(heap->free_set());
109110

110111
// Perform full GC
111112
do_it(cause);
112113

113-
ShenandoahHeap* const heap = ShenandoahHeap::heap();
114-
115114
if (heap->mode()->is_generational()) {
116115
ShenandoahGenerationalFullGC::handle_completion(heap);
117116
}
118117

119-
metrics.snap_after();
120-
121-
if (metrics.is_good_progress(heap->global_generation())) {
118+
if (metrics.is_good_progress()) {
122119
heap->notify_gc_progress();
123120
} else {
124121
// Nothing to do. Tell the allocation path that we have failed to make

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

Lines changed: 28 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -28,69 +28,45 @@
2828
#include "gc/shenandoah/shenandoahHeapRegion.hpp"
2929
#include "gc/shenandoah/shenandoahMetrics.hpp"
3030

31-
ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot() {
32-
_heap = ShenandoahHeap::heap();
31+
ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot(ShenandoahFreeSet* free_set)
32+
: _free_set(free_set)
33+
, _used_before(free_set->used())
34+
, _if_before(free_set->internal_fragmentation())
35+
, _ef_before(free_set->external_fragmentation()) {
3336
}
3437

35-
void ShenandoahMetricsSnapshot::snap_before() {
36-
_used_before = _heap->used();
37-
_if_before = _heap->free_set()->internal_fragmentation();
38-
_ef_before = _heap->free_set()->external_fragmentation();
39-
}
40-
void ShenandoahMetricsSnapshot::snap_after() {
41-
_used_after = _heap->used();
42-
_if_after = _heap->free_set()->internal_fragmentation();
43-
_ef_after = _heap->free_set()->external_fragmentation();
44-
}
45-
46-
// For degenerated GC, generation is Young in generational mode, Global in non-generational mode.
47-
// For full GC, generation is always Global.
48-
//
49-
// Note that the size of the chosen collection set is proportional to the relevant generation's collection set.
50-
// Note also that the generation size may change following selection of the collection set, as a side effect
51-
// of evacuation. Evacuation may promote objects, causing old to grow and young to shrink. Or this may be a
52-
// mixed evacuation. When old regions are evacuated, this typically allows young to expand. In all of these
53-
// various scenarios, the purpose of asking is_good_progress() is to determine if there is enough memory available
54-
// within young generation to justify making an attempt to perform a concurrent collection. For this reason, we'll
55-
// use the current size of the generation (which may not be different than when the collection set was chosen) to
56-
// assess how much free memory we require in order to consider the most recent GC to have had good progress.
57-
58-
bool ShenandoahMetricsSnapshot::is_good_progress(ShenandoahGeneration* generation) {
38+
bool ShenandoahMetricsSnapshot::is_good_progress() const {
5939
// Under the critical threshold?
60-
ShenandoahFreeSet* free_set = _heap->free_set();
61-
size_t free_actual = free_set->available();
40+
const size_t free_actual = _free_set->available();
6241
assert(free_actual != ShenandoahFreeSet::FreeSetUnderConstruction, "Avoid this race");
6342

64-
// ShenandoahCriticalFreeThreshold is expressed as a percentage. We multiple this percentage by 1/100th
65-
// of the generation capacity to determine whether the available memory within the generation exceeds the
66-
// critical threshold.
67-
size_t free_expected = (ShenandoahHeap::heap()->soft_max_capacity() / 100) * ShenandoahCriticalFreeThreshold;
68-
69-
bool prog_free = free_actual >= free_expected;
70-
log_info(gc, ergo)("%s progress for free space: %zu%s, need %zu%s",
71-
prog_free ? "Good" : "Bad",
72-
byte_size_in_proper_unit(free_actual), proper_unit_for_byte_size(free_actual),
73-
byte_size_in_proper_unit(free_expected), proper_unit_for_byte_size(free_expected));
43+
// ShenandoahCriticalFreeThreshold is expressed as a percentage. We multiply this percentage by 1/100th
44+
// of the soft max capacity to determine whether the available memory within the mutator partition of the
45+
// freeset exceeds the critical threshold.
46+
const size_t free_expected = (ShenandoahHeap::heap()->soft_max_capacity() / 100) * ShenandoahCriticalFreeThreshold;
47+
const bool prog_free = free_actual >= free_expected;
48+
log_info(gc, ergo)("%s progress for free space: " PROPERFMT ", need " PROPERFMT,
49+
prog_free ? "Good" : "Bad", PROPERFMTARGS(free_actual), PROPERFMTARGS(free_expected));
7450
if (!prog_free) {
7551
return false;
7652
}
7753

7854
// Freed up enough?
79-
size_t progress_actual = (_used_before > _used_after) ? _used_before - _used_after : 0;
80-
size_t progress_expected = ShenandoahHeapRegion::region_size_bytes();
81-
bool prog_used = progress_actual >= progress_expected;
82-
log_info(gc, ergo)("%s progress for used space: %zu%s, need %zu%s",
83-
prog_used ? "Good" : "Bad",
84-
byte_size_in_proper_unit(progress_actual), proper_unit_for_byte_size(progress_actual),
85-
byte_size_in_proper_unit(progress_expected), proper_unit_for_byte_size(progress_expected));
55+
const size_t used_after = _free_set->used();
56+
const size_t progress_actual = (_used_before > used_after) ? _used_before - used_after : 0;
57+
const size_t progress_expected = ShenandoahHeapRegion::region_size_bytes();
58+
const bool prog_used = progress_actual >= progress_expected;
59+
log_info(gc, ergo)("%s progress for used space: " PROPERFMT ", need " PROPERFMT,
60+
prog_used ? "Good" : "Bad", PROPERFMTARGS(progress_actual), PROPERFMTARGS(progress_expected));
8661
if (prog_used) {
8762
return true;
8863
}
8964

9065
// Internal fragmentation is down?
91-
double if_actual = _if_before - _if_after;
92-
double if_expected = 0.01; // 1% should be enough
93-
bool prog_if = if_actual >= if_expected;
66+
const double if_after = _free_set->internal_fragmentation();
67+
const double if_actual = _if_before - if_after;
68+
const double if_expected = 0.01; // 1% should be enough
69+
const bool prog_if = if_actual >= if_expected;
9470
log_info(gc, ergo)("%s progress for internal fragmentation: %.1f%%, need %.1f%%",
9571
prog_if ? "Good" : "Bad",
9672
if_actual * 100, if_expected * 100);
@@ -99,9 +75,10 @@ bool ShenandoahMetricsSnapshot::is_good_progress(ShenandoahGeneration* generatio
9975
}
10076

10177
// External fragmentation is down?
102-
double ef_actual = _ef_before - _ef_after;
103-
double ef_expected = 0.01; // 1% should be enough
104-
bool prog_ef = ef_actual >= ef_expected;
78+
const double ef_after = _free_set->external_fragmentation();
79+
const double ef_actual = _ef_before - ef_after;
80+
const double ef_expected = 0.01; // 1% should be enough
81+
const bool prog_ef = ef_actual >= ef_expected;
10582
log_info(gc, ergo)("%s progress for external fragmentation: %.1f%%, need %.1f%%",
10683
prog_ef ? "Good" : "Bad",
10784
ef_actual * 100, ef_expected * 100);

src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,20 @@
2525
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHMETRICS_HPP
2626
#define SHARE_GC_SHENANDOAH_SHENANDOAHMETRICS_HPP
2727

28-
#include "gc/shenandoah/shenandoahHeap.hpp"
28+
#include "gc/shenandoah/shenandoahFreeSet.hpp"
2929

3030
class ShenandoahMetricsSnapshot : public StackObj {
3131
private:
32-
ShenandoahHeap* _heap;
33-
size_t _used_before, _used_after;
34-
double _if_before, _if_after;
35-
double _ef_before, _ef_after;
32+
ShenandoahFreeSet* _free_set;
33+
size_t _used_before;
34+
double _if_before;
35+
double _ef_before;
3636

3737
public:
38-
ShenandoahMetricsSnapshot();
38+
explicit ShenandoahMetricsSnapshot(ShenandoahFreeSet* free_set);
3939

40-
void snap_before();
41-
void snap_after();
42-
43-
bool is_good_progress(ShenandoahGeneration *generation);
40+
// Decide if the GC made "good" progress (i.e., reduced fragmentation, freed up sufficient memory).
41+
bool is_good_progress() const;
4442
};
4543

4644
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHMETRICS_HPP

0 commit comments

Comments
 (0)