Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
99698ad
Reset bitmap after collection
pengxiaolong Dec 7, 2024
a8948cf
Use template class for ShenandoahResetBitmapClosure
pengxiaolong Dec 16, 2024
11fdb12
Remove _generation from ShenandoahResetBitmapClosure
pengxiaolong Dec 17, 2024
859f937
Remove assert
pengxiaolong Dec 17, 2024
bc278bd
Remove ShenandoahPrepareForMarkClosure used by ShenandoahFullGC
pengxiaolong Dec 17, 2024
145a090
Merge Concurrent reset (Old) into Concurrent reset
pengxiaolong Dec 17, 2024
a689932
Renaming, comments, cleanup
pengxiaolong Dec 18, 2024
b43b10d
Not invoke set_mark_incomplete when reset bitmap after cycle
pengxiaolong Dec 18, 2024
450ab17
Not reset_mark_bitmap after cycle when is_concurrent_old_mark_in_pro…
pengxiaolong Dec 20, 2024
ae6843e
fix
pengxiaolong Dec 20, 2024
f71d7d5
Add comments
pengxiaolong Dec 20, 2024
022ac7b
Fix
pengxiaolong Dec 20, 2024
cf9e0a5
Always set_mark_incomplete when reset mark bitmap
pengxiaolong Dec 20, 2024
1f748c0
Remove ShenandoahResetUpdateRegionStateClosure
pengxiaolong Dec 20, 2024
2b9f28a
Merge branch 'openjdk:master' into reset-bitmap
pengxiaolong Dec 20, 2024
36f1483
Address review comments
pengxiaolong Dec 25, 2024
f82fdfa
Merge branch 'openjdk:master' into reset-bitmap
pengxiaolong Dec 30, 2024
4ae220f
Remove condition check !_do_old_gc_bootstrap && !heap->is_concurrent_…
pengxiaolong Jan 8, 2025
6b4a892
Remove entry_reset_after_collect from ShenandoahOldGC
pengxiaolong Jan 8, 2025
04299a7
Adding condition "!_do_old_gc_bootstrap && !heap->is_concurrent_old_m…
pengxiaolong Jan 9, 2025
5a18147
Merge branch 'openjdk:master' into reset-bitmap
pengxiaolong Jan 10, 2025
9e7f342
Merge branch 'openjdk:master' into reset-bitmap
pengxiaolong Jan 14, 2025
92c6315
Merge branch 'openjdk:master' into reset-bitmap
pengxiaolong Jan 15, 2025
c7e9bff
Merge branch 'openjdk:master' into reset-bitmap
pengxiaolong Feb 14, 2025
7eea955
Merge branch 'openjdk:master' into reset-bitmap
pengxiaolong Feb 28, 2025
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
64 changes: 52 additions & 12 deletions src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) {
if (heap->mode()->is_generational()) {
ShenandoahGenerationalHeap::heap()->complete_concurrent_cycle();
}

// Instead of always resetting immediately before the start of a new GC, we can often reset at the end of the
// previous GC. This allows us to start the next GC cycle more quickly after a trigger condition is detected,
// reducing the likelihood that GC will degenerate.
entry_reset_after_collect();

return true;
}

Expand Down Expand Up @@ -363,17 +369,6 @@ void ShenandoahConcurrentGC::entry_reset() {
msg);
op_reset();
}

if (_do_old_gc_bootstrap) {
static const char* msg = "Concurrent reset (Old)";
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset_old);
ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(),
ShenandoahWorkerPolicy::calc_workers_for_conc_reset(),
msg);
EventMark em("%s", msg);

heap->old_generation()->prepare_gc();
}
}

void ShenandoahConcurrentGC::entry_scan_remembered_set() {
Expand Down Expand Up @@ -583,12 +578,29 @@ void ShenandoahConcurrentGC::entry_cleanup_complete() {
op_cleanup_complete();
}

void ShenandoahConcurrentGC::entry_reset_after_collect() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
const char* msg = conc_reset_after_collect_event_message();
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset_after_collect);
EventMark em("%s", msg);

op_reset_after_collect();
}

void ShenandoahConcurrentGC::op_reset() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
if (ShenandoahPacing) {
heap->pacer()->setup_for_reset();
}
_generation->prepare_gc();
// If it is old GC bootstrap cycle, always clear bitmap for global gen
// to ensure bitmap for old gen is clear for old GC cycle after this.
if (_do_old_gc_bootstrap) {
assert(!heap->is_prepare_for_old_mark_in_progress(), "Cannot reset old without making it parsable");
heap->global_generation()->prepare_gc();
} else {
_generation->prepare_gc();
}
}

class ShenandoahInitMarkUpdateRegionStateClosure : public ShenandoahHeapRegionClosure {
Expand Down Expand Up @@ -1211,6 +1223,26 @@ void ShenandoahConcurrentGC::op_cleanup_complete() {
ShenandoahHeap::heap()->recycle_trash();
}

void ShenandoahConcurrentGC::op_reset_after_collect() {
ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(),
ShenandoahWorkerPolicy::calc_workers_for_conc_reset(),
"reset after collection.");

ShenandoahHeap* const heap = ShenandoahHeap::heap();
if (heap->mode()->is_generational()) {
// Resetting bitmaps of young gen when bootstrap old GC or there is preempted old GC
// causes crash due to remembered set violation, hence condition is added to fix the crash.
// Assuming bitmaps of young gen are not used at all after the cycle, the crash should not
// have happend, it seems to tickle a bug in remembered set scan. Root causing and fixing of the bug
// will be tracked via ticket https://bugs.openjdk.org/browse/JDK-8347371
if (!_do_old_gc_bootstrap && !heap->is_concurrent_old_mark_in_progress()) {
heap->young_generation()->reset_mark_bitmap<false>();
}
} else {
_generation->reset_mark_bitmap<false>();
}
}

bool ShenandoahConcurrentGC::check_cancellation_and_abort(ShenandoahDegenPoint point) {
if (ShenandoahHeap::heap()->cancelled_gc()) {
_degen_point = point;
Expand Down Expand Up @@ -1260,6 +1292,14 @@ const char* ShenandoahConcurrentGC::conc_reset_event_message() const {
}
}

const char* ShenandoahConcurrentGC::conc_reset_after_collect_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", " (unload classes)");
} else {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", "");
}
}

const char* ShenandoahConcurrentGC::final_roots_event_message() const {
if (ShenandoahHeap::heap()->unload_classes()) {
SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Final Roots", " (unload classes)");
Expand Down
5 changes: 5 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,14 @@ class ShenandoahConcurrentGC : public ShenandoahGC {
void op_final_update_refs();
void op_final_roots();
void op_cleanup_complete();
void op_reset_after_collect();

// Check GC cancellation and abort concurrent GC
bool check_cancellation_and_abort(ShenandoahDegenPoint point);

// Called when concurrent GC succeeds.
void entry_reset_after_collect();

private:
void start_mark();

Expand All @@ -134,6 +138,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC {
const char* final_roots_event_message() const;
const char* conc_mark_event_message() const;
const char* conc_reset_event_message() const;
const char* conc_reset_after_collect_event_message() const;
const char* conc_weak_refs_event_message() const;
const char* conc_weak_roots_event_message() const;
const char* conc_cleanup_event_message() const;
Expand Down
30 changes: 5 additions & 25 deletions src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,16 +197,11 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) {
update_roots(true /*full_gc*/);
}

// d. Reset the bitmaps for new marking
heap->global_generation()->reset_mark_bitmap();
assert(heap->marking_context()->is_bitmap_clear(), "sanity");
assert(!heap->global_generation()->is_mark_complete(), "sanity");

// e. Abandon reference discovery and clear all discovered references.
// d. Abandon reference discovery and clear all discovered references.
ShenandoahReferenceProcessor* rp = heap->global_generation()->ref_processor();
rp->abandon_partial_discovery();

// f. Sync pinned region status from the CP marks
// e. Sync pinned region status from the CP marks
heap->sync_pinned_region_status();

if (heap->mode()->is_generational()) {
Expand Down Expand Up @@ -287,30 +282,15 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) {
}
}

class ShenandoahPrepareForMarkClosure: public ShenandoahHeapRegionClosure {
private:
ShenandoahMarkingContext* const _ctx;

public:
ShenandoahPrepareForMarkClosure() : _ctx(ShenandoahHeap::heap()->marking_context()) {}

void heap_region_do(ShenandoahHeapRegion *r) override {
_ctx->capture_top_at_mark_start(r);
r->clear_live_data();
}

bool is_thread_safe() override { return true; }
};

void ShenandoahFullGC::phase1_mark_heap() {
GCTraceTime(Info, gc, phases) time("Phase 1: Mark live objects", _gc_timer);
ShenandoahGCPhase mark_phase(ShenandoahPhaseTimings::full_gc_mark);

ShenandoahHeap* heap = ShenandoahHeap::heap();

ShenandoahPrepareForMarkClosure prepare_for_mark;
ShenandoahExcludeRegionClosure<FREE> cl(&prepare_for_mark);
heap->parallel_heap_region_iterate(&cl);
heap->global_generation()->reset_mark_bitmap<true, true>();
assert(heap->marking_context()->is_bitmap_clear(), "sanity");
assert(!heap->global_generation()->is_mark_complete(), "sanity");

heap->set_unload_classes(heap->global_generation()->heuristics()->can_unload_classes());

Expand Down
83 changes: 37 additions & 46 deletions src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,53 +41,44 @@

#include "utilities/quickSort.hpp"


class ShenandoahResetUpdateRegionStateClosure : public ShenandoahHeapRegionClosure {
template <bool PREPARE_FOR_CURRENT_CYCLE, bool FULL_GC = false>
class ShenandoahResetBitmapClosure final : public ShenandoahHeapRegionClosure {
private:
ShenandoahHeap* _heap;
ShenandoahMarkingContext* const _ctx;
ShenandoahHeap* _heap;
ShenandoahMarkingContext* _ctx;

public:
ShenandoahResetUpdateRegionStateClosure() :
_heap(ShenandoahHeap::heap()),
_ctx(_heap->marking_context()) {}
explicit ShenandoahResetBitmapClosure() :
ShenandoahHeapRegionClosure(), _heap(ShenandoahHeap::heap()), _ctx(_heap->marking_context()) {}

void heap_region_do(ShenandoahHeapRegion* r) override {
if (r->is_active()) {
// Reset live data and set TAMS optimistically. We would recheck these under the pause
// anyway to capture any updates that happened since now.
_ctx->capture_top_at_mark_start(r);
r->clear_live_data();
void heap_region_do(ShenandoahHeapRegion* region) override {
assert(!_heap->is_uncommit_in_progress(), "Cannot uncommit bitmaps while resetting them.");
if (PREPARE_FOR_CURRENT_CYCLE) {
if (region->need_bitmap_reset() && _heap->is_bitmap_slice_committed(region)) {
_ctx->clear_bitmap(region);
} else {
region->set_needs_bitmap_reset();
}
// Capture Top At Mark Start for this generation.
if (FULL_GC || region->is_active()) {
// Reset live data and set TAMS optimistically. We would recheck these under the pause
// anyway to capture any updates that happened since now.
_ctx->capture_top_at_mark_start(region);
region->clear_live_data();
}
} else {
if (_heap->is_bitmap_slice_committed(region)) {
_ctx->clear_bitmap(region);
region->unset_needs_bitmap_reset();
} else {
region->set_needs_bitmap_reset();
}
}
}

bool is_thread_safe() override { return true; }
};

class ShenandoahResetBitmapTask : public WorkerTask {
private:
ShenandoahRegionIterator _regions;
ShenandoahGeneration* _generation;

public:
ShenandoahResetBitmapTask(ShenandoahGeneration* generation) :
WorkerTask("Shenandoah Reset Bitmap"), _generation(generation) {}

void work(uint worker_id) {
ShenandoahHeap* heap = ShenandoahHeap::heap();
assert(!heap->is_uncommit_in_progress(), "Cannot uncommit bitmaps while resetting them.");
ShenandoahHeapRegion* region = _regions.next();
ShenandoahMarkingContext* const ctx = heap->marking_context();
while (region != nullptr) {
auto const affiliation = region->affiliation();
bool needs_reset = affiliation == FREE || _generation->contains(affiliation);
if (needs_reset && heap->is_bitmap_slice_committed(region)) {
ctx->clear_bitmap(region);
}
region = _regions.next();
}
}
};

// Copy the write-version of the card-table into the read-version, clearing the
// write-copy.
class ShenandoahMergeWriteTable: public ShenandoahHeapRegionClosure {
Expand Down Expand Up @@ -225,15 +216,20 @@ void ShenandoahGeneration::log_status(const char *msg) const {
PROPERFMTARGS(v_soft_max_capacity), PROPERFMTARGS(v_max_capacity), PROPERFMTARGS(v_available));
}

template <bool PREPARE_FOR_CURRENT_CYCLE, bool FULL_GC>
void ShenandoahGeneration::reset_mark_bitmap() {
ShenandoahHeap* heap = ShenandoahHeap::heap();
heap->assert_gc_workers(heap->workers()->active_workers());

set_mark_incomplete();

ShenandoahResetBitmapTask task(this);
heap->workers()->run_task(&task);
ShenandoahResetBitmapClosure<PREPARE_FOR_CURRENT_CYCLE, FULL_GC> closure;
parallel_heap_region_iterate_free(&closure);
}
// Explicit specializations
template void ShenandoahGeneration::reset_mark_bitmap<true, false>();
template void ShenandoahGeneration::reset_mark_bitmap<true, true>();
template void ShenandoahGeneration::reset_mark_bitmap<false, false>();

// The ideal is to swap the remembered set so the safepoint effort is no more than a few pointer manipulations.
// However, limitations in the implementation of the mutator write-barrier make it difficult to simply change the
Expand Down Expand Up @@ -265,12 +261,7 @@ void ShenandoahGeneration::merge_write_table() {
}

void ShenandoahGeneration::prepare_gc() {

reset_mark_bitmap();

// Capture Top At Mark Start for this generation (typically young) and reset mark bitmap.
ShenandoahResetUpdateRegionStateClosure cl;
parallel_heap_region_iterate_free(&cl);
reset_mark_bitmap<true>();
}

void ShenandoahGeneration::parallel_heap_region_iterate_free(ShenandoahHeapRegionClosure* cl) {
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ class ShenandoahGeneration : public CHeapObj<mtGC>, public ShenandoahSpaceInfo {
void log_status(const char* msg) const;

// Used directly by FullGC
template <bool FOR_CURRENT_CYCLE, bool FULL_GC = false>
void reset_mark_bitmap();

// Used by concurrent and degenerated GC to reset remembered set.
Expand Down
5 changes: 3 additions & 2 deletions src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@ ShenandoahHeapRegion::ShenandoahHeapRegion(HeapWord* start, size_t index, bool c
_live_data(0),
_critical_pins(0),
_update_watermark(start),
_age(0)
_age(0),
#ifdef SHENANDOAH_CENSUS_NOISE
, _youth(0)
_youth(0),
#endif // SHENANDOAH_CENSUS_NOISE
_needs_bitmap_reset(false)
{

assert(Universe::on_page_boundary(_bottom) && Universe::on_page_boundary(_end),
Expand Down
14 changes: 14 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ class ShenandoahHeapRegion {

ShenandoahSharedFlag _recycling; // Used to indicate that the region is being recycled; see try_recycle*().

bool _needs_bitmap_reset;

public:
ShenandoahHeapRegion(HeapWord* start, size_t index, bool committed);

Expand Down Expand Up @@ -477,6 +479,18 @@ class ShenandoahHeapRegion {

CENSUS_NOISE(void clear_youth() { _youth = 0; })

inline bool need_bitmap_reset() const {
return _needs_bitmap_reset;
}

inline void set_needs_bitmap_reset() {
_needs_bitmap_reset = true;
}

inline void unset_needs_bitmap_reset() {
_needs_bitmap_reset = false;
}

private:
void decrement_humongous_waste() const;
void do_commit();
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class outputStream;

#define SHENANDOAH_PHASE_DO(f) \
f(conc_reset, "Concurrent Reset") \
f(conc_reset_after_collect, "Concurrent Reset After Collect") \
f(conc_reset_old, "Concurrent Reset (OLD)") \
f(init_mark_gross, "Pause Init Mark (G)") \
f(init_mark, "Pause Init Mark (N)") \
Expand Down