8336086: G1: Use one G1CardSet instance for all young regions

Reviewed-by: tschatzl, ayang
This commit is contained in:
Ivan Walulya 2024-08-15 08:26:22 +00:00
parent 4c344335fe
commit f536f5ab68
21 changed files with 173 additions and 33 deletions

View File

@ -244,6 +244,10 @@ class G1CardSetHashTable : public CHeapObj<mtGCCardSet> {
using CHTScanTask = CardSetHash::ScanTask;
const static uint BucketClaimSize = 16;
// The claim size for group cardsets should be smaller to facilitate
// better work distribution. The group cardsets should be larger than
// the per region cardsets.
const static uint GroupBucketClaimSize = 4;
// Did we insert at least one card in the table?
bool volatile _inserted_card;
@ -347,7 +351,15 @@ public:
}
void reset_table_scanner() {
_table_scanner.set(&_table, BucketClaimSize);
reset_table_scanner(BucketClaimSize);
}
void reset_table_scanner_for_groups() {
reset_table_scanner(GroupBucketClaimSize);
}
void reset_table_scanner(uint claim_size) {
_table_scanner.set(&_table, claim_size);
}
void grow() {
@ -1042,3 +1054,7 @@ void G1CardSet::clear() {
void G1CardSet::reset_table_scanner() {
_table->reset_table_scanner();
}
void G1CardSet::reset_table_scanner_for_groups() {
_table->reset_table_scanner_for_groups();
}

View File

@ -380,6 +380,8 @@ public:
void reset_table_scanner();
void reset_table_scanner_for_groups();
// Iterate over the container, calling a method on every card or card range contained
// in the card container.
// For every container, first calls

View File

@ -1159,6 +1159,8 @@ G1CollectedHeap::G1CollectedHeap() :
_rem_set(nullptr),
_card_set_config(),
_card_set_freelist_pool(G1CardSetConfiguration::num_mem_object_types()),
_young_regions_cardset_mm(card_set_config(), card_set_freelist_pool()),
_young_regions_cardset(card_set_config(), &_young_regions_cardset_mm),
_cm(nullptr),
_cm_thread(nullptr),
_cr(nullptr),
@ -2693,6 +2695,7 @@ bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) {
void G1CollectedHeap::set_region_short_lived_locked(G1HeapRegion* hr) {
_eden.add(hr);
_policy->set_region_eden(hr);
hr->install_group_cardset(young_regions_cardset());
}
#ifdef ASSERT
@ -2902,6 +2905,8 @@ G1HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegio
new_alloc_region->set_survivor();
_survivor.add(new_alloc_region);
register_new_survivor_region_with_region_attr(new_alloc_region);
// Install the group cardset.
new_alloc_region->install_group_cardset(young_regions_cardset());
} else {
new_alloc_region->set_old();
}
@ -3043,3 +3048,7 @@ void G1CollectedHeap::finish_codecache_marking_cycle() {
CodeCache::on_gc_marking_cycle_finish();
CodeCache::arm_all_nmethods();
}
void G1CollectedHeap::prepare_group_cardsets_for_scan () {
_young_regions_cardset.reset_table_scanner_for_groups();
}

View File

@ -779,7 +779,19 @@ private:
G1MonotonicArenaFreePool _card_set_freelist_pool;
// Group cardsets
G1CardSetMemoryManager _young_regions_cardset_mm;
G1CardSet _young_regions_cardset;
public:
G1CardSetConfiguration* card_set_config() { return &_card_set_config; }
G1CardSet* young_regions_cardset() { return &_young_regions_cardset; };
G1CardSetMemoryManager* young_regions_card_set_mm() { return &_young_regions_cardset_mm; }
void prepare_group_cardsets_for_scan();
// After a collection pause, reset eden and the collection set.
void clear_eden();
void clear_collection_set();

View File

@ -297,7 +297,7 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi
verify_young_cset_indices();
double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards);
double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards, _g1h->young_regions_cardset()->occupied());
// Base time already includes the whole remembered set related time, so do not add that here
// again.
double predicted_eden_time = _policy->predict_young_region_other_time_ms(eden_region_length) +

View File

@ -2980,6 +2980,7 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p
_total_capacity_bytes(0),
_total_live_bytes(0),
_total_remset_bytes(0),
_young_cardset_bytes_per_region(0),
_total_code_roots_bytes(0)
{
if (!log_is_enabled(Trace, gc, liveness)) {
@ -2990,6 +2991,13 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p
MemRegion reserved = g1h->reserved();
double now = os::elapsedTime();
uint num_young_regions = g1h->young_regions_count();
size_t young_cardset_bytes = g1h->young_regions_cardset()->mem_size();
if (num_young_regions > 0) {
_young_cardset_bytes_per_region = young_cardset_bytes / num_young_regions;
}
// Print the header of the output.
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now);
log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" HEAP"
@ -3041,6 +3049,10 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) {
const char* remset_type = r->rem_set()->get_short_state_str();
FormatBuffer<16> gc_efficiency("");
if (r->is_young()) {
remset_bytes = _young_cardset_bytes_per_region;
}
_total_used_bytes += used_bytes;
_total_capacity_bytes += capacity_bytes;
_total_live_bytes += live_bytes;

View File

@ -958,6 +958,8 @@ class G1PrintRegionLivenessInfoClosure : public G1HeapRegionClosure {
// Accumulator for the remembered set size
size_t _total_remset_bytes;
size_t _young_cardset_bytes_per_region;
// Accumulator for code roots memory size
size_t _total_code_roots_bytes;

View File

@ -254,21 +254,18 @@ uint64_t G1ConcurrentRefine::adjust_threads_wait_ms() const {
}
class G1ConcurrentRefine::RemSetSamplingClosure : public G1HeapRegionClosure {
size_t _sampled_card_rs_length;
size_t _sampled_code_root_rs_length;
public:
RemSetSamplingClosure() :
_sampled_card_rs_length(0), _sampled_code_root_rs_length(0) {}
_sampled_code_root_rs_length(0) {}
bool do_heap_region(G1HeapRegion* r) override {
G1HeapRegionRemSet* rem_set = r->rem_set();
_sampled_card_rs_length += rem_set->occupied();
_sampled_code_root_rs_length += rem_set->code_roots_list_length();
return false;
}
size_t sampled_card_rs_length() const { return _sampled_card_rs_length; }
size_t sampled_code_root_rs_length() const { return _sampled_code_root_rs_length; }
};
@ -286,10 +283,15 @@ public:
// gen size to keep pause time length goal.
void G1ConcurrentRefine::adjust_young_list_target_length() {
if (_policy->use_adaptive_young_list_length()) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1CollectionSet* cset = g1h->collection_set();
RemSetSamplingClosure cl;
G1CollectionSet* cset = G1CollectedHeap::heap()->collection_set();
cset->iterate(&cl);
_policy->revise_young_list_target_length(cl.sampled_card_rs_length(), cl.sampled_code_root_rs_length());
size_t card_rs_length = g1h->young_regions_cardset()->occupied();
size_t sampled_code_root_rs_length = cl.sampled_code_root_rs_length();
_policy->revise_young_list_target_length(card_rs_length, sampled_code_root_rs_length);
}
}

View File

@ -172,6 +172,7 @@ public:
bool do_heap_region(G1HeapRegion* hr) {
hr->prepare_for_full_gc();
hr->uninstall_group_cardset();
G1CollectedHeap::heap()->prepare_region_for_full_compaction(hr);
_collector->before_marking_update_attribute_table(hr);
return false;
@ -247,6 +248,8 @@ void G1FullCollector::complete_collection() {
_heap->resize_all_tlabs();
_heap->young_regions_cardset()->clear();
_heap->policy()->record_full_collection_end();
_heap->gc_epilogue(true);

View File

@ -119,6 +119,7 @@ void G1HeapRegion::hr_clear(bool clear_space) {
clear_young_index_in_cset();
clear_index_in_opt_cset();
uninstall_surv_rate_group();
uninstall_group_cardset();
set_free();
reset_pre_dummy_top();
@ -215,6 +216,9 @@ void G1HeapRegion::clear_humongous() {
}
void G1HeapRegion::prepare_remset_for_scan() {
if (is_young()) {
uninstall_group_cardset();
}
_rem_set->reset_table_scanner();
}

View File

@ -36,6 +36,7 @@
#include "runtime/mutex.hpp"
#include "utilities/macros.hpp"
class G1CardSet;
class G1CardSetConfiguration;
class G1CollectedHeap;
class G1CMBitMap;
@ -508,6 +509,9 @@ public:
void install_surv_rate_group(G1SurvRateGroup* surv_rate_group);
void uninstall_surv_rate_group();
void install_group_cardset(G1CardSet* group_cardset);
void uninstall_group_cardset();
void record_surv_words_in_group(size_t words_survived);
// Determine if an address is in the parsable or the to-be-scrubbed area.

View File

@ -511,4 +511,12 @@ inline void G1HeapRegion::add_pinned_object_count(size_t value) {
Atomic::add(&_pinned_object_count, value, memory_order_relaxed);
}
inline void G1HeapRegion::install_group_cardset(G1CardSet* group_cardset) {
_rem_set->install_group_cardset(group_cardset);
}
inline void G1HeapRegion::uninstall_group_cardset() {
_rem_set->uninstall_group_cardset();
}
#endif // SHARE_GC_G1_G1HEAPREGION_INLINE_HPP

View File

@ -55,11 +55,19 @@ void G1HeapRegionRemSet::initialize(MemRegion reserved) {
_heap_base_address = reserved.start();
}
void G1HeapRegionRemSet::uninstall_group_cardset() {
if (_saved_card_set != nullptr) {
_card_set = _saved_card_set;
_saved_card_set = nullptr;
}
}
G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion* hr,
G1CardSetConfiguration* config) :
_code_roots(),
_card_set_mm(config, G1CollectedHeap::heap()->card_set_freelist_pool()),
_card_set(config, &_card_set_mm),
_card_set(new G1CardSet(config, &_card_set_mm)),
_saved_card_set(nullptr),
_hr(hr),
_state(Untracked) { }
@ -68,11 +76,12 @@ void G1HeapRegionRemSet::clear_fcc() {
}
void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) {
assert(_saved_card_set == nullptr, "pre-condition");
if (!only_cardset) {
_code_roots.clear();
}
clear_fcc();
_card_set.clear();
_card_set->clear();
if (!keep_tracked) {
set_state_untracked();
} else {
@ -83,7 +92,7 @@ void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) {
void G1HeapRegionRemSet::reset_table_scanner() {
_code_roots.reset_table_scanner();
_card_set.reset_table_scanner();
_card_set->reset_table_scanner();
}
G1MonotonicArenaMemoryStats G1HeapRegionRemSet::card_set_memory_stats() const {

View File

@ -47,7 +47,8 @@ class G1HeapRegionRemSet : public CHeapObj<mtGC> {
G1CardSetMemoryManager _card_set_mm;
// The set of cards in the Java heap
G1CardSet _card_set;
G1CardSet* _card_set;
G1CardSet* _saved_card_set;
G1HeapRegion* _hr;
@ -58,9 +59,24 @@ class G1HeapRegionRemSet : public CHeapObj<mtGC> {
public:
G1HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config);
~G1HeapRegionRemSet() { delete _card_set; }
bool cardset_is_empty() const {
return _card_set.is_empty();
return _card_set->is_empty();
}
void install_group_cardset(G1CardSet* group_cardset) {
assert(group_cardset != nullptr, "pre-condition");
assert(_saved_card_set == nullptr, "pre-condition");
_saved_card_set = _card_set;
_card_set = group_cardset;
}
void uninstall_group_cardset();
bool has_group_cardset() {
return _saved_card_set != nullptr;
}
bool is_empty() const {
@ -68,7 +84,7 @@ public:
}
bool occupancy_less_or_equal_than(size_t occ) const {
return (code_roots_list_length() == 0) && _card_set.occupancy_less_or_equal_to(occ);
return (code_roots_list_length() == 0) && _card_set->occupancy_less_or_equal_to(occ);
}
// Iterate the card based remembered set for merging them into the card table.
@ -77,10 +93,15 @@ public:
template <class CardOrRangeVisitor>
inline void iterate_for_merge(CardOrRangeVisitor& cl);
template <class CardOrRangeVisitor>
inline static void iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl);
size_t occupied() {
return _card_set.occupied();
return _card_set->occupied();
}
G1CardSet* card_set() { return _card_set; }
static void initialize(MemRegion reserved);
// Coarsening statistics since VM start.
@ -125,13 +146,13 @@ public:
// The actual # of bytes this hr_remset takes up. Also includes the code
// root set.
size_t mem_size() {
return _card_set.mem_size()
return _card_set->mem_size()
+ (sizeof(G1HeapRegionRemSet) - sizeof(G1CardSet)) // Avoid double-counting G1CardSet.
+ code_roots_mem_size();
}
size_t unused_mem_size() {
return _card_set.unused_mem_size();
return _card_set->unused_mem_size();
}
// Returns the memory occupancy of all static data structures associated

View File

@ -108,13 +108,17 @@ public:
template <class CardOrRangeVisitor>
inline void G1HeapRegionRemSet::iterate_for_merge(CardOrRangeVisitor& cl) {
G1HeapRegionRemSetMergeCardClosure<CardOrRangeVisitor, G1ContainerCardsOrRanges> cl2(&_card_set,
cl,
_card_set.config()->log2_card_regions_per_heap_region(),
_card_set.config()->log2_cards_per_card_region());
_card_set.iterate_containers(&cl2, true /* at_safepoint */);
iterate_for_merge(_card_set, cl);
}
template <class CardOrRangeVisitor>
void G1HeapRegionRemSet::iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl) {
G1HeapRegionRemSetMergeCardClosure<CardOrRangeVisitor, G1ContainerCardsOrRanges> cl2(card_set,
cl,
card_set->config()->log2_card_regions_per_heap_region(),
card_set->config()->log2_cards_per_card_region());
card_set->iterate_containers(&cl2, true /* at_safepoint */);
}
uintptr_t G1HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const {
return pointer_delta(from, _heap_base_address, 1) >> CardTable::card_shift();
@ -130,18 +134,18 @@ void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) {
// We can't check whether the card is in the remembered set - the card container
// may be coarsened just now.
//assert(contains_reference(from), "We just found " PTR_FORMAT " in the FromCardCache", p2i(from));
return;
return;
}
_card_set.add_card(to_card(from));
_card_set->add_card(to_card(from));
}
bool G1HeapRegionRemSet::contains_reference(OopOrNarrowOopStar from) {
return _card_set.contains_card(to_card(from));
return _card_set->contains_card(to_card(from));
}
void G1HeapRegionRemSet::print_info(outputStream* st, OopOrNarrowOopStar from) {
_card_set.print_info(st, to_card(from));
_card_set->print_info(st, to_card(from));
}
#endif // SHARE_VM_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP

View File

@ -1089,6 +1089,11 @@ double G1Policy::predict_base_time_ms(size_t pending_cards,
double G1Policy::predict_base_time_ms(size_t pending_cards) const {
bool for_young_only_phase = collector_state()->in_young_only_phase();
size_t card_rs_length = _analytics->predict_card_rs_length(for_young_only_phase);
return predict_base_time_ms(pending_cards, card_rs_length);
}
double G1Policy::predict_base_time_ms(size_t pending_cards, size_t card_rs_length) const {
bool for_young_only_phase = collector_state()->in_young_only_phase();
size_t code_root_rs_length = _analytics->predict_code_root_rs_length(for_young_only_phase);
return predict_base_time_ms(pending_cards, card_rs_length, code_root_rs_length);
}

View File

@ -138,6 +138,8 @@ public:
double predict_base_time_ms(size_t pending_cards) const;
double predict_base_time_ms(size_t pending_cards, size_t card_rs_length) const;
private:
// Base time contains handling remembered sets and constant other time of the
// whole young gen, refinement buffers, and copying survivors.

View File

@ -1379,6 +1379,10 @@ public:
G1ClearBitmapClosure clear(g1h);
G1CombinedClosure combined(&merge, &clear);
if (_initial_evacuation) {
G1HeapRegionRemSet::iterate_for_merge(g1h->young_regions_cardset(), merge);
}
g1h->collection_set_iterate_increment_from(&combined, nullptr, worker_id);
G1MergeCardSetStats stats = merge.stats();

View File

@ -218,15 +218,24 @@ public:
bool do_heap_region(G1HeapRegion* r) {
G1HeapRegionRemSet* hrrs = r->rem_set();
size_t occupied_cards = hrrs->occupied();
// G1HeapRegionRemSet::mem_size() includes the
// size of the code roots
size_t rs_unused_mem_sz = hrrs->unused_mem_size();
size_t rs_mem_sz = hrrs->mem_size();
if (r->is_young()) {
uint num_young = G1CollectedHeap::heap()->young_regions_count();
occupied_cards /= num_young;
rs_unused_mem_sz /= num_young;
rs_mem_sz /= num_young;
}
if (rs_mem_sz > _max_rs_mem_sz) {
_max_rs_mem_sz = rs_mem_sz;
_max_rs_mem_sz_region = r;
}
size_t occupied_cards = hrrs->occupied();
size_t code_root_mem_sz = hrrs->code_roots_mem_size();
if (code_root_mem_sz > max_code_root_mem_sz()) {
_max_code_root_mem_sz = code_root_mem_sz;

View File

@ -295,10 +295,9 @@ class G1PrepareEvacuationTask : public WorkerTask {
G1MonotonicArenaMemoryStats _card_set_stats;
void sample_card_set_size(G1HeapRegion* hr) {
// Sample card set sizes for young gen and humongous before GC: this makes
// the policy to give back memory to the OS keep the most recent amount of
// memory for these regions.
if (hr->is_young() || hr->is_starts_humongous()) {
// Sample card set sizes for humongous before GC: this makes the policy to give
// back memory to the OS keep the most recent amount of memory for these regions.
if (hr->is_starts_humongous()) {
_card_set_stats.add(hr->rem_set()->card_set_memory_stats());
}
}
@ -507,6 +506,9 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info)
{
Ticks start = Ticks::now();
rem_set()->prepare_for_scan_heap_roots();
_g1h->prepare_group_cardsets_for_scan();
phase_times()->record_prepare_heap_roots_time_ms((Ticks::now() - start).seconds() * 1000.0);
}
@ -514,7 +516,10 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info)
G1PrepareEvacuationTask g1_prep_task(_g1h);
Tickspan task_time = run_task_timed(&g1_prep_task);
_g1h->set_young_gen_card_set_stats(g1_prep_task.all_card_set_stats());
G1MonotonicArenaMemoryStats sampled_card_set_stats = g1_prep_task.all_card_set_stats();
sampled_card_set_stats.add(_g1h->young_regions_card_set_mm()->memory_stats());
_g1h->set_young_gen_card_set_stats(sampled_card_set_stats);
_g1h->set_humongous_stats(g1_prep_task.humongous_total(), g1_prep_task.humongous_candidates());
phase_times()->record_register_regions(task_time.seconds() * 1000.0);

View File

@ -673,6 +673,10 @@ public:
G1Policy *policy = g1h->policy();
policy->old_gen_alloc_tracker()->add_allocated_bytes_since_last_gc(_bytes_allocated_in_old_since_last_gc);
// Add the cards from the group cardsets.
_card_rs_length += g1h->young_regions_cardset()->occupied();
policy->record_card_rs_length(_card_rs_length);
policy->cset_regions_freed();
}
@ -822,9 +826,10 @@ public:
JFREventForRegion event(r, _worker_id);
TimerForRegion timer(timer_for_region(r));
stats()->account_card_rs_length(r);
if (r->is_young()) {
// We only use card_rs_length statistics to estimate young regions length.
stats()->account_card_rs_length(r);
assert_tracks_surviving_words(r);
r->record_surv_words_in_group(_surviving_young_words[r->young_index_in_cset()]);
}
@ -911,6 +916,8 @@ public:
p->record_serial_free_cset_time_ms((Ticks::now() - serial_time).seconds() * 1000.0);
_g1h->clear_collection_set();
_g1h->young_regions_cardset()->clear();
}
double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->region_length(); }