8222492: G1 unnecessarily scans remembered set cards for regions that already have been evacuated
authortschatzl
Sat, 18 May 2019 22:11:25 +0200
changeset 54934 39814e0a8964
parent 54933 24c0eeb3ebe7
child 54935 cb80f2adf35c
8222492: G1 unnecessarily scans remembered set cards for regions that already have been evacuated Summary: Filter out cards from the current collection set during evacuation increments. Reviewed-by: kbarrett, sangheki
src/hotspot/share/gc/g1/g1CollectedHeap.hpp
src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp
src/hotspot/share/gc/g1/g1OopClosures.hpp
src/hotspot/share/gc/g1/g1OopClosures.inline.hpp
src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp
src/hotspot/share/gc/g1/g1RemSet.cpp
src/hotspot/share/gc/g1/g1RemSet.hpp
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Sat May 18 12:13:38 2019 -0700
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Sat May 18 22:11:25 2019 +0200
@@ -1111,7 +1111,7 @@
 
  public:
 
-  inline G1HeapRegionAttr region_attr(const oop obj);
+  inline G1HeapRegionAttr region_attr(const void* obj);
 
   // Return "TRUE" iff the given object address is in the reserved
   // region of g1.
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp	Sat May 18 12:13:38 2019 -0700
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp	Sat May 18 22:11:25 2019 +0200
@@ -29,6 +29,7 @@
 #include "gc/g1/g1CollectedHeap.hpp"
 #include "gc/g1/g1CollectorState.hpp"
 #include "gc/g1/g1Policy.hpp"
+#include "gc/g1/g1RemSet.hpp"
 #include "gc/g1/heapRegionManager.inline.hpp"
 #include "gc/g1/heapRegionRemSet.hpp"
 #include "gc/g1/heapRegionSet.inline.hpp"
@@ -162,8 +163,8 @@
   return _region_attr.is_in_cset_or_humongous((HeapWord*)obj);
 }
 
-G1HeapRegionAttr G1CollectedHeap::region_attr(const oop obj) {
-  return _region_attr.at((HeapWord*)obj);
+G1HeapRegionAttr G1CollectedHeap::region_attr(const void* addr) {
+  return _region_attr.at((HeapWord*)addr);
 }
 
 void G1CollectedHeap::register_humongous_region_with_region_attr(uint index) {
@@ -176,6 +177,7 @@
 
 void G1CollectedHeap::register_old_region_with_region_attr(HeapRegion* r) {
   _region_attr.set_in_old(r->hrm_index(), r->rem_set()->is_tracked());
+  _rem_set->prepare_for_scan_rem_set(r->hrm_index());
 }
 
 void G1CollectedHeap::register_optional_region_with_region_attr(HeapRegion* r) {
--- a/src/hotspot/share/gc/g1/g1OopClosures.hpp	Sat May 18 12:13:38 2019 -0700
+++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp	Sat May 18 22:11:25 2019 +0200
@@ -73,9 +73,10 @@
 
 // Used during Optional RS scanning to make sure we trim the queues in a timely manner.
 class G1ScanRSForOptionalClosure : public OopClosure {
+  G1CollectedHeap* _g1h;
   G1ScanCardClosure* _scan_cl;
 public:
-  G1ScanRSForOptionalClosure(G1ScanCardClosure* cl) : _scan_cl(cl) { }
+  G1ScanRSForOptionalClosure(G1CollectedHeap* g1h, G1ScanCardClosure* cl) : _g1h(g1h), _scan_cl(cl) { }
 
   template <class T> void do_oop_work(T* p);
   virtual void do_oop(oop* p)          { do_oop_work(p); }
--- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp	Sat May 18 12:13:38 2019 -0700
+++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp	Sat May 18 22:11:25 2019 +0200
@@ -169,11 +169,14 @@
 
   check_obj_during_refinement(p, obj);
 
-  // We can not check for references from the collection set: the remembered sets
-  // may contain such entries and we do not filter them before.
+  assert(!_g1h->is_in_cset((HeapWord*)p),
+         "Oop originates from " PTR_FORMAT " (region: %u) which is in the collection set.",
+         p2i(p), _g1h->addr_to_region((HeapWord*)p));
 
   const G1HeapRegionAttr region_attr = _g1h->region_attr(obj);
   if (region_attr.is_in_cset()) {
+    // Since the source is always from outside the collection set, here we implicitly know
+    // that this is a cross-region reference too.
     prefetch_and_push(p, obj);
   } else if (!HeapRegion::is_in_same_region(p, obj)) {
     handle_non_cset_obj_common(region_attr, p, obj);
@@ -183,6 +186,13 @@
 
 template <class T>
 inline void G1ScanRSForOptionalClosure::do_oop_work(T* p) {
+  const G1HeapRegionAttr region_attr = _g1h->region_attr(p);
+  // Entries in the optional collection set may start to originate from the collection
+  // set after one or more increments. In this case, previously optional regions
+  // became actual collection set regions. Filter them out here.
+  if (region_attr.is_in_cset()) {
+    return;
+  }
   _scan_cl->do_oop_work(p);
   _scan_cl->trim_queue_partially();
 }
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp	Sat May 18 12:13:38 2019 -0700
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp	Sat May 18 22:11:25 2019 +0200
@@ -208,6 +208,8 @@
 inline void G1ParScanThreadState::remember_root_into_optional_region(T* p) {
   oop o = RawAccess<IS_NOT_NULL>::oop_load(p);
   uint index = _g1h->heap_region_containing(o)->index_in_opt_cset();
+  assert(index < _num_optional_regions,
+         "Trying to access optional region idx %u beyond " SIZE_FORMAT, index, _num_optional_regions);
   _oops_into_optional_regions[index].push_root(p);
 }
 
@@ -215,11 +217,16 @@
 inline void G1ParScanThreadState::remember_reference_into_optional_region(T* p) {
   oop o = RawAccess<IS_NOT_NULL>::oop_load(p);
   uint index = _g1h->heap_region_containing(o)->index_in_opt_cset();
+  assert(index < _num_optional_regions,
+         "Trying to access optional region idx %u beyond " SIZE_FORMAT, index, _num_optional_regions);
   _oops_into_optional_regions[index].push_oop(p);
   DEBUG_ONLY(verify_ref(p);)
 }
 
 G1OopStarChunkedList* G1ParScanThreadState::oops_into_optional_region(const HeapRegion* hr) {
+  assert(hr->index_in_opt_cset() < _num_optional_regions,
+         "Trying to access optional region idx %u beyond " SIZE_FORMAT " " HR_FORMAT,
+         hr->index_in_opt_cset(), _num_optional_regions, HR_FORMAT_PARAMS(hr));
   return &_oops_into_optional_regions[hr->index_in_opt_cset()];
 }
 
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp	Sat May 18 12:13:38 2019 -0700
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp	Sat May 18 22:11:25 2019 +0200
@@ -188,7 +188,7 @@
   void reset() {
     for (uint i = 0; i < _max_regions; i++) {
       _iter_states[i] = Unclaimed;
-      _scan_top[i] = NULL;
+      clear_scan_top(i);
     }
 
     G1ResetScanTopClosure cl(_scan_top);
@@ -253,6 +253,10 @@
     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) {
@@ -346,7 +350,7 @@
   G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r);
 
   G1ScanCardClosure scan_cl(_g1h, _pss);
-  G1ScanRSForOptionalClosure cl(&scan_cl);
+  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();
 
@@ -550,6 +554,10 @@
   _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();
 
--- a/src/hotspot/share/gc/g1/g1RemSet.hpp	Sat May 18 12:13:38 2019 -0700
+++ b/src/hotspot/share/gc/g1/g1RemSet.hpp	Sat May 18 22:11:25 2019 +0200
@@ -98,10 +98,12 @@
   // into the collection set or update the remembered set.
   void update_rem_set(G1ParScanThreadState* pss, uint worker_i);
 
-  // Prepare for and cleanup after scanning the remembered sets.  Must be called
+  // Prepare for and cleanup after scanning the remembered sets. Must be called
   // once before and after in sequential code.
   void prepare_for_scan_rem_set();
   void cleanup_after_scan_rem_set();
+  // Prepares the given region for remembered set scanning.
+  void prepare_for_scan_rem_set(uint region_idx);
 
   G1RemSetScanState* scan_state() const { return _scan_state; }