< prev index next >

src/hotspot/share/gc/g1/g1RemSet.cpp

Print this page

        

*** 186,196 **** } void reset() { for (uint i = 0; i < _max_regions; i++) { _iter_states[i] = Unclaimed; ! clear_scan_top(i); } G1ResetScanTopClosure cl(_scan_top); G1CollectedHeap::heap()->heap_region_iterate(&cl); --- 186,196 ---- } void reset() { for (uint i = 0; i < _max_regions; i++) { _iter_states[i] = Unclaimed; ! _scan_top[i] = NULL; } G1ResetScanTopClosure cl(_scan_top); G1CollectedHeap::heap()->heap_region_iterate(&cl);
*** 251,264 **** HeapWord* scan_top(uint region_idx) const { return _scan_top[region_idx]; } - void clear_scan_top(uint region_idx) { - _scan_top[region_idx] = NULL; - } - // Clear the card table of "dirty" regions. void clear_card_table(WorkGang* workers) { if (_cur_dirty_region == 0) { return; } --- 251,260 ----
*** 306,546 **** void G1RemSet::initialize(size_t capacity, uint max_regions) { G1FromCardCache::initialize(num_par_rem_sets(), max_regions); _scan_state->initialize(max_regions); } ! class G1ScanRSForRegionClosure : public HeapRegionClosure { ! G1CollectedHeap* _g1h; ! G1CardTable *_ct; ! ! G1ParScanThreadState* _pss; ! G1ScanCardClosure* _scan_objs_on_card_cl; ! ! G1RemSetScanState* _scan_state; ! ! G1GCPhaseTimes::GCParPhases _phase; ! ! uint _worker_i; ! ! size_t _opt_refs_scanned; ! size_t _opt_refs_memory_used; ! ! size_t _cards_scanned; ! size_t _cards_claimed; ! size_t _cards_skipped; ! ! Tickspan _rem_set_root_scan_time; ! Tickspan _rem_set_trim_partially_time; ! ! Tickspan _strong_code_root_scan_time; ! Tickspan _strong_code_trim_partially_time; ! ! void claim_card(size_t card_index, const uint region_idx_for_card) { ! _ct->set_card_claimed(card_index); ! _scan_state->add_dirty_region(region_idx_for_card); } ! void scan_card(MemRegion mr, uint region_idx_for_card) { ! HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); ! assert(!card_region->is_young(), "Should not scan card in young region %u", region_idx_for_card); ! card_region->oops_on_card_seq_iterate_careful<true>(mr, _scan_objs_on_card_cl); ! _scan_objs_on_card_cl->trim_queue_partially(); ! _cards_scanned++; } ! void scan_opt_rem_set_roots(HeapRegion* r) { ! EventGCPhaseParallel event; ! G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r); ! G1ScanCardClosure scan_cl(_g1h, _pss); ! G1ScanRSForOptionalClosure cl(_g1h, &scan_cl); ! _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops()); ! _opt_refs_memory_used += opt_rem_set_list->used_memory(); ! ! event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); ! } ! ! void scan_rem_set_roots(HeapRegion* r) { ! EventGCPhaseParallel event; ! uint const region_idx = r->hrm_index(); ! ! if (_scan_state->claim_iter(region_idx)) { ! // If we ever free the collection set concurrently, we should also ! // clear the card table concurrently therefore we won't need to ! // add regions of the collection set to the dirty cards region. ! _scan_state->add_dirty_region(region_idx); } ! ! if (r->rem_set()->cardset_is_empty()) { ! return; } ! // We claim cards in blocks so as to reduce the contention. ! size_t const block_size = G1RSetScanBlockSize; ! ! HeapRegionRemSetIterator iter(r->rem_set()); ! size_t card_index; ! ! size_t claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); ! for (size_t current_card = 0; iter.has_next(card_index); current_card++) { ! if (current_card >= claimed_card_block + block_size) { ! claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); ! } ! if (current_card < claimed_card_block) { ! _cards_skipped++; ! continue; ! } ! _cards_claimed++; ! ! HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index); ! uint const region_idx_for_card = _g1h->addr_to_region(card_start); #ifdef ASSERT ! HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card); ! assert(hr == NULL || hr->is_in_reserved(card_start), ! "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index()); #endif ! HeapWord* const top = _scan_state->scan_top(region_idx_for_card); ! if (card_start >= top) { ! continue; ! } ! ! // If the card is dirty, then G1 will scan it during Update RS. ! if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) { ! continue; ! } ! ! // We claim lazily (so races are possible but they're benign), which reduces the ! // number of duplicate scans (the rsets of the regions in the cset can intersect). ! // Claim the card after checking bounds above: the remembered set may contain ! // random cards into current survivor, and we would then have an incorrectly ! // claimed card in survivor space. Card table clear does not reset the card table ! // of survivor space regions. ! claim_card(card_index, region_idx_for_card); ! ! MemRegion const mr(card_start, MIN2(card_start + BOTConstants::N_words, top)); ! ! scan_card(mr, region_idx_for_card); ! } ! event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); ! } ! ! void scan_strong_code_roots(HeapRegion* r) { ! EventGCPhaseParallel event; ! // We pass a weak code blobs closure to the remembered set scanning because we want to avoid ! // treating the nmethods visited to act as roots for concurrent marking. ! // We only want to make sure that the oops in the nmethods are adjusted with regard to the ! // objects copied by the current evacuation. ! r->strong_code_roots_do(_pss->closures()->weak_codeblobs()); ! event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots)); ! } ! ! public: ! G1ScanRSForRegionClosure(G1RemSetScanState* scan_state, ! G1ScanCardClosure* scan_obj_on_card, ! G1ParScanThreadState* pss, ! G1GCPhaseTimes::GCParPhases phase, ! uint worker_i) : ! _g1h(G1CollectedHeap::heap()), ! _ct(_g1h->card_table()), ! _pss(pss), ! _scan_objs_on_card_cl(scan_obj_on_card), ! _scan_state(scan_state), ! _phase(phase), ! _worker_i(worker_i), ! _opt_refs_scanned(0), ! _opt_refs_memory_used(0), ! _cards_scanned(0), ! _cards_claimed(0), ! _cards_skipped(0), ! _rem_set_root_scan_time(), ! _rem_set_trim_partially_time(), ! _strong_code_root_scan_time(), ! _strong_code_trim_partially_time() { } ! ! bool do_heap_region(HeapRegion* r) { ! assert(r->in_collection_set(), "Region %u is not in the collection set.", r->hrm_index()); ! uint const region_idx = r->hrm_index(); ! ! // The individual references for the optional remembered set are per-worker, so we ! // always need to scan them. ! if (r->has_index_in_opt_cset()) { ! G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); ! scan_opt_rem_set_roots(r); } ! // Do an early out if we know we are complete. ! if (_scan_state->iter_is_complete(region_idx)) { ! return false; } ! { ! G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); ! scan_rem_set_roots(r); ! } ! if (_scan_state->set_iter_complete(region_idx)) { ! G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time); ! // Scan the strong code root list attached to the current region ! scan_strong_code_roots(r); ! } ! return false; } ! Tickspan rem_set_root_scan_time() const { return _rem_set_root_scan_time; } ! Tickspan rem_set_trim_partially_time() const { return _rem_set_trim_partially_time; } ! Tickspan strong_code_root_scan_time() const { return _strong_code_root_scan_time; } ! Tickspan strong_code_root_trim_partially_time() const { return _strong_code_trim_partially_time; } ! size_t cards_scanned() const { return _cards_scanned; } ! size_t cards_claimed() const { return _cards_claimed; } ! size_t cards_skipped() const { return _cards_skipped; } ! size_t opt_refs_scanned() const { return _opt_refs_scanned; } ! size_t opt_refs_memory_used() const { return _opt_refs_memory_used; } ! }; ! void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, ! uint worker_i, ! G1GCPhaseTimes::GCParPhases scan_phase, ! G1GCPhaseTimes::GCParPhases objcopy_phase, ! G1GCPhaseTimes::GCParPhases coderoots_phase) { ! assert(pss->trim_ticks().value() == 0, "Queues must have been trimmed before entering."); ! ! G1ScanCardClosure scan_cl(_g1h, pss); ! G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, pss, scan_phase, worker_i); ! _g1h->collection_set_iterate_increment_from(&cl, worker_i); G1GCPhaseTimes* p = _g1p->phase_times(); ! p->record_or_add_time_secs(objcopy_phase, worker_i, cl.rem_set_trim_partially_time().seconds()); ! p->record_or_add_time_secs(scan_phase, worker_i, cl.rem_set_root_scan_time().seconds()); ! p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards); ! p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards); ! p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards); ! // At this time we only record some metrics for the optional remembered set. ! if (scan_phase == G1GCPhaseTimes::OptScanRS) { ! p->record_or_add_thread_work_item(scan_phase, worker_i, cl.opt_refs_scanned(), G1GCPhaseTimes::ScanRSScannedOptRefs); ! p->record_or_add_thread_work_item(scan_phase, worker_i, cl.opt_refs_memory_used(), G1GCPhaseTimes::ScanRSUsedMemory); ! } ! p->record_or_add_time_secs(coderoots_phase, worker_i, cl.strong_code_root_scan_time().seconds()); ! p->add_time_secs(objcopy_phase, worker_i, cl.strong_code_root_trim_partially_time().seconds()); } // Closure used for updating rem sets. Only called during an evacuation pause. class G1RefineCardClosure: public G1CardTableEntryClosure { G1RemSet* _g1rs; ! G1ScanCardClosure* _update_rs_cl; size_t _cards_scanned; size_t _cards_skipped; public: ! G1RefineCardClosure(G1CollectedHeap* g1h, G1ScanCardClosure* update_rs_cl) : _g1rs(g1h->rem_set()), _update_rs_cl(update_rs_cl), _cards_scanned(0), _cards_skipped(0) {} bool do_card_ptr(CardValue* card_ptr, uint worker_i) { // The only time we care about recording cards that --- 302,471 ---- void G1RemSet::initialize(size_t capacity, uint max_regions) { G1FromCardCache::initialize(num_par_rem_sets(), max_regions); _scan_state->initialize(max_regions); } ! G1ScanRSForRegionClosure::G1ScanRSForRegionClosure(G1RemSetScanState* scan_state, ! G1ScanObjsDuringScanRSClosure* scan_obj_on_card, ! G1ParScanThreadState* pss, ! G1GCPhaseTimes::GCParPhases phase, ! uint worker_i) : ! _g1h(G1CollectedHeap::heap()), ! _ct(_g1h->card_table()), ! _pss(pss), ! _scan_objs_on_card_cl(scan_obj_on_card), ! _scan_state(scan_state), ! _phase(phase), ! _worker_i(worker_i), ! _cards_scanned(0), ! _cards_claimed(0), ! _cards_skipped(0), ! _rem_set_root_scan_time(), ! _rem_set_trim_partially_time(), ! _strong_code_root_scan_time(), ! _strong_code_trim_partially_time() { ! } ! ! void G1ScanRSForRegionClosure::claim_card(size_t card_index, const uint region_idx_for_card){ ! _ct->set_card_claimed(card_index); ! _scan_state->add_dirty_region(region_idx_for_card); ! } ! ! void G1ScanRSForRegionClosure::scan_card(MemRegion mr, uint region_idx_for_card) { ! HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); ! assert(!card_region->is_young(), "Should not scan card in young region %u", region_idx_for_card); ! card_region->oops_on_card_seq_iterate_careful<true>(mr, _scan_objs_on_card_cl); ! _scan_objs_on_card_cl->trim_queue_partially(); ! _cards_scanned++; ! } ! ! void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) { ! EventGCPhaseParallel event; ! uint const region_idx = r->hrm_index(); ! ! if (_scan_state->claim_iter(region_idx)) { ! // If we ever free the collection set concurrently, we should also ! // clear the card table concurrently therefore we won't need to ! // add regions of the collection set to the dirty cards region. ! _scan_state->add_dirty_region(region_idx); } ! if (r->rem_set()->cardset_is_empty()) { ! return; } ! // We claim cards in blocks so as to reduce the contention. ! size_t const block_size = G1RSetScanBlockSize; ! HeapRegionRemSetIterator iter(r->rem_set()); ! size_t card_index; ! size_t claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); ! for (size_t current_card = 0; iter.has_next(card_index); current_card++) { ! if (current_card >= claimed_card_block + block_size) { ! claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size); } ! if (current_card < claimed_card_block) { ! _cards_skipped++; ! continue; } + _cards_claimed++; ! HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index); ! uint const region_idx_for_card = _g1h->addr_to_region(card_start); #ifdef ASSERT ! HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card); ! assert(hr == NULL || hr->is_in_reserved(card_start), ! "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index()); #endif ! HeapWord* const top = _scan_state->scan_top(region_idx_for_card); ! if (card_start >= top) { ! continue; } ! // If the card is dirty, then G1 will scan it during Update RS. ! if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) { ! continue; } ! // We claim lazily (so races are possible but they're benign), which reduces the ! // number of duplicate scans (the rsets of the regions in the cset can intersect). ! // Claim the card after checking bounds above: the remembered set may contain ! // random cards into current survivor, and we would then have an incorrectly ! // claimed card in survivor space. Card table clear does not reset the card table ! // of survivor space regions. ! claim_card(card_index, region_idx_for_card); ! MemRegion const mr(card_start, MIN2(card_start + BOTConstants::N_words, top)); ! ! scan_card(mr, region_idx_for_card); } + event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); + } ! void G1ScanRSForRegionClosure::scan_strong_code_roots(HeapRegion* r) { ! EventGCPhaseParallel event; ! // We pass a weak code blobs closure to the remembered set scanning because we want to avoid ! // treating the nmethods visited to act as roots for concurrent marking. ! // We only want to make sure that the oops in the nmethods are adjusted with regard to the ! // objects copied by the current evacuation. ! r->strong_code_roots_do(_pss->closures()->weak_codeblobs()); ! event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots)); ! } ! bool G1ScanRSForRegionClosure::do_heap_region(HeapRegion* r) { ! assert(r->in_collection_set(), ! "Should only be called on elements of the collection set but region %u is not.", ! r->hrm_index()); ! uint const region_idx = r->hrm_index(); ! // Do an early out if we know we are complete. ! if (_scan_state->iter_is_complete(region_idx)) { ! return false; ! } ! { ! G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); ! scan_rem_set_roots(r); ! } ! if (_scan_state->set_iter_complete(region_idx)) { ! G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time); ! // Scan the strong code root list attached to the current region ! scan_strong_code_roots(r); ! } ! return false; ! } ! ! void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, uint worker_i) { ! G1ScanObjsDuringScanRSClosure scan_cl(_g1h, pss); ! G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, pss, G1GCPhaseTimes::ScanRS, worker_i); ! _g1h->collection_set_iterate_from(&cl, worker_i); G1GCPhaseTimes* p = _g1p->phase_times(); ! p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, cl.rem_set_root_scan_time().seconds()); ! p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.rem_set_trim_partially_time().seconds()); ! p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards); ! p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards); ! p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards); ! p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, cl.strong_code_root_scan_time().seconds()); ! p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.strong_code_root_trim_partially_time().seconds()); } // Closure used for updating rem sets. Only called during an evacuation pause. class G1RefineCardClosure: public G1CardTableEntryClosure { G1RemSet* _g1rs; ! G1ScanObjsDuringUpdateRSClosure* _update_rs_cl; size_t _cards_scanned; size_t _cards_skipped; public: ! G1RefineCardClosure(G1CollectedHeap* g1h, G1ScanObjsDuringUpdateRSClosure* update_rs_cl) : _g1rs(g1h->rem_set()), _update_rs_cl(update_rs_cl), _cards_scanned(0), _cards_skipped(0) {} bool do_card_ptr(CardValue* card_ptr, uint worker_i) { // The only time we care about recording cards that
*** 569,606 **** // Apply closure to log entries in the HCC. if (G1HotCardCache::default_use_cache()) { G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::ScanHCC, worker_i); ! G1ScanCardClosure scan_hcc_cl(_g1h, pss); G1RefineCardClosure refine_card_cl(_g1h, &scan_hcc_cl); _g1h->iterate_hcc_closure(&refine_card_cl, worker_i); } // Now apply the closure to all remaining log entries. { G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::UpdateRS, worker_i); ! G1ScanCardClosure update_rs_cl(_g1h, pss); G1RefineCardClosure refine_card_cl(_g1h, &update_rs_cl); _g1h->iterate_dirty_card_closure(&refine_card_cl, worker_i); p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_scanned(), G1GCPhaseTimes::UpdateRSScannedCards); p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_skipped(), G1GCPhaseTimes::UpdateRSSkippedCards); } } ! void G1RemSet::prepare_for_scan_rem_set() { ! G1BarrierSet::dirty_card_queue_set().concatenate_logs(); ! _scan_state->reset(); } ! void G1RemSet::prepare_for_scan_rem_set(uint region_idx) { ! _scan_state->clear_scan_top(region_idx); } ! void G1RemSet::cleanup_after_scan_rem_set() { G1GCPhaseTimes* phase_times = _g1h->phase_times(); // Set all cards back to clean. double start = os::elapsedTime(); _scan_state->clear_card_table(_g1h->workers()); --- 494,532 ---- // Apply closure to log entries in the HCC. if (G1HotCardCache::default_use_cache()) { G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::ScanHCC, worker_i); ! G1ScanObjsDuringUpdateRSClosure scan_hcc_cl(_g1h, pss); G1RefineCardClosure refine_card_cl(_g1h, &scan_hcc_cl); _g1h->iterate_hcc_closure(&refine_card_cl, worker_i); } // Now apply the closure to all remaining log entries. { G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::UpdateRS, worker_i); ! G1ScanObjsDuringUpdateRSClosure update_rs_cl(_g1h, pss); G1RefineCardClosure refine_card_cl(_g1h, &update_rs_cl); _g1h->iterate_dirty_card_closure(&refine_card_cl, worker_i); p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_scanned(), G1GCPhaseTimes::UpdateRSScannedCards); p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_skipped(), G1GCPhaseTimes::UpdateRSSkippedCards); } } ! void G1RemSet::oops_into_collection_set_do(G1ParScanThreadState* pss, uint worker_i) { ! update_rem_set(pss, worker_i); ! scan_rem_set(pss, worker_i);; } ! void G1RemSet::prepare_for_oops_into_collection_set_do() { ! G1BarrierSet::dirty_card_queue_set().concatenate_logs(); ! _scan_state->reset(); } ! void G1RemSet::cleanup_after_oops_into_collection_set_do() { G1GCPhaseTimes* phase_times = _g1h->phase_times(); // Set all cards back to clean. double start = os::elapsedTime(); _scan_state->clear_card_table(_g1h->workers());
*** 758,768 **** *card_ptr = G1CardTable::dirty_card_val(); G1BarrierSet::shared_dirty_card_queue().enqueue(card_ptr); } bool G1RemSet::refine_card_during_gc(CardValue* card_ptr, ! G1ScanCardClosure* update_rs_cl) { assert(_g1h->is_gc_active(), "Only call during GC"); // Construct the region representing the card. HeapWord* card_start = _ct->addr_for(card_ptr); // And find the region containing it. --- 684,694 ---- *card_ptr = G1CardTable::dirty_card_val(); G1BarrierSet::shared_dirty_card_queue().enqueue(card_ptr); } bool G1RemSet::refine_card_during_gc(CardValue* card_ptr, ! G1ScanObjsDuringUpdateRSClosure* update_rs_cl) { assert(_g1h->is_gc_active(), "Only call during GC"); // Construct the region representing the card. HeapWord* card_start = _ct->addr_for(card_ptr); // And find the region containing it.
< prev index next >