Mercurial > hg > graal-compiler
diff src/share/vm/gc_implementation/g1/g1RemSet.cpp @ 890:6cb8e9df7174
6819077: G1: first GC thread coming late into the GC.
Summary: The first worker thread is delayed when entering the GC because it clears the card count table that is used in identifying hot cards. Replace the card count table with a dynamically sized evicting hash table that includes an epoch based counter.
Reviewed-by: iveresov, tonyp
author | johnc |
---|---|
date | Tue, 04 Aug 2009 16:00:17 -0700 |
parents | df6caf649ff7 |
children | 0414c1049f15 |
line wrap: on
line diff
--- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Mon Aug 03 12:59:30 2009 -0700 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Tue Aug 04 16:00:17 2009 -0700 @@ -676,6 +676,55 @@ static IntHistogram out_of_histo(50, 50); +void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i) { + // Construct the region representing the card. + HeapWord* start = _ct_bs->addr_for(card_ptr); + // And find the region containing it. + HeapRegion* r = _g1->heap_region_containing(start); + assert(r != NULL, "unexpected null"); + + HeapWord* end = _ct_bs->addr_for(card_ptr + 1); + MemRegion dirtyRegion(start, end); + +#if CARD_REPEAT_HISTO + init_ct_freq_table(_g1->g1_reserved_obj_bytes()); + ct_freq_note_card(_ct_bs->index_for(start)); +#endif + + UpdateRSOopClosure update_rs_oop_cl(this, worker_i); + update_rs_oop_cl.set_from(r); + FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, &update_rs_oop_cl); + + // Undirty the card. + *card_ptr = CardTableModRefBS::clean_card_val(); + // We must complete this write before we do any of the reads below. + OrderAccess::storeload(); + // And process it, being careful of unallocated portions of TLAB's. + HeapWord* stop_point = + r->oops_on_card_seq_iterate_careful(dirtyRegion, + &filter_then_update_rs_oop_cl); + // If stop_point is non-null, then we encountered an unallocated region + // (perhaps the unfilled portion of a TLAB.) For now, we'll dirty the + // card and re-enqueue: if we put off the card until a GC pause, then the + // unallocated portion will be filled in. Alternatively, we might try + // the full complexity of the technique used in "regular" precleaning. + if (stop_point != NULL) { + // The card might have gotten re-dirtied and re-enqueued while we + // worked. (In fact, it's pretty likely.) + if (*card_ptr != CardTableModRefBS::dirty_card_val()) { + *card_ptr = CardTableModRefBS::dirty_card_val(); + MutexLockerEx x(Shared_DirtyCardQ_lock, + Mutex::_no_safepoint_check_flag); + DirtyCardQueue* sdcq = + JavaThread::dirty_card_queue_set().shared_dirty_card_queue(); + sdcq->enqueue(card_ptr); + } + } else { + out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region()); + _conc_refine_cards++; + } +} + void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { // If the card is no longer dirty, nothing to do. if (*card_ptr != CardTableModRefBS::dirty_card_val()) return; @@ -716,61 +765,63 @@ return; } - // Should we defer it? - if (_cg1r->use_cache()) { - card_ptr = _cg1r->cache_insert(card_ptr); - // If it was not an eviction, nothing to do. - if (card_ptr == NULL) return; + // Should we defer processing the card? + // + // Previously the result from the insert_cache call would be + // either card_ptr (implying that card_ptr was currently "cold"), + // null (meaning we had inserted the card ptr into the "hot" + // cache, which had some headroom), or a "hot" card ptr + // extracted from the "hot" cache. + // + // Now that the _card_counts cache in the ConcurrentG1Refine + // instance is an evicting hash table, the result we get back + // could be from evicting the card ptr in an already occupied + // bucket (in which case we have replaced the card ptr in the + // bucket with card_ptr and "defer" is set to false). To avoid + // having a data structure (updates to which would need a lock) + // to hold these unprocessed dirty cards, we need to immediately + // process card_ptr. The actions needed to be taken on return + // from cache_insert are summarized in the following table: + // + // res defer action + // -------------------------------------------------------------- + // null false card evicted from _card_counts & replaced with + // card_ptr; evicted ptr added to hot cache. + // No need to process res; immediately process card_ptr + // + // null true card not evicted from _card_counts; card_ptr added + // to hot cache. + // Nothing to do. + // + // non-null false card evicted from _card_counts & replaced with + // card_ptr; evicted ptr is currently "cold" or + // caused an eviction from the hot cache. + // Immediately process res; process card_ptr. + // + // non-null true card not evicted from _card_counts; card_ptr is + // currently cold, or caused an eviction from hot + // cache. + // Immediately process res; no need to process card_ptr. - // OK, we have to reset the card start, region, etc. - start = _ct_bs->addr_for(card_ptr); - r = _g1->heap_region_containing(start); - if (r == NULL) { - guarantee(_g1->is_in_permanent(start), "Or else where?"); - return; // Not in the G1 heap (might be in perm, for example.) + jbyte* res = card_ptr; + bool defer = false; + if (_cg1r->use_cache()) { + jbyte* res = _cg1r->cache_insert(card_ptr, &defer); + if (res != NULL && (res != card_ptr || defer)) { + start = _ct_bs->addr_for(res); + r = _g1->heap_region_containing(start); + if (r == NULL) { + assert(_g1->is_in_permanent(start), "Or else where?"); + } else { + guarantee(!r->is_young(), "It was evicted in the current minor cycle."); + // Process card pointer we get back from the hot card cache + concurrentRefineOneCard_impl(res, worker_i); + } } - guarantee(!r->is_young(), "It was evicted in the current minor cycle."); } - HeapWord* end = _ct_bs->addr_for(card_ptr + 1); - MemRegion dirtyRegion(start, end); - -#if CARD_REPEAT_HISTO - init_ct_freq_table(_g1->g1_reserved_obj_bytes()); - ct_freq_note_card(_ct_bs->index_for(start)); -#endif - - UpdateRSOopClosure update_rs_oop_cl(this, worker_i); - update_rs_oop_cl.set_from(r); - FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, &update_rs_oop_cl); - - // Undirty the card. - *card_ptr = CardTableModRefBS::clean_card_val(); - // We must complete this write before we do any of the reads below. - OrderAccess::storeload(); - // And process it, being careful of unallocated portions of TLAB's. - HeapWord* stop_point = - r->oops_on_card_seq_iterate_careful(dirtyRegion, - &filter_then_update_rs_oop_cl); - // If stop_point is non-null, then we encountered an unallocated region - // (perhaps the unfilled portion of a TLAB.) For now, we'll dirty the - // card and re-enqueue: if we put off the card until a GC pause, then the - // unallocated portion will be filled in. Alternatively, we might try - // the full complexity of the technique used in "regular" precleaning. - if (stop_point != NULL) { - // The card might have gotten re-dirtied and re-enqueued while we - // worked. (In fact, it's pretty likely.) - if (*card_ptr != CardTableModRefBS::dirty_card_val()) { - *card_ptr = CardTableModRefBS::dirty_card_val(); - MutexLockerEx x(Shared_DirtyCardQ_lock, - Mutex::_no_safepoint_check_flag); - DirtyCardQueue* sdcq = - JavaThread::dirty_card_queue_set().shared_dirty_card_queue(); - sdcq->enqueue(card_ptr); - } - } else { - out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region()); - _conc_refine_cards++; + if (!defer) { + concurrentRefineOneCard_impl(card_ptr, worker_i); } }