Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,10 @@ void ShenandoahGenerationalHeap::complete_concurrent_cycle() {
entry_global_coalesce_and_fill();
}

log_info(gc, cset)("Concurrent cycle complete, promotions reserved: %zu, promotions expended: %zu, failed count: %zu, failed bytes: %zu",
old_generation()->get_promoted_reserve(), old_generation()->get_promoted_expended(),
old_generation()->get_promotion_failed_count(), old_generation()->get_promotion_failed_words() * HeapWordSize);

TransferResult result;
{
ShenandoahHeapLocker locker(lock());
Expand Down
52 changes: 30 additions & 22 deletions src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ ShenandoahOldGeneration::ShenandoahOldGeneration(uint max_queues, size_t max_cap
_promoted_expended(0),
_promotion_potential(0),
_pad_for_promote_in_place(0),
_promotion_failure_count(0),
_promotion_failure_words(0),
_promotable_humongous_regions(0),
_promotable_regular_regions(0),
_is_parsable(true),
Expand Down Expand Up @@ -240,7 +242,9 @@ void ShenandoahOldGeneration::augment_promoted_reserve(size_t increment) {

void ShenandoahOldGeneration::reset_promoted_expended() {
shenandoah_assert_heaplocked_or_safepoint();
AtomicAccess::store(&_promoted_expended, (size_t) 0);
AtomicAccess::store(&_promoted_expended, static_cast<size_t>(0));
AtomicAccess::store(&_promotion_failure_count, static_cast<size_t>(0));
AtomicAccess::store(&_promotion_failure_words, static_cast<size_t>(0));
}

size_t ShenandoahOldGeneration::expend_promoted(size_t increment) {
Expand Down Expand Up @@ -669,38 +673,42 @@ void ShenandoahOldGeneration::handle_failed_evacuation() {
}

void ShenandoahOldGeneration::handle_failed_promotion(Thread* thread, size_t size) {
AtomicAccess::inc(&_promotion_failure_count);
AtomicAccess::add(&_promotion_failure_words, size);

LogTarget(Debug, gc, plab) lt;
LogStream ls(lt);
if (lt.is_enabled()) {
log_failed_promotion(ls, thread, size);
}
}

void ShenandoahOldGeneration::log_failed_promotion(LogStream& ls, Thread* thread, size_t size) const {
// We squelch excessive reports to reduce noise in logs.
const size_t MaxReportsPerEpoch = 4;
constexpr size_t MaxReportsPerEpoch = 4;
static size_t last_report_epoch = 0;
static size_t epoch_report_count = 0;
auto heap = ShenandoahGenerationalHeap::heap();

size_t promotion_reserve;
size_t promotion_expended;

const auto heap = ShenandoahGenerationalHeap::heap();
const size_t gc_id = heap->control_thread()->get_gc_id();

if ((gc_id != last_report_epoch) || (epoch_report_count++ < MaxReportsPerEpoch)) {
{
// Promotion failures should be very rare. Invest in providing useful diagnostic info.
ShenandoahHeapLocker locker(heap->lock());
promotion_reserve = get_promoted_reserve();
promotion_expended = get_promoted_expended();
}
// Promotion failures should be very rare. Invest in providing useful diagnostic info.
PLAB* const plab = ShenandoahThreadLocalData::plab(thread);
const size_t words_remaining = (plab == nullptr)? 0: plab->words_remaining();
const char* promote_enabled = ShenandoahThreadLocalData::allow_plab_promotions(thread)? "enabled": "disabled";

log_info(gc, ergo)("Promotion failed, size %zu, has plab? %s, PLAB remaining: %zu"
", plab promotions %s, promotion reserve: %zu, promotion expended: %zu"
", old capacity: %zu, old_used: %zu, old unaffiliated regions: %zu",
size * HeapWordSize, plab == nullptr? "no": "yes",
words_remaining * HeapWordSize, promote_enabled, promotion_reserve, promotion_expended,
max_capacity(), used(), free_unaffiliated_regions());
// Promoted reserve is only changed by vm or control thread. Promoted expended is always accessed atomically.
const size_t promotion_reserve = get_promoted_reserve();
const size_t promotion_expended = get_promoted_expended();

ls.print_cr("Promotion failed, size %zu, has plab? %s, PLAB remaining: %zu"
", plab promotions %s, promotion reserve: %zu, promotion expended: %zu"
", old capacity: %zu, old_used: %zu, old unaffiliated regions: %zu",
size * HeapWordSize, plab == nullptr? "no": "yes",
words_remaining * HeapWordSize, promote_enabled, promotion_reserve, promotion_expended,
max_capacity(), used(), free_unaffiliated_regions());

if ((gc_id == last_report_epoch) && (epoch_report_count >= MaxReportsPerEpoch)) {
log_debug(gc, ergo)("Squelching additional promotion failure reports for current epoch");
} else if (gc_id != last_report_epoch) {
if (gc_id != last_report_epoch) {
last_report_epoch = gc_id;
epoch_report_count = 1;
}
Expand Down
24 changes: 18 additions & 6 deletions src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "gc/shenandoah/shenandoahScanRemembered.hpp"
#include "gc/shenandoah/shenandoahSharedVariables.hpp"

class LogStream;
class ShenandoahHeapRegion;
class ShenandoahHeapRegionClosure;
class ShenandoahOldHeuristics;
Expand Down Expand Up @@ -65,16 +66,21 @@ class ShenandoahOldGeneration : public ShenandoahGeneration {
// remaining in a PLAB when it is retired.
size_t _promoted_expended;

// Represents the quantity of live bytes we expect to promote in place during the next
// evacuation cycle. This value is used by the young heuristic to trigger mixed collections.
// Represents the quantity of live bytes we expect to promote during the next evacuation
// cycle. This value is used by the young heuristic to trigger mixed collections.
// It is also used when computing the optimum size for the old generation.
size_t _promotion_potential;

// When a region is selected to be promoted in place, the remaining free memory is filled
// in to prevent additional allocations (preventing premature promotion of newly allocated
// objects. This field records the total amount of padding used for such regions.
// objects). This field records the total amount of padding used for such regions.
size_t _pad_for_promote_in_place;

// Keep track of the number and size of promotions that failed. Perhaps we should use this to increase
// the size of the old generation for the next collection cycle.
size_t _promotion_failure_count;
size_t _promotion_failure_words;

// During construction of the collection set, we keep track of regions that are eligible
// for promotion in place. These fields track the count of those humongous and regular regions.
// This data is used to force the evacuation phase even when the collection set is otherwise
Expand Down Expand Up @@ -119,6 +125,10 @@ class ShenandoahOldGeneration : public ShenandoahGeneration {
// This is used on the allocation path to gate promotions that would exceed the reserve
size_t get_promoted_expended() const;

// Return the count and size (in words) of failed promotions since the last reset
size_t get_promotion_failed_count() const { return AtomicAccess::load(&_promotion_failure_count); }
size_t get_promotion_failed_words() const { return AtomicAccess::load(&_promotion_failure_words); }

// Test if there is enough memory reserved for this promotion
bool can_promote(size_t requested_bytes) const {
size_t promotion_avail = get_promoted_reserve();
Expand All @@ -137,9 +147,10 @@ class ShenandoahOldGeneration : public ShenandoahGeneration {
// See description in field declaration
void set_region_balance(ssize_t balance) { _region_balance = balance; }
ssize_t get_region_balance() const { return _region_balance; }

// See description in field declaration
void set_promotion_potential(size_t val) { _promotion_potential = val; };
size_t get_promotion_potential() const { return _promotion_potential; };
void set_promotion_potential(size_t val) { _promotion_potential = val; }
size_t get_promotion_potential() const { return _promotion_potential; }

// See description in field declaration
void set_pad_for_promote_in_place(size_t pad) { _pad_for_promote_in_place = pad; }
Expand All @@ -161,8 +172,9 @@ class ShenandoahOldGeneration : public ShenandoahGeneration {
// This will signal the control thread to run a full GC instead of a futile degenerated gc
void handle_failed_evacuation();

// This logs that an evacuation to the old generation has failed
// Increment promotion failure counters, optionally log a more detailed message
void handle_failed_promotion(Thread* thread, size_t size);
void log_failed_promotion(LogStream& ls, Thread* thread, size_t size) const;

// A successful evacuation re-dirties the cards and registers the object with the remembered set
void handle_evacuation(HeapWord* obj, size_t words, bool promotion);
Expand Down