Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: openjdk/shenandoah
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ebc1fd1d
Choose a base ref
...
head repository: openjdk/shenandoah
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 58bd7b36
Choose a head ref
  • 12 commits
  • 12 files changed
  • 1 contributor

Commits on Feb 7, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    26bd340 View commit details

Commits on Feb 8, 2023

  1. Copy the full SHA
    014d760 View commit details

Commits on Feb 13, 2023

  1. Copy the full SHA
    5158af4 View commit details
  2. Copy the full SHA
    ad704a4 View commit details
  3. Copy the full SHA
    b51b845 View commit details

Commits on Feb 14, 2023

  1. Copy the full SHA
    a83f1a2 View commit details

Commits on Feb 15, 2023

  1. Copy the full SHA
    7d47f34 View commit details

Commits on Feb 16, 2023

  1. Copy the full SHA
    b93f1d2 View commit details

Commits on Feb 17, 2023

  1. Copy the full SHA
    e77dc53 View commit details
  2. Copy the full SHA
    c3e6c47 View commit details

Commits on Mar 2, 2023

  1. Copy the full SHA
    6871dbd View commit details
  2. Copy the full SHA
    58bd7b3 View commit details
Original file line number Diff line number Diff line change
@@ -213,20 +213,27 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand
size_t free_target = (capacity * ShenandoahMinFreeThreshold) / 100 + max_cset;
size_t min_garbage = (free_target > actual_free) ? (free_target - actual_free) : 0;

log_info(gc, ergo)("Adaptive CSet Selection. Max Evacuation: " SIZE_FORMAT "%s, Actual Free: " SIZE_FORMAT "%s.",
byte_size_in_proper_unit(max_cset), proper_unit_for_byte_size(max_cset),
byte_size_in_proper_unit(actual_free), proper_unit_for_byte_size(actual_free));
log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "%s, Actual Free: "
SIZE_FORMAT "%s, Max Evacuation: " SIZE_FORMAT "%s, Min Garbage: " SIZE_FORMAT "%s",
byte_size_in_proper_unit(free_target), proper_unit_for_byte_size(free_target),
byte_size_in_proper_unit(actual_free), proper_unit_for_byte_size(actual_free),
byte_size_in_proper_unit(max_cset), proper_unit_for_byte_size(max_cset),
byte_size_in_proper_unit(min_garbage), proper_unit_for_byte_size(min_garbage));

size_t cur_cset = 0;
size_t cur_garbage = 0;

for (size_t idx = 0; idx < size; idx++) {
ShenandoahHeapRegion* r = data[idx]._region;
size_t new_cset = cur_cset + r->get_live_data_bytes();
size_t region_garbage = r->garbage();
size_t new_garbage = cur_garbage + region_garbage;
bool add_regardless = (region_garbage > ignore_threshold) && (new_garbage < min_garbage);
if ((new_cset <= max_cset) && (add_regardless || (region_garbage > garbage_threshold))) {

size_t new_cset = cur_cset + r->get_live_data_bytes();
size_t new_garbage = cur_garbage + r->garbage();

if (new_cset > max_cset) {
break;
}

if ((new_garbage < min_garbage) || (r->garbage() > garbage_threshold)) {
cset->add_region(r);
cur_cset = new_cset;
cur_garbage = new_garbage;
@@ -361,7 +368,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() {

size_t min_threshold = min_free_threshold();

if (allocation_headroom < min_threshold) {
if (available < min_threshold) {
log_info(gc)("Trigger (%s): Free (" SIZE_FORMAT "%s) is below minimum threshold (" SIZE_FORMAT "%s)",
_generation->name(),
byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom),
@@ -373,7 +380,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() {
const size_t max_learn = ShenandoahLearningSteps;
if (_gc_times_learned < max_learn) {
size_t init_threshold = capacity / 100 * ShenandoahInitFreeThreshold;
if (allocation_headroom < init_threshold) {
if (available < init_threshold) {
log_info(gc)("Trigger (%s): Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "%s) is below initial threshold (" SIZE_FORMAT "%s)",
_generation->name(), _gc_times_learned + 1, max_learn,
byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom),
@@ -423,33 +430,11 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() {

double avg_cycle_time = _gc_cycle_time_history->davg() + (_margin_of_error_sd * _gc_cycle_time_history->dsd());

size_t last_live_memory = get_last_live_memory();
size_t penultimate_live_memory = get_penultimate_live_memory();
double original_cycle_time = avg_cycle_time;
if ((penultimate_live_memory < last_live_memory) && (penultimate_live_memory != 0)) {
// If the live-memory size is growing, our estimates of cycle time are based on lighter workload, so adjust.
// TODO: Be more precise about how to scale when live memory is growing. Existing code is a very rough approximation
// tuned with very limited workload observations.
avg_cycle_time = (avg_cycle_time * 2 * last_live_memory) / penultimate_live_memory;
} else {
int degen_cycles = degenerated_cycles_in_a_row();
if (degen_cycles > 0) {
// If we've degenerated recently, we might be waiting too long between triggers so adjust trigger forward.
// TODO: Be more precise about how to scale when we've experienced recent degenerated GC. Existing code is a very
// rough approximation tuned with very limited workload observations.
avg_cycle_time += degen_cycles * avg_cycle_time;
}
}

double avg_alloc_rate = _allocation_rate.upper_bound(_margin_of_error_sd);
log_debug(gc)("%s: average GC time: %.2f ms, allocation rate: %.0f %s/s",
_generation->name(), avg_cycle_time * 1000, byte_size_in_proper_unit(avg_alloc_rate), proper_unit_for_byte_size(avg_alloc_rate));

if (avg_cycle_time > allocation_headroom / avg_alloc_rate) {
if (avg_cycle_time > original_cycle_time) {
log_debug(gc)("%s: average GC time adjusted from: %.2f ms to %.2f ms because upward trend in live memory retention",
_generation->name(), original_cycle_time, avg_cycle_time);
}

log_info(gc)("Trigger (%s): Average GC time (%.2f ms) is above the time for average allocation rate (%.0f %sB/s) to deplete free headroom (" SIZE_FORMAT "%s) (margin of error = %.2f)",
_generation->name(), avg_cycle_time * 1000,
@@ -585,10 +570,6 @@ bool ShenandoahAllocationRate::is_spiking(double rate, double threshold) const {
return false;
}

double ShenandoahAllocationRate::instantaneous_rate(size_t allocated) const {
return instantaneous_rate(os::elapsedTime(), allocated);
}

double ShenandoahAllocationRate::instantaneous_rate(double time, size_t allocated) const {
size_t last_value = _last_sample_value;
double last_time = _last_sample_time;
Original file line number Diff line number Diff line change
@@ -36,7 +36,6 @@ class ShenandoahAllocationRate : public CHeapObj<mtGC> {

double sample(size_t allocated);

double instantaneous_rate(size_t allocated) const;
double upper_bound(double sds) const;
bool is_spiking(double rate, double threshold) const;

Original file line number Diff line number Diff line change
@@ -58,8 +58,6 @@ ShenandoahHeuristics::ShenandoahHeuristics(ShenandoahGeneration* generation) :
_gc_times_learned(0),
_gc_time_penalties(0),
_gc_cycle_time_history(new TruncatedSeq(Moving_Average_Samples, ShenandoahAdaptiveDecayFactor)),
_live_memory_last_cycle(0),
_live_memory_penultimate_cycle(0),
_metaspace_oom()
{
// No unloading during concurrent mark? Communicate that to heuristics
@@ -126,7 +124,7 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec

for (size_t i = 0; i < num_regions; i++) {
ShenandoahHeapRegion* region = heap->get_region(i);
if (!in_generation(region)) {
if (is_generational && !in_generation(region)) {
continue;
}

@@ -181,8 +179,6 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec
}
}

save_last_live_memory(live_memory);

// Step 2. Look back at garbage statistics, and decide if we want to collect anything,
// given the amount of immediately reclaimable garbage. If we do, figure out the collection set.

@@ -217,8 +213,8 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec
size_t collectable_garbage_percent = (total_garbage == 0) ? 0 : (collectable_garbage * 100 / total_garbage);

log_info(gc, ergo)("Collectable Garbage: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), "
"Immediate: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), "
"CSet: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%)",
"Immediate: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%) R: " SIZE_FORMAT ", "
"CSet: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%) R: " SIZE_FORMAT,

byte_size_in_proper_unit(collectable_garbage),
proper_unit_for_byte_size(collectable_garbage),
@@ -227,10 +223,12 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec
byte_size_in_proper_unit(immediate_garbage),
proper_unit_for_byte_size(immediate_garbage),
immediate_percent,
immediate_regions,

byte_size_in_proper_unit(collection_set->garbage()),
proper_unit_for_byte_size(collection_set->garbage()),
cset_percent);
cset_percent,
collection_set->count());

if (collection_set->garbage() > 0) {
size_t young_evac_bytes = collection_set->get_young_bytes_reserved_for_evacuation();
@@ -382,16 +380,3 @@ size_t ShenandoahHeuristics::min_free_threshold() {
: ShenandoahMinFreeThreshold;
return _generation->soft_max_capacity() / 100 * min_free_threshold;
}

void ShenandoahHeuristics::save_last_live_memory(size_t live_memory) {
_live_memory_penultimate_cycle = _live_memory_last_cycle;
_live_memory_last_cycle = live_memory;
}

size_t ShenandoahHeuristics::get_last_live_memory() {
return _live_memory_last_cycle;
}

size_t ShenandoahHeuristics::get_penultimate_live_memory() {
return _live_memory_penultimate_cycle;
}
Original file line number Diff line number Diff line change
@@ -101,9 +101,6 @@ class ShenandoahHeuristics : public CHeapObj<mtGC> {
intx _gc_time_penalties;
TruncatedSeq* _gc_cycle_time_history;

size_t _live_memory_last_cycle;
size_t _live_memory_penultimate_cycle;

// There may be many threads that contend to set this flag
ShenandoahSharedFlag _metaspace_oom;

@@ -173,10 +170,6 @@ class ShenandoahHeuristics : public CHeapObj<mtGC> {
virtual void initialize();

double elapsed_cycle_time() const;

void save_last_live_memory(size_t live_memory);
size_t get_last_live_memory();
size_t get_penultimate_live_memory();
};

#endif // SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHHEURISTICS_HPP
9 changes: 8 additions & 1 deletion src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ ShenandoahCollectionSet::ShenandoahCollectionSet(ShenandoahHeap* heap, ReservedS
_has_old_regions(false),
_garbage(0),
_used(0),
_live(0),
_region_count(0),
_old_garbage(0),
_current_index(0) {
@@ -105,6 +106,7 @@ void ShenandoahCollectionSet::add_region(ShenandoahHeapRegion* r) {
_has_old_regions |= r->is_old();
_garbage += r->garbage();
_used += r->used();
_live += r->get_live_data_bytes();
// Update the region status too. State transition would be checked internally.
r->make_cset();
}
@@ -122,6 +124,7 @@ void ShenandoahCollectionSet::clear() {
_garbage = 0;
_old_garbage = 0;
_used = 0;
_live = 0;

_region_count = 0;
_current_index = 0;
@@ -177,7 +180,11 @@ ShenandoahHeapRegion* ShenandoahCollectionSet::next() {
}

void ShenandoahCollectionSet::print_on(outputStream* out) const {
out->print_cr("Collection Set : " SIZE_FORMAT "", count());
out->print_cr("Collection Set: Regions: "
SIZE_FORMAT ", Garbage: " SIZE_FORMAT "%s, Live: " SIZE_FORMAT "%s, Used: " SIZE_FORMAT "%s", count(),
byte_size_in_proper_unit(garbage()), proper_unit_for_byte_size(garbage()),
byte_size_in_proper_unit(live()), proper_unit_for_byte_size(live()),
byte_size_in_proper_unit(used()), proper_unit_for_byte_size(used()));

debug_only(size_t regions = 0;)
for (size_t index = 0; index < _heap->num_regions(); index ++) {
4 changes: 3 additions & 1 deletion src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.hpp
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@ class ShenandoahCollectionSet : public CHeapObj<mtGC> {
bool _has_old_regions;
size_t _garbage;
size_t _used;
size_t _live;
size_t _region_count;
size_t _immediate_trash;

@@ -119,8 +120,9 @@ class ShenandoahCollectionSet : public CHeapObj<mtGC> {

bool has_old_regions() const { return _has_old_regions; }
size_t used() const { return _used; }

size_t live() const { return _live; }
size_t garbage() const { return _garbage; }

void clear();

private:
7 changes: 7 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
Original file line number Diff line number Diff line change
@@ -747,6 +747,13 @@ void ShenandoahConcurrentGC::op_final_mark() {
heap->prepare_concurrent_roots();

if (!heap->collection_set()->is_empty()) {
LogTarget(Info, gc, ergo) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
heap->collection_set()->print_on(&ls);
}

if (ShenandoahVerify) {
heap->verifier()->verify_before_evacuation();
}
Loading