Skip to content

8361726: Shenandoah: More detailed evacuation instrumentation #26222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
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
6 changes: 6 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ void ShenandoahControlThread::run_service() {
ResourceMark rm;
LogStream ls(lt);
heap->phase_timings()->print_cycle_on(&ls);
#ifdef NOT_PRODUCT
ShenandoahEvacuationTracker* evac_tracker = heap->evac_tracker();
ShenandoahCycleStats evac_stats = evac_tracker->flush_cycle_to_global();
evac_tracker->print_evacuations_on(&ls, &evac_stats.workers,
&evac_stats.mutators);
#endif
}
}

Expand Down
80 changes: 50 additions & 30 deletions src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,22 @@
#include "runtime/thread.hpp"
#include "runtime/threadSMR.inline.hpp"

ShenandoahEvacuationStats::ShenandoahEvacuations* ShenandoahEvacuationStats::get_category(
ShenandoahAffiliation from,
ShenandoahAffiliation to) {
if (from == YOUNG_GENERATION) {
if (to == YOUNG_GENERATION) {
return &_young;
}
assert(to == OLD_GENERATION, "If not evacuating to young, must be promotion to old");
return &_promotion;
}
assert(from == OLD_GENERATION, "If not evacuating from young, then must be from old");
return &_old;
}

ShenandoahEvacuationStats::ShenandoahEvacuationStats()
: _evacuations_completed(0), _bytes_completed(0),
_evacuations_attempted(0), _bytes_attempted(0),
_use_age_table(ShenandoahGenerationalCensusAtEvac || !ShenandoahGenerationalAdaptiveTenuring),
: _use_age_table(ShenandoahGenerationalCensusAtEvac || !ShenandoahGenerationalAdaptiveTenuring),
_age_table(nullptr) {
if (_use_age_table) {
_age_table = new AgeTable(false);
Expand All @@ -45,14 +57,17 @@ AgeTable* ShenandoahEvacuationStats::age_table() const {
return _age_table;
}

void ShenandoahEvacuationStats::begin_evacuation(size_t bytes) {
++_evacuations_attempted;
_bytes_attempted += bytes;
void ShenandoahEvacuationStats::begin_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
ShenandoahEvacuations* category = get_category(from, to);
category->_evacuations_attempted++;
category->_bytes_attempted += bytes;

}

void ShenandoahEvacuationStats::end_evacuation(size_t bytes) {
++_evacuations_completed;
_bytes_completed += bytes;
void ShenandoahEvacuationStats::end_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
ShenandoahEvacuations* category = get_category(from, to);
category->_evacuations_completed++;
category->_bytes_completed += bytes;
}

void ShenandoahEvacuationStats::record_age(size_t bytes, uint age) {
Expand All @@ -63,34 +78,39 @@ void ShenandoahEvacuationStats::record_age(size_t bytes, uint age) {
}

void ShenandoahEvacuationStats::accumulate(const ShenandoahEvacuationStats* other) {
_evacuations_completed += other->_evacuations_completed;
_bytes_completed += other->_bytes_completed;
_evacuations_attempted += other->_evacuations_attempted;
_bytes_attempted += other->_bytes_attempted;
_young.accumulate(other->_young);
_old.accumulate(other->_old);
_promotion.accumulate(other->_promotion);

if (_use_age_table) {
_age_table->merge(other->age_table());
}
}

void ShenandoahEvacuationStats::reset() {
_evacuations_completed = _evacuations_attempted = 0;
_bytes_completed = _bytes_attempted = 0;
_young.reset();
_old.reset();
_promotion.reset();

if (_use_age_table) {
_age_table->clear();
}
}

void ShenandoahEvacuationStats::print_on(outputStream* st) {
#ifndef PRODUCT
void ShenandoahEvacuationStats::ShenandoahEvacuations::print_on(outputStream* st) const {
size_t abandoned_size = _bytes_attempted - _bytes_completed;
size_t abandoned_count = _evacuations_attempted - _evacuations_completed;
st->print_cr("Evacuated %zu%s across %zu objects, "
"abandoned %zu%s across %zu objects.",
byte_size_in_proper_unit(_bytes_completed), proper_unit_for_byte_size(_bytes_completed),
_evacuations_completed,
byte_size_in_proper_unit(abandoned_size), proper_unit_for_byte_size(abandoned_size),
abandoned_count);
#endif
st->print_cr("Evacuated " PROPERFMT" across %zu objects, "
"abandoned " PROPERFMT " across %zu objects.",
PROPERFMTARGS(_bytes_completed), _evacuations_completed,
PROPERFMTARGS(abandoned_size), abandoned_count);
}

void ShenandoahEvacuationStats::print_on(outputStream* st) const {
st->print("Young: "); _young.print_on(st);
st->print("Promotion: "); _promotion.print_on(st);
st->print("Old: "); _old.print_on(st);

if (_use_age_table) {
_age_table->print_on(st);
}
Expand All @@ -103,10 +123,10 @@ void ShenandoahEvacuationTracker::print_global_on(outputStream* st) {
void ShenandoahEvacuationTracker::print_evacuations_on(outputStream* st,
ShenandoahEvacuationStats* workers,
ShenandoahEvacuationStats* mutators) {
st->print("Workers: ");
st->print_cr("Workers: ");
workers->print_on(st);
st->cr();
st->print("Mutators: ");
st->print_cr("Mutators: ");
mutators->print_on(st);
st->cr();

Expand Down Expand Up @@ -160,12 +180,12 @@ ShenandoahCycleStats ShenandoahEvacuationTracker::flush_cycle_to_global() {
return {workers, mutators};
}

void ShenandoahEvacuationTracker::begin_evacuation(Thread* thread, size_t bytes) {
ShenandoahThreadLocalData::begin_evacuation(thread, bytes);
void ShenandoahEvacuationTracker::begin_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
ShenandoahThreadLocalData::begin_evacuation(thread, bytes, from, to);
}

void ShenandoahEvacuationTracker::end_evacuation(Thread* thread, size_t bytes) {
ShenandoahThreadLocalData::end_evacuation(thread, bytes);
void ShenandoahEvacuationTracker::end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
ShenandoahThreadLocalData::end_evacuation(thread, bytes, from, to);
}

void ShenandoahEvacuationTracker::record_age(Thread* thread, size_t bytes, uint age) {
Expand Down
56 changes: 47 additions & 9 deletions src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,45 @@
#define SHARE_GC_SHENANDOAH_SHENANDOAHEVACTRACKER_HPP

#include "gc/shared/ageTable.hpp"
#include "gc/shenandoah/shenandoahAffiliation.hpp"
#include "utilities/ostream.hpp"

class ShenandoahEvacuationStats : public CHeapObj<mtGC> {
private:
size_t _evacuations_completed;
size_t _bytes_completed;
size_t _evacuations_attempted;
size_t _bytes_attempted;
struct ShenandoahEvacuations {
size_t _evacuations_completed;
size_t _bytes_completed;
size_t _evacuations_attempted;
size_t _bytes_attempted;
ShenandoahEvacuations()
: _evacuations_completed(0)
, _bytes_completed(0)
, _evacuations_attempted(0)
, _bytes_attempted(0) {
}

void accumulate(const ShenandoahEvacuations& other) {
_evacuations_completed += other._evacuations_completed;
_bytes_completed += other._bytes_completed;
_evacuations_attempted += other._evacuations_attempted;
_bytes_attempted += other._bytes_attempted;
}

void reset() {
_evacuations_completed = 0;
_bytes_completed = 0;
_evacuations_attempted = 0;
_bytes_attempted = 0;
}

void print_on(outputStream* st) const;
};

ShenandoahEvacuations* get_category(ShenandoahAffiliation from, ShenandoahAffiliation to);

ShenandoahEvacuations _young;
ShenandoahEvacuations _old;
ShenandoahEvacuations _promotion;

bool _use_age_table;
AgeTable* _age_table;
Expand All @@ -43,11 +74,14 @@ class ShenandoahEvacuationStats : public CHeapObj<mtGC> {

AgeTable* age_table() const;

void begin_evacuation(size_t bytes);
void end_evacuation(size_t bytes);
// Record that the current thread is attempting to copy this many bytes.
void begin_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to);

// Record that the current thread has completed copying this many bytes.
void end_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to);
void record_age(size_t bytes, uint age);

void print_on(outputStream* st);
void print_on(outputStream* st) const;
void accumulate(const ShenandoahEvacuationStats* other);
void reset();
};
Expand All @@ -66,8 +100,12 @@ class ShenandoahEvacuationTracker : public CHeapObj<mtGC> {
public:
ShenandoahEvacuationTracker() = default;

void begin_evacuation(Thread* thread, size_t bytes);
void end_evacuation(Thread* thread, size_t bytes);
// Record that the given thread has begun to evacuate an object of this size.
void begin_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to);

// Multiple threads may attempt to evacuate the same object, but only the successful thread will end the evacuation.
// Evacuations that were begun, but not ended are considered 'abandoned'.
void end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to);
void record_age(Thread* thread, size_t bytes, uint age);

void print_global_on(outputStream* st);
Expand Down
17 changes: 2 additions & 15 deletions src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ size_t ShenandoahGenerationalHeap::unsafe_max_tlab_alloc(Thread *thread) const {
ShenandoahGenerationalHeap::ShenandoahGenerationalHeap(ShenandoahCollectorPolicy* policy) :
ShenandoahHeap(policy),
_age_census(nullptr),
_evac_tracker(new ShenandoahEvacuationTracker()),
_min_plab_size(calculate_min_plab()),
_max_plab_size(calculate_max_plab()),
_regulator_thread(nullptr),
Expand All @@ -100,18 +99,6 @@ void ShenandoahGenerationalHeap::print_init_logger() const {
logger.print_all();
}

void ShenandoahGenerationalHeap::print_tracing_info() const {
ShenandoahHeap::print_tracing_info();

LogTarget(Info, gc, stats) lt;
if (lt.is_enabled()) {
LogStream ls(lt);
ls.cr();
ls.cr();
evac_tracker()->print_global_on(&ls);
}
}

void ShenandoahGenerationalHeap::initialize_heuristics() {
// Initialize global generation and heuristics even in generational mode.
ShenandoahHeap::initialize_heuristics();
Expand Down Expand Up @@ -338,7 +325,7 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
}

// Copy the object:
NOT_PRODUCT(evac_tracker()->begin_evacuation(thread, size * HeapWordSize));
NOT_PRODUCT(evac_tracker()->begin_evacuation(thread, size * HeapWordSize, from_region->affiliation(), target_gen));
Copy::aligned_disjoint_words(cast_from_oop<HeapWord*>(p), copy, size);
oop copy_val = cast_to_oop(copy);

Expand All @@ -360,7 +347,7 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena
ContinuationGCSupport::relativize_stack_chunk(copy_val);

// Record that the evacuation succeeded
NOT_PRODUCT(evac_tracker()->end_evacuation(thread, size * HeapWordSize));
NOT_PRODUCT(evac_tracker()->end_evacuation(thread, size * HeapWordSize, from_region->affiliation(), target_gen));

if (target_gen == OLD_GENERATION) {
old_generation()->handle_evacuation(copy, size, from_region->is_young());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class ShenandoahGenerationalControlThread;
class ShenandoahAgeCensus;

class ShenandoahGenerationalHeap : public ShenandoahHeap {
void print_tracing_info() const override;
void stop() override;

public:
Expand Down Expand Up @@ -66,8 +65,6 @@ class ShenandoahGenerationalHeap : public ShenandoahHeap {
ShenandoahSharedFlag _is_aging_cycle;
// Age census used for adapting tenuring threshold
ShenandoahAgeCensus* _age_census;
// Used primarily to look for failed evacuation attempts.
ShenandoahEvacuationTracker* _evac_tracker;

public:
void set_aging_cycle(bool cond) {
Expand All @@ -83,9 +80,6 @@ class ShenandoahGenerationalHeap : public ShenandoahHeap {
return _age_census;
}

ShenandoahEvacuationTracker* evac_tracker() const {
return _evac_tracker;
}

// Ages regions that haven't been used for allocations in the current cycle.
// Resets ages for regions that have been used for allocations.
Expand Down
12 changes: 11 additions & 1 deletion src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,8 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) :
_bitmap_region_special(false),
_aux_bitmap_region_special(false),
_liveness_cache(nullptr),
_collection_set(nullptr)
_collection_set(nullptr),
_evac_tracker(new ShenandoahEvacuationTracker())
{
// Initialize GC mode early, many subsequent initialization procedures depend on it
initialize_mode();
Expand Down Expand Up @@ -1352,6 +1353,7 @@ oop ShenandoahHeap::try_evacuate_object(oop p, Thread* thread, ShenandoahHeapReg
}

// Copy the object:
NOT_PRODUCT(evac_tracker()->begin_evacuation(thread, size * HeapWordSize, from_region->affiliation(), target_gen));
Copy::aligned_disjoint_words(cast_from_oop<HeapWord*>(p), copy, size);

// Try to install the new forwarding pointer.
Expand All @@ -1361,6 +1363,7 @@ oop ShenandoahHeap::try_evacuate_object(oop p, Thread* thread, ShenandoahHeapReg
// Successfully evacuated. Our copy is now the public one!
ContinuationGCSupport::relativize_stack_chunk(copy_val);
shenandoah_assert_correct(nullptr, copy_val);
NOT_PRODUCT(evac_tracker()->end_evacuation(thread, size * HeapWordSize, from_region->affiliation(), target_gen));
return copy_val;
} else {
// Failed to evacuate. We need to deal with the object that is left behind. Since this
Expand Down Expand Up @@ -1590,6 +1593,13 @@ void ShenandoahHeap::print_tracing_info() const {
ResourceMark rm;
LogStream ls(lt);

#ifdef NOT_PRODUCT
evac_tracker()->print_global_on(&ls);

ls.cr();
ls.cr();
#endif

phase_timings()->print_global_on(&ls);

ls.cr();
Expand Down
8 changes: 8 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,10 @@ class ShenandoahHeap : public CollectedHeap {

ShenandoahEvacOOMHandler* oom_evac_handler() { return &_oom_evac_handler; }

ShenandoahEvacuationTracker* evac_tracker() const {
return _evac_tracker;
}

void on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation);
void on_cycle_end(ShenandoahGeneration* generation);

Expand Down Expand Up @@ -789,6 +793,10 @@ class ShenandoahHeap : public CollectedHeap {

oop try_evacuate_object(oop src, Thread* thread, ShenandoahHeapRegion* from_region, ShenandoahAffiliation target_gen);

protected:
// Used primarily to look for failed evacuation attempts.
ShenandoahEvacuationTracker* _evac_tracker;

public:
static address in_cset_fast_test_addr();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ ShenandoahThreadLocalData::ShenandoahThreadLocalData() :
_plab_promoted(0),
_plab_allows_promotion(true),
_plab_retries_enabled(true),
_evacuation_stats(nullptr) {
if (ShenandoahHeap::heap()->mode()->is_generational()) {
_evacuation_stats = new ShenandoahEvacuationStats();
}
_evacuation_stats(new ShenandoahEvacuationStats()) {
}

ShenandoahThreadLocalData::~ShenandoahThreadLocalData() {
Expand Down
Loading