--- a/src/hotspot/share/gc/g1/g1RemSet.cpp Wed Jul 17 23:22:48 2019 +0900
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Wed Jul 17 16:33:19 2019 +0200
@@ -183,259 +183,6 @@
}
};
- // 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 @@
}
_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;
- for (uint i = 0; i < _max_regions * _scan_chunks_per_region; i++) {
- if (_region_scan_chunks[i]) {
- num_scan_chunks++;
- }
- }
- size_t num_visited_cards = num_scan_chunks * CardsPerChunk;
- size_t total_dirty_region_cards = _next_dirty_regions->size() * HeapRegion::CardsPerRegion;
+ void prepare_for_merge_heap_roots() {
+ _all_dirty_regions->merge(_next_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;
+ _next_dirty_regions->reset();
+ for (size_t i = 0; i < _max_regions; i++) {
+ _card_table_scan_state[i] = 0;
+ }
- 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));
+ ::memset(_region_scan_chunks, false, _max_regions * _scan_chunks_per_region * sizeof(*_region_scan_chunks));
}
- 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();
+ // 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());
+ }
- uint const num_workers = !remembered_set_only ? workers->active_workers() :
- MIN2(workers->active_workers(), (uint)increment_length);
+ 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]) {
+ result++;
+ }
+ }
+ return result * CardsPerChunk;
+ }
- {
- 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 @@
_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) {