7095236: G1: _markedRegions never contains NULL regions
authorysr
Thu, 06 Oct 2011 18:56:47 -0700
changeset 10680 f7bdba11999b
parent 10678 ecb473e90f9b
child 10681 0855fd34f5ae
7095236: G1: _markedRegions never contains NULL regions Summary: Removed the code for skipping over NULL regions in _markedRegions, replacing it with an assertion that a NULL region is never encountered; removed dead methods, remove() and remove_region(), and inlined a simplified addRegion() directly into fillCache(). Reviewed-by: brutisso, tonyp
hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp
hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp
--- a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp	Thu Oct 06 13:28:09 2011 -0400
+++ b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp	Thu Oct 06 18:56:47 2011 -0700
@@ -118,30 +118,6 @@
   }
 }
 
-// this is a bit expensive... but we expect that it should not be called
-// to often.
-void CSetChooserCache::remove(HeapRegion *hr) {
-  assert(_occupancy > 0, "cache should not be empty");
-  assert(hr->sort_index() < -1, "should already be in the cache");
-  int index = get_index(hr->sort_index());
-  assert(_cache[index] == hr, "index should be correct");
-  int next_index = trim_index(index + 1);
-  int last_index = trim_index(_first + _occupancy - 1);
-  while (index != last_index) {
-    assert(_cache[next_index] != NULL, "should not be null");
-    _cache[index] = _cache[next_index];
-    _cache[index]->set_sort_index(get_sort_index(index));
-
-    index = next_index;
-    next_index = trim_index(next_index+1);
-  }
-  assert(index == last_index, "should have reached the last one");
-  _cache[index] = NULL;
-  hr->set_sort_index(-1);
-  --_occupancy;
-  assert(verify(), "cache should be consistent");
-}
-
 static inline int orderRegions(HeapRegion* hr1, HeapRegion* hr2) {
   if (hr1 == NULL) {
     if (hr2 == NULL) return 0;
@@ -197,43 +173,34 @@
   HeapRegion *prev = NULL;
   while (index < _numMarkedRegions) {
     HeapRegion *curr = _markedRegions.at(index++);
-    if (curr != NULL) {
-      int si = curr->sort_index();
-      guarantee(!curr->is_young(), "should not be young!");
-      guarantee(si > -1 && si == (index-1), "sort index invariant");
-      if (prev != NULL) {
-        guarantee(orderRegions(prev, curr) != 1, "regions should be sorted");
-      }
-      prev = curr;
+    guarantee(curr != NULL, "Regions in _markedRegions array cannot be NULL");
+    int si = curr->sort_index();
+    guarantee(!curr->is_young(), "should not be young!");
+    guarantee(si > -1 && si == (index-1), "sort index invariant");
+    if (prev != NULL) {
+      guarantee(orderRegions(prev, curr) != 1, "regions should be sorted");
     }
+    prev = curr;
   }
   return _cache.verify();
 }
 #endif
 
-bool
-CollectionSetChooser::addRegionToCache() {
-  assert(!_cache.is_full(), "cache should not be full");
-
-  HeapRegion *hr = NULL;
-  while (hr == NULL && _curMarkedIndex < _numMarkedRegions) {
-    hr = _markedRegions.at(_curMarkedIndex++);
-  }
-  if (hr == NULL)
-    return false;
-  assert(!hr->is_young(), "should not be young!");
-  assert(hr->sort_index() == _curMarkedIndex-1, "sort_index invariant");
-  _markedRegions.at_put(hr->sort_index(), NULL);
-  _cache.insert(hr);
-  assert(!_cache.is_empty(), "cache should not be empty");
-  assert(verify(), "cache should be consistent");
-  return false;
-}
-
 void
 CollectionSetChooser::fillCache() {
-  while (!_cache.is_full() && addRegionToCache()) {
+  while (!_cache.is_full() && (_curMarkedIndex < _numMarkedRegions)) {
+    HeapRegion* hr = _markedRegions.at(_curMarkedIndex);
+    assert(hr != NULL,
+           err_msg("Unexpected NULL hr in _markedRegions at index %d",
+                   _curMarkedIndex));
+    _curMarkedIndex += 1;
+    assert(!hr->is_young(), "should not be young!");
+    assert(hr->sort_index() == _curMarkedIndex-1, "sort_index invariant");
+    _markedRegions.at_put(hr->sort_index(), NULL);
+    _cache.insert(hr);
+    assert(!_cache.is_empty(), "cache should not be empty");
   }
+  assert(verify(), "cache should be consistent");
 }
 
 void
@@ -334,20 +301,6 @@
   clearMarkedHeapRegions();
 }
 
-void CollectionSetChooser::removeRegion(HeapRegion *hr) {
-  int si = hr->sort_index();
-  assert(si == -1 || hr->is_marked(), "Sort index not valid.");
-  if (si > -1) {
-    assert(_markedRegions.at(si) == hr, "Sort index not valid." );
-    _markedRegions.at_put(si, NULL);
-  } else if (si < -1) {
-    assert(_cache.region_in_cache(hr), "should be in the cache");
-    _cache.remove(hr);
-    assert(hr->sort_index() == -1, "sort index invariant");
-  }
-  hr->set_sort_index(-1);
-}
-
 // if time_remaining < 0.0, then this method should try to return
 // a region, whether it fits within the remaining time or not
 HeapRegion*
--- a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp	Thu Oct 06 13:28:09 2011 -0400
+++ b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp	Thu Oct 06 18:56:47 2011 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,26 @@
 #include "utilities/growableArray.hpp"
 
 // We need to sort heap regions by collection desirability.
+// This sorting is currently done in two "stages". An initial sort is
+// done following a cleanup pause as soon as all of the marked but
+// non-empty regions have been identified and the completely empty
+// ones reclaimed.
+// This gives us a global sort on a GC efficiency metric
+// based on predictive data available at that time. However,
+// any of these regions that are collected will only be collected
+// during a future GC pause, by which time it is possible that newer
+// data might allow us to revise and/or refine the earlier
+// pause predictions, leading to changes in expected gc efficiency
+// order. To somewhat mitigate this obsolescence, more so in the
+// case of regions towards the end of the list, which will be
+// picked later, these pre-sorted regions from the _markedRegions
+// array are not used as is, but a small prefix thereof is
+// insertion-sorted again into a small cache, based on more
+// recent remembered set information. Regions are then drawn
+// from this cache to construct the collection set at each
+// incremental GC.
+// This scheme and/or its implementation may be subject to
+// revision in the future.
 
 class CSetChooserCache VALUE_OBJ_CLASS_SPEC {
 private:
@@ -37,8 +57,8 @@
   } PrivateConstants;
 
   HeapRegion*  _cache[CacheLength];
-  int          _occupancy; // number of region in cache
-  int          _first; // "first" region in the cache
+  int          _occupancy; // number of regions in cache
+  int          _first;     // (index of) "first" region in the cache
 
   // adding CacheLength to deal with negative values
   inline int trim_index(int index) {
@@ -62,7 +82,6 @@
   void clear(void);
   void insert(HeapRegion *hr);
   HeapRegion *remove_first(void);
-  void remove (HeapRegion *hr);
   inline HeapRegion *get_first(void) {
     return _cache[_first];
   }
@@ -102,7 +121,6 @@
 
   void sortMarkedHeapRegions();
   void fillCache();
-  bool addRegionToCache(void);
   void addMarkedHeapRegion(HeapRegion *hr);
 
   // Must be called before calls to getParMarkedHeapRegionChunk.
@@ -122,9 +140,6 @@
 
   void updateAfterFullCollection();
 
-  // Ensure that "hr" is not a member of the marked region array or the cache
-  void removeRegion(HeapRegion* hr);
-
   bool unmarked_age_1_returned_as_new() { return _unmarked_age_1_returned_as_new; }
 
   // Returns true if the used portion of "_markedRegions" is properly