8226232: Move merge heap roots code out from G1RemSetScanState

Reviewed-by: sangheki, kbarrett
This commit is contained in:
Thomas Schatzl 2019-07-17 16:33:19 +02:00
parent 20053ae242
commit bb7bf64fd7
2 changed files with 311 additions and 298 deletions

View File

@ -183,259 +183,6 @@ private:
}
};
// Returns whether the given region contains cards we need to scan. The remembered
// set and other sources may contain cards that
// - are in uncommitted regions
// - are located in the collection set
// - are located in free regions
// as we do not clean up remembered sets before merging heap roots.
bool contains_cards_to_process(uint const region_idx) const {
HeapRegion* hr = G1CollectedHeap::heap()->region_at_or_null(region_idx);
return (hr != NULL && !hr->in_collection_set() && hr->is_old_or_humongous_or_archive());
}
class G1MergeCardSetClosure : public HeapRegionClosure {
G1RemSetScanState* _scan_state;
G1CardTable* _ct;
uint _merged_sparse;
uint _merged_fine;
uint _merged_coarse;
// Returns if the region contains cards we need to scan. If so, remember that
// region in the current set of dirty regions.
bool remember_if_interesting(uint const region_idx) {
if (!_scan_state->contains_cards_to_process(region_idx)) {
return false;
}
_scan_state->add_dirty_region(region_idx);
return true;
}
public:
G1MergeCardSetClosure(G1RemSetScanState* scan_state) :
_scan_state(scan_state),
_ct(G1CollectedHeap::heap()->card_table()),
_merged_sparse(0),
_merged_fine(0),
_merged_coarse(0) { }
void next_coarse_prt(uint const region_idx) {
if (!remember_if_interesting(region_idx)) {
return;
}
_merged_coarse++;
size_t region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion;
_ct->mark_region_dirty(region_base_idx, HeapRegion::CardsPerRegion);
_scan_state->set_chunk_region_dirty(region_base_idx);
}
void next_fine_prt(uint const region_idx, BitMap* bm) {
if (!remember_if_interesting(region_idx)) {
return;
}
_merged_fine++;
size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion;
BitMap::idx_t cur = bm->get_next_one_offset(0);
while (cur != bm->size()) {
_ct->mark_clean_as_dirty(region_base_idx + cur);
_scan_state->set_chunk_dirty(region_base_idx + cur);
cur = bm->get_next_one_offset(cur + 1);
}
}
void next_sparse_prt(uint const region_idx, SparsePRTEntry::card_elem_t* cards, uint const num_cards) {
if (!remember_if_interesting(region_idx)) {
return;
}
_merged_sparse++;
size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion;
for (uint i = 0; i < num_cards; i++) {
size_t card_idx = region_base_idx + cards[i];
_ct->mark_clean_as_dirty(card_idx);
_scan_state->set_chunk_dirty(card_idx);
}
}
virtual bool do_heap_region(HeapRegion* r) {
assert(r->in_collection_set() || r->is_starts_humongous(), "must be");
HeapRegionRemSet* rem_set = r->rem_set();
if (!rem_set->is_empty()) {
rem_set->iterate_prts(*this);
}
return false;
}
size_t merged_sparse() const { return _merged_sparse; }
size_t merged_fine() const { return _merged_fine; }
size_t merged_coarse() const { return _merged_coarse; }
};
// Visitor for the remembered sets of humongous candidate regions to merge their
// remembered set into the card table.
class G1FlushHumongousCandidateRemSets : public HeapRegionClosure {
G1MergeCardSetClosure _cl;
public:
G1FlushHumongousCandidateRemSets(G1RemSetScanState* scan_state) : _cl(scan_state) { }
virtual bool do_heap_region(HeapRegion* r) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
if (!r->is_starts_humongous() ||
!g1h->region_attr(r->hrm_index()).is_humongous() ||
r->rem_set()->is_empty()) {
return false;
}
guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries),
"Found a not-small remembered set here. This is inconsistent with previous assumptions.");
_cl.do_heap_region(r);
// We should only clear the card based remembered set here as we will not
// implicitly rebuild anything else during eager reclaim. Note that at the moment
// (and probably never) we do not enter this path if there are other kind of
// remembered sets for this region.
r->rem_set()->clear_locked(true /* only_cardset */);
// Clear_locked() above sets the state to Empty. However we want to continue
// collecting remembered set entries for humongous regions that were not
// reclaimed.
r->rem_set()->set_state_complete();
#ifdef ASSERT
G1HeapRegionAttr region_attr = g1h->region_attr(r->hrm_index());
assert(region_attr.needs_remset_update(), "must be");
#endif
assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
return false;
}
size_t merged_sparse() const { return _cl.merged_sparse(); }
size_t merged_fine() const { return _cl.merged_fine(); }
size_t merged_coarse() const { return _cl.merged_coarse(); }
};
// Visitor for the log buffer entries to merge them into the card table.
class G1MergeLogBufferCardsClosure : public G1CardTableEntryClosure {
G1RemSetScanState* _scan_state;
G1CardTable* _ct;
size_t _cards_dirty;
size_t _cards_skipped;
public:
G1MergeLogBufferCardsClosure(G1CollectedHeap* g1h, G1RemSetScanState* scan_state) :
_scan_state(scan_state), _ct(g1h->card_table()), _cards_dirty(0), _cards_skipped(0)
{}
bool do_card_ptr(CardValue* card_ptr, uint worker_i) {
// The only time we care about recording cards that
// contain references that point into the collection set
// is during RSet updating within an evacuation pause.
// In this case worker_id should be the id of a GC worker thread.
assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause");
uint const region_idx = _ct->region_idx_for(card_ptr);
// The second clause must come after - the log buffers might contain cards to uncommited
// regions.
// This code may count duplicate entries in the log buffers (even if rare) multiple
// times.
if (_scan_state->contains_cards_to_process(region_idx) && (*card_ptr == G1CardTable::dirty_card_val())) {
_scan_state->add_dirty_region(region_idx);
_scan_state->set_chunk_dirty(_ct->index_for_cardvalue(card_ptr));
_cards_dirty++;
} else {
// We may have had dirty cards in the (initial) collection set (or the
// young regions which are always in the initial collection set). We do
// not fix their cards here: we already added these regions to the set of
// regions to clear the card table at the end during the prepare() phase.
_cards_skipped++;
}
return true;
}
size_t cards_dirty() const { return _cards_dirty; }
size_t cards_skipped() const { return _cards_skipped; }
};
class G1MergeHeapRootsTask : public AbstractGangTask {
HeapRegionClaimer _hr_claimer;
G1RemSetScanState* _scan_state;
bool _remembered_set_only;
G1GCPhaseTimes::GCParPhases _merge_phase;
volatile bool _fast_reclaim_handled;
public:
G1MergeHeapRootsTask(G1RemSetScanState* scan_state, uint num_workers, bool remembered_set_only, G1GCPhaseTimes::GCParPhases merge_phase) :
AbstractGangTask("G1 Merge Heap Roots"),
_hr_claimer(num_workers),
_scan_state(scan_state),
_remembered_set_only(remembered_set_only),
_merge_phase(merge_phase),
_fast_reclaim_handled(false) { }
virtual void work(uint worker_id) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1GCPhaseTimes* p = g1h->phase_times();
// We schedule flushing the remembered sets of humongous fast reclaim candidates
// onto the card table first to allow the remaining parallelized tasks hide it.
if (!_remembered_set_only &&
p->fast_reclaim_humongous_candidates() > 0 &&
!_fast_reclaim_handled &&
!Atomic::cmpxchg(true, &_fast_reclaim_handled, false)) {
G1FlushHumongousCandidateRemSets cl(_scan_state);
g1h->heap_region_iterate(&cl);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse);
}
// Merge remembered sets of current candidates.
{
G1GCParPhaseTimesTracker x(p, _merge_phase, worker_id, !_remembered_set_only /* must_record */);
G1MergeCardSetClosure cl(_scan_state);
g1h->collection_set_iterate_increment_from(&cl, &_hr_claimer, worker_id);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse);
}
// Apply closure to log entries in the HCC.
if (!_remembered_set_only && G1HotCardCache::default_use_cache()) {
assert(_merge_phase == G1GCPhaseTimes::MergeRS, "Wrong merge phase");
G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeHCC, worker_id);
G1MergeLogBufferCardsClosure cl(g1h, _scan_state);
g1h->iterate_hcc_closure(&cl, worker_id);
}
// Now apply the closure to all remaining log entries.
if (!_remembered_set_only) {
assert(_merge_phase == G1GCPhaseTimes::MergeRS, "Wrong merge phase");
G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeLB, worker_id);
G1MergeLogBufferCardsClosure cl(g1h, _scan_state);
g1h->iterate_dirty_card_closure(&cl, worker_id);
p->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_id, cl.cards_dirty(), G1GCPhaseTimes::MergeLBDirtyCards);
p->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_id, cl.cards_skipped(), G1GCPhaseTimes::MergeLBSkippedCards);
}
}
};
// Creates a snapshot of the current _top values at the start of collection to
// filter out card marks that we do not want to scan.
class G1ResetScanTopClosure : public HeapRegionClosure {
@ -571,61 +318,46 @@ public:
}
_all_dirty_regions = new G1DirtyRegions(_max_regions);
_next_dirty_regions = new G1DirtyRegions(_max_regions);
G1ResetScanTopClosure cl(this);
G1CollectedHeap::heap()->heap_region_iterate(&cl);
_next_dirty_regions = new G1DirtyRegions(_max_regions);
}
void print_merge_heap_roots_stats() {
size_t num_scan_chunks = 0;
void prepare_for_merge_heap_roots() {
_all_dirty_regions->merge(_next_dirty_regions);
_next_dirty_regions->reset();
for (size_t i = 0; i < _max_regions; i++) {
_card_table_scan_state[i] = 0;
}
::memset(_region_scan_chunks, false, _max_regions * _scan_chunks_per_region * sizeof(*_region_scan_chunks));
}
// Returns whether the given region contains cards we need to scan. The remembered
// set and other sources may contain cards that
// - are in uncommitted regions
// - are located in the collection set
// - are located in free regions
// as we do not clean up remembered sets before merging heap roots.
bool contains_cards_to_process(uint const region_idx) const {
HeapRegion* hr = G1CollectedHeap::heap()->region_at_or_null(region_idx);
return (hr != NULL && !hr->in_collection_set() && hr->is_old_or_humongous_or_archive());
}
size_t num_visited_cards() const {
size_t result = 0;
for (uint i = 0; i < _max_regions * _scan_chunks_per_region; i++) {
if (_region_scan_chunks[i]) {
num_scan_chunks++;
result++;
}
}
size_t num_visited_cards = num_scan_chunks * CardsPerChunk;
size_t total_dirty_region_cards = _next_dirty_regions->size() * HeapRegion::CardsPerRegion;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
size_t total_old_region_cards =
(g1h->num_regions() - (g1h->num_free_regions() - g1h->collection_set()->cur_length())) * HeapRegion::CardsPerRegion;
log_debug(gc,remset)("Visited cards " SIZE_FORMAT " Total dirty " SIZE_FORMAT " (%.2lf%%) Total old " SIZE_FORMAT " (%.2lf%%)",
num_visited_cards,
total_dirty_region_cards,
percent_of(num_visited_cards, total_dirty_region_cards),
total_old_region_cards,
percent_of(num_visited_cards, total_old_region_cards));
return result * CardsPerChunk;
}
void merge_heap_roots(WorkGang* workers, bool remembered_set_only, G1GCPhaseTimes::GCParPhases merge_phase) {
{
_all_dirty_regions->merge(_next_dirty_regions);
_next_dirty_regions->reset();
for (size_t i = 0; i < _max_regions; i++) {
_card_table_scan_state[i] = 0;
}
::memset(_region_scan_chunks, false, _max_regions * _scan_chunks_per_region * sizeof(*_region_scan_chunks));
}
size_t const increment_length = G1CollectedHeap::heap()->collection_set()->increment_length();
uint const num_workers = !remembered_set_only ? workers->active_workers() :
MIN2(workers->active_workers(), (uint)increment_length);
{
G1MergeHeapRootsTask cl(this, num_workers, remembered_set_only, merge_phase);
log_debug(gc, ergo)("Running %s using %u workers for " SIZE_FORMAT " regions",
cl.name(), num_workers, increment_length);
workers->run_task(&cl, num_workers);
}
if (log_is_enabled(Debug, gc, remset)) {
print_merge_heap_roots_stats();
}
size_t num_cards_in_dirty_regions() const {
return _next_dirty_regions->size() * HeapRegion::CardsPerRegion;
}
void set_chunk_region_dirty(size_t const region_card_idx) {
@ -1169,8 +901,288 @@ void G1RemSet::prepare_for_scan_heap_roots() {
_scan_state->prepare();
}
class G1MergeHeapRootsTask : public AbstractGangTask {
// Visitor for remembered sets, dropping entries onto the card table.
class G1MergeCardSetClosure : public HeapRegionClosure {
G1RemSetScanState* _scan_state;
G1CardTable* _ct;
uint _merged_sparse;
uint _merged_fine;
uint _merged_coarse;
// Returns if the region contains cards we need to scan. If so, remember that
// region in the current set of dirty regions.
bool remember_if_interesting(uint const region_idx) {
if (!_scan_state->contains_cards_to_process(region_idx)) {
return false;
}
_scan_state->add_dirty_region(region_idx);
return true;
}
public:
G1MergeCardSetClosure(G1RemSetScanState* scan_state) :
_scan_state(scan_state),
_ct(G1CollectedHeap::heap()->card_table()),
_merged_sparse(0),
_merged_fine(0),
_merged_coarse(0) { }
void next_coarse_prt(uint const region_idx) {
if (!remember_if_interesting(region_idx)) {
return;
}
_merged_coarse++;
size_t region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion;
_ct->mark_region_dirty(region_base_idx, HeapRegion::CardsPerRegion);
_scan_state->set_chunk_region_dirty(region_base_idx);
}
void next_fine_prt(uint const region_idx, BitMap* bm) {
if (!remember_if_interesting(region_idx)) {
return;
}
_merged_fine++;
size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion;
BitMap::idx_t cur = bm->get_next_one_offset(0);
while (cur != bm->size()) {
_ct->mark_clean_as_dirty(region_base_idx + cur);
_scan_state->set_chunk_dirty(region_base_idx + cur);
cur = bm->get_next_one_offset(cur + 1);
}
}
void next_sparse_prt(uint const region_idx, SparsePRTEntry::card_elem_t* cards, uint const num_cards) {
if (!remember_if_interesting(region_idx)) {
return;
}
_merged_sparse++;
size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion;
for (uint i = 0; i < num_cards; i++) {
size_t card_idx = region_base_idx + cards[i];
_ct->mark_clean_as_dirty(card_idx);
_scan_state->set_chunk_dirty(card_idx);
}
}
virtual bool do_heap_region(HeapRegion* r) {
assert(r->in_collection_set() || r->is_starts_humongous(), "must be");
HeapRegionRemSet* rem_set = r->rem_set();
if (!rem_set->is_empty()) {
rem_set->iterate_prts(*this);
}
return false;
}
size_t merged_sparse() const { return _merged_sparse; }
size_t merged_fine() const { return _merged_fine; }
size_t merged_coarse() const { return _merged_coarse; }
};
// Visitor for the remembered sets of humongous candidate regions to merge their
// remembered set into the card table.
class G1FlushHumongousCandidateRemSets : public HeapRegionClosure {
G1MergeCardSetClosure _cl;
public:
G1FlushHumongousCandidateRemSets(G1RemSetScanState* scan_state) : _cl(scan_state) { }
virtual bool do_heap_region(HeapRegion* r) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
if (!r->is_starts_humongous() ||
!g1h->region_attr(r->hrm_index()).is_humongous() ||
r->rem_set()->is_empty()) {
return false;
}
guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries),
"Found a not-small remembered set here. This is inconsistent with previous assumptions.");
_cl.do_heap_region(r);
// We should only clear the card based remembered set here as we will not
// implicitly rebuild anything else during eager reclaim. Note that at the moment
// (and probably never) we do not enter this path if there are other kind of
// remembered sets for this region.
r->rem_set()->clear_locked(true /* only_cardset */);
// Clear_locked() above sets the state to Empty. However we want to continue
// collecting remembered set entries for humongous regions that were not
// reclaimed.
r->rem_set()->set_state_complete();
#ifdef ASSERT
G1HeapRegionAttr region_attr = g1h->region_attr(r->hrm_index());
assert(region_attr.needs_remset_update(), "must be");
#endif
assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
return false;
}
size_t merged_sparse() const { return _cl.merged_sparse(); }
size_t merged_fine() const { return _cl.merged_fine(); }
size_t merged_coarse() const { return _cl.merged_coarse(); }
};
// Visitor for the log buffer entries to merge them into the card table.
class G1MergeLogBufferCardsClosure : public G1CardTableEntryClosure {
G1RemSetScanState* _scan_state;
G1CardTable* _ct;
size_t _cards_dirty;
size_t _cards_skipped;
public:
G1MergeLogBufferCardsClosure(G1CollectedHeap* g1h, G1RemSetScanState* scan_state) :
_scan_state(scan_state), _ct(g1h->card_table()), _cards_dirty(0), _cards_skipped(0)
{}
bool do_card_ptr(CardValue* card_ptr, uint worker_i) {
// The only time we care about recording cards that
// contain references that point into the collection set
// is during RSet updating within an evacuation pause.
// In this case worker_id should be the id of a GC worker thread.
assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause");
uint const region_idx = _ct->region_idx_for(card_ptr);
// The second clause must come after - the log buffers might contain cards to uncommited
// regions.
// This code may count duplicate entries in the log buffers (even if rare) multiple
// times.
if (_scan_state->contains_cards_to_process(region_idx) && (*card_ptr == G1CardTable::dirty_card_val())) {
_scan_state->add_dirty_region(region_idx);
_scan_state->set_chunk_dirty(_ct->index_for_cardvalue(card_ptr));
_cards_dirty++;
} else {
// We may have had dirty cards in the (initial) collection set (or the
// young regions which are always in the initial collection set). We do
// not fix their cards here: we already added these regions to the set of
// regions to clear the card table at the end during the prepare() phase.
_cards_skipped++;
}
return true;
}
size_t cards_dirty() const { return _cards_dirty; }
size_t cards_skipped() const { return _cards_skipped; }
};
HeapRegionClaimer _hr_claimer;
G1RemSetScanState* _scan_state;
bool _remembered_set_only;
G1GCPhaseTimes::GCParPhases _merge_phase;
volatile bool _fast_reclaim_handled;
public:
G1MergeHeapRootsTask(G1RemSetScanState* scan_state, uint num_workers, bool remembered_set_only, G1GCPhaseTimes::GCParPhases merge_phase) :
AbstractGangTask("G1 Merge Heap Roots"),
_hr_claimer(num_workers),
_scan_state(scan_state),
_remembered_set_only(remembered_set_only),
_merge_phase(merge_phase),
_fast_reclaim_handled(false) { }
virtual void work(uint worker_id) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1GCPhaseTimes* p = g1h->phase_times();
// We schedule flushing the remembered sets of humongous fast reclaim candidates
// onto the card table first to allow the remaining parallelized tasks hide it.
if (!_remembered_set_only &&
p->fast_reclaim_humongous_candidates() > 0 &&
!_fast_reclaim_handled &&
!Atomic::cmpxchg(true, &_fast_reclaim_handled, false)) {
G1FlushHumongousCandidateRemSets cl(_scan_state);
g1h->heap_region_iterate(&cl);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse);
}
// Merge remembered sets of current candidates.
{
G1GCParPhaseTimesTracker x(p, _merge_phase, worker_id, !_remembered_set_only /* must_record */);
G1MergeCardSetClosure cl(_scan_state);
g1h->collection_set_iterate_increment_from(&cl, &_hr_claimer, worker_id);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine);
p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse);
}
// Apply closure to log entries in the HCC.
if (!_remembered_set_only && G1HotCardCache::default_use_cache()) {
assert(_merge_phase == G1GCPhaseTimes::MergeRS, "Wrong merge phase");
G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeHCC, worker_id);
G1MergeLogBufferCardsClosure cl(g1h, _scan_state);
g1h->iterate_hcc_closure(&cl, worker_id);
}
// Now apply the closure to all remaining log entries.
if (!_remembered_set_only) {
assert(_merge_phase == G1GCPhaseTimes::MergeRS, "Wrong merge phase");
G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeLB, worker_id);
G1MergeLogBufferCardsClosure cl(g1h, _scan_state);
g1h->iterate_dirty_card_closure(&cl, worker_id);
p->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_id, cl.cards_dirty(), G1GCPhaseTimes::MergeLBDirtyCards);
p->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_id, cl.cards_skipped(), G1GCPhaseTimes::MergeLBSkippedCards);
}
}
};
void G1RemSet::print_merge_heap_roots_stats() {
size_t num_visited_cards = _scan_state->num_visited_cards();
size_t total_dirty_region_cards = _scan_state->num_cards_in_dirty_regions();
G1CollectedHeap* g1h = G1CollectedHeap::heap();
size_t total_old_region_cards =
(g1h->num_regions() - (g1h->num_free_regions() - g1h->collection_set()->cur_length())) * HeapRegion::CardsPerRegion;
log_debug(gc,remset)("Visited cards " SIZE_FORMAT " Total dirty " SIZE_FORMAT " (%.2lf%%) Total old " SIZE_FORMAT " (%.2lf%%)",
num_visited_cards,
total_dirty_region_cards,
percent_of(num_visited_cards, total_dirty_region_cards),
total_old_region_cards,
percent_of(num_visited_cards, total_old_region_cards));
}
void G1RemSet::merge_heap_roots(bool remembered_set_only, G1GCPhaseTimes::GCParPhases merge_phase) {
_scan_state->merge_heap_roots(_g1h->workers(), remembered_set_only, merge_phase);
{
_scan_state->prepare_for_merge_heap_roots();
}
WorkGang* workers = G1CollectedHeap::heap()->workers();
size_t const increment_length = G1CollectedHeap::heap()->collection_set()->increment_length();
uint const num_workers = !remembered_set_only ? workers->active_workers() :
MIN2(workers->active_workers(), (uint)increment_length);
{
G1MergeHeapRootsTask cl(_scan_state, num_workers, remembered_set_only, merge_phase);
log_debug(gc, ergo)("Running %s using %u workers for " SIZE_FORMAT " regions",
cl.name(), num_workers, increment_length);
workers->run_task(&cl, num_workers);
}
if (log_is_enabled(Debug, gc, remset)) {
print_merge_heap_roots_stats();
}
}
void G1RemSet::prepare_for_scan_heap_roots(uint region_idx) {

View File

@ -67,6 +67,7 @@ private:
G1Policy* _g1p;
G1HotCardCache* _hot_card_cache;
void print_merge_heap_roots_stats();
public:
typedef CardTable::CardValue CardValue;