changeset 54045:c97c87e96897

8220350: Refactor ShenandoahHeap::initialize Reviewed-by: rkennke, zgu
author shade
date Mon, 11 Mar 2019 00:06:46 +0100
parents d9853137aa28
children f02c6b980c04
files src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp
diffstat 5 files changed, 137 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp	Sun Mar 10 18:53:55 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp	Mon Mar 11 00:06:46 2019 +0100
@@ -89,27 +89,28 @@
 class ShenandoahPretouchTask : public AbstractGangTask {
 private:
   ShenandoahRegionIterator _regions;
+  char* _bitmap_base;
   const size_t _bitmap_size;
-  const size_t _page_size;
-  char* _bitmap_base;
+  const size_t _heap_page_size;
+  const size_t _bitmap_page_size;
 public:
-  ShenandoahPretouchTask(char* bitmap_base, size_t bitmap_size, size_t page_size) :
+  ShenandoahPretouchTask(char* bitmap_base, size_t bitmap_size, size_t heap_page_size, size_t bitmap_page_size) :
     AbstractGangTask("Shenandoah PreTouch"),
+    _bitmap_base(bitmap_base),
     _bitmap_size(bitmap_size),
-    _page_size(page_size),
-    _bitmap_base(bitmap_base) {
-  }
+    _heap_page_size(heap_page_size),
+    _bitmap_page_size(bitmap_page_size) {}
 
   virtual void work(uint worker_id) {
     ShenandoahHeapRegion* r = _regions.next();
     while (r != NULL) {
-      os::pretouch_memory(r->bottom(), r->end(), _page_size);
+      os::pretouch_memory(r->bottom(), r->end(), _heap_page_size);
 
       size_t start = r->region_number()       * ShenandoahHeapRegion::region_size_bytes() / MarkBitMap::heap_map_factor();
       size_t end   = (r->region_number() + 1) * ShenandoahHeapRegion::region_size_bytes() / MarkBitMap::heap_map_factor();
       assert (end <= _bitmap_size, "end is sane: " SIZE_FORMAT " < " SIZE_FORMAT, end, _bitmap_size);
 
-      os::pretouch_memory(_bitmap_base + start, _bitmap_base + end, _page_size);
+      os::pretouch_memory(_bitmap_base + start, _bitmap_base + end, _bitmap_page_size);
 
       r = _regions.next();
     }
@@ -121,73 +122,57 @@
 
   initialize_heuristics();
 
+  //
+  // Figure out heap sizing
+  //
+
   size_t init_byte_size = collector_policy()->initial_heap_byte_size();
-  size_t max_byte_size = collector_policy()->max_heap_byte_size();
+  size_t max_byte_size  = collector_policy()->max_heap_byte_size();
   size_t heap_alignment = collector_policy()->heap_alignment();
 
+  size_t reg_size_bytes = ShenandoahHeapRegion::region_size_bytes();
+
   if (ShenandoahAlwaysPreTouch) {
     // Enabled pre-touch means the entire heap is committed right away.
     init_byte_size = max_byte_size;
   }
 
-  Universe::check_alignment(max_byte_size,
-                            ShenandoahHeapRegion::region_size_bytes(),
-                            "shenandoah heap");
-  Universe::check_alignment(init_byte_size,
-                            ShenandoahHeapRegion::region_size_bytes(),
-                            "shenandoah heap");
-
-  ReservedSpace heap_rs = Universe::reserve_heap(max_byte_size,
-                                                 heap_alignment);
-  initialize_reserved_region((HeapWord*)heap_rs.base(), (HeapWord*) (heap_rs.base() + heap_rs.size()));
-
-  ReservedSpace pgc_rs = heap_rs.first_part(max_byte_size);
+  Universe::check_alignment(max_byte_size,  reg_size_bytes, "Shenandoah heap");
+  Universe::check_alignment(init_byte_size, reg_size_bytes, "Shenandoah heap");
 
   _num_regions = ShenandoahHeapRegion::region_count();
 
-  size_t num_committed_regions = init_byte_size / ShenandoahHeapRegion::region_size_bytes();
+  size_t num_committed_regions = init_byte_size / reg_size_bytes;
   num_committed_regions = MIN2(num_committed_regions, _num_regions);
   assert(num_committed_regions <= _num_regions, "sanity");
 
-  _initial_size = num_committed_regions * ShenandoahHeapRegion::region_size_bytes();
+  _initial_size = num_committed_regions * reg_size_bytes;
   _committed = _initial_size;
 
-  log_info(gc, heap)("Initialize Shenandoah heap with initial size " SIZE_FORMAT "%s",
-          byte_size_in_proper_unit(_initial_size), proper_unit_for_byte_size(_initial_size));
-  if (!os::commit_memory(pgc_rs.base(), _initial_size, false)) {
-    vm_exit_out_of_memory(_initial_size, OOM_MMAP_ERROR, "Shenandoah failed to initialize heap");
-  }
-
-  size_t reg_size_words = ShenandoahHeapRegion::region_size_words();
-  size_t reg_size_bytes = ShenandoahHeapRegion::region_size_bytes();
-
-  _regions = NEW_C_HEAP_ARRAY(ShenandoahHeapRegion*, _num_regions, mtGC);
-  _free_set = new ShenandoahFreeSet(this, _num_regions);
-
-  _collection_set = new ShenandoahCollectionSet(this, (HeapWord*)pgc_rs.base());
-
-  if (ShenandoahPacing) {
-    _pacer = new ShenandoahPacer(this);
-    _pacer->setup_for_idle();
-  } else {
-    _pacer = NULL;
-  }
+  size_t heap_page_size   = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size();
+  size_t bitmap_page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size();
+
+  //
+  // Reserve and commit memory for heap
+  //
+
+  ReservedSpace heap_rs = Universe::reserve_heap(max_byte_size, heap_alignment);
+  initialize_reserved_region((HeapWord*)heap_rs.base(), (HeapWord*) (heap_rs.base() + heap_rs.size()));
+  _heap_region = MemRegion((HeapWord*)heap_rs.base(), heap_rs.size() / HeapWordSize);
 
   assert((((size_t) base()) & ShenandoahHeapRegion::region_size_bytes_mask()) == 0,
-         "misaligned heap: " PTR_FORMAT, p2i(base()));
-
-  // The call below uses stuff (the SATB* things) that are in G1, but probably
-  // belong into a shared location.
-  ShenandoahBarrierSet::satb_mark_queue_set().initialize(this,
-                                               SATB_Q_CBL_mon,
-                                               20 /* G1SATBProcessCompletedThreshold */,
-                                               60 /* G1SATBBufferEnqueueingThresholdPercent */);
-
-  // Reserve space for prev and next bitmap.
-  size_t bitmap_page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size();
+         "Misaligned heap: " PTR_FORMAT, p2i(base()));
+
+  ReservedSpace sh_rs = heap_rs.first_part(max_byte_size);
+  os::commit_memory_or_exit(sh_rs.base(), _initial_size, false,
+                            "Cannot commit heap memory");
+
+  //
+  // Reserve and commit memory for bitmap(s)
+  //
+
   _bitmap_size = MarkBitMap::compute_size(heap_rs.size());
   _bitmap_size = align_up(_bitmap_size, bitmap_page_size);
-  _heap_region = MemRegion((HeapWord*) heap_rs.base(), heap_rs.size() / HeapWordSize);
 
   size_t bitmap_bytes_per_region = reg_size_bytes / MarkBitMap::heap_map_factor();
 
@@ -212,91 +197,80 @@
             "Bitmap slices should be page-granular: bps = " SIZE_FORMAT ", page size = " SIZE_FORMAT,
             _bitmap_bytes_per_slice, bitmap_page_size);
 
-  ReservedSpace bitmap0(_bitmap_size, bitmap_page_size);
-  MemTracker::record_virtual_memory_type(bitmap0.base(), mtGC);
-  _bitmap_region = MemRegion((HeapWord*) bitmap0.base(), bitmap0.size() / HeapWordSize);
+  ReservedSpace bitmap(_bitmap_size, bitmap_page_size);
+  MemTracker::record_virtual_memory_type(bitmap.base(), mtGC);
+  _bitmap_region = MemRegion((HeapWord*) bitmap.base(), bitmap.size() / HeapWordSize);
 
   size_t bitmap_init_commit = _bitmap_bytes_per_slice *
                               align_up(num_committed_regions, _bitmap_regions_per_slice) / _bitmap_regions_per_slice;
   bitmap_init_commit = MIN2(_bitmap_size, bitmap_init_commit);
-  os::commit_memory_or_exit((char *) (_bitmap_region.start()), bitmap_init_commit, false,
-                            "couldn't allocate initial bitmap");
-
-  size_t page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size();
+  os::commit_memory_or_exit((char *)_bitmap_region.start(), bitmap_init_commit, false,
+                            "Cannot commit bitmap memory");
+
+  _marking_context = new ShenandoahMarkingContext(_heap_region, _bitmap_region, _num_regions);
 
   if (ShenandoahVerify) {
-    ReservedSpace verify_bitmap(_bitmap_size, page_size);
+    ReservedSpace verify_bitmap(_bitmap_size, bitmap_page_size);
     os::commit_memory_or_exit(verify_bitmap.base(), verify_bitmap.size(), false,
-                              "couldn't allocate verification bitmap");
+                              "Cannot commit verification bitmap memory");
     MemTracker::record_virtual_memory_type(verify_bitmap.base(), mtGC);
     MemRegion verify_bitmap_region = MemRegion((HeapWord *) verify_bitmap.base(), verify_bitmap.size() / HeapWordSize);
     _verification_bit_map.initialize(_heap_region, verify_bitmap_region);
     _verifier = new ShenandoahVerifier(this, &_verification_bit_map);
   }
 
-  _marking_context = new ShenandoahMarkingContext(_heap_region, _bitmap_region, _num_regions);
-
-  {
-    ShenandoahHeapLocker locker(lock());
-    for (size_t i = 0; i < _num_regions; i++) {
-      ShenandoahHeapRegion* r = new ShenandoahHeapRegion(this,
-                                                         (HeapWord*) pgc_rs.base() + reg_size_words * i,
-                                                         reg_size_words,
-                                                         i,
-                                                         i < num_committed_regions);
-
-      _marking_context->initialize_top_at_mark_start(r);
-      _regions[i] = r;
-      assert(!collection_set()->is_in(i), "New region should not be in collection set");
-    }
-
-    // Initialize to complete
-    _marking_context->mark_complete();
-
-    _free_set->rebuild();
-  }
-
-  if (ShenandoahAlwaysPreTouch) {
-    assert (!AlwaysPreTouch, "Should have been overridden");
-
-    // For NUMA, it is important to pre-touch the storage under bitmaps with worker threads,
-    // before initialize() below zeroes it with initializing thread. For any given region,
-    // we touch the region and the corresponding bitmaps from the same thread.
-    ShenandoahPushWorkerScope scope(workers(), _max_workers, false);
-
-    log_info(gc, heap)("Parallel pretouch " SIZE_FORMAT " regions with " SIZE_FORMAT " byte pages",
-                       _num_regions, page_size);
-    ShenandoahPretouchTask cl(bitmap0.base(), _bitmap_size, page_size);
-    _workers->run_task(&cl);
-  }
-
   // Reserve aux bitmap for use in object_iterate(). We don't commit it here.
   ReservedSpace aux_bitmap(_bitmap_size, bitmap_page_size);
   MemTracker::record_virtual_memory_type(aux_bitmap.base(), mtGC);
   _aux_bitmap_region = MemRegion((HeapWord*) aux_bitmap.base(), aux_bitmap.size() / HeapWordSize);
   _aux_bit_map.initialize(_heap_region, _aux_bitmap_region);
 
-  _traversal_gc = heuristics()->can_do_traversal_gc() ?
-                new ShenandoahTraversalGC(this, _num_regions) :
-                NULL;
-
-  _monitoring_support = new ShenandoahMonitoringSupport(this);
-
-  _phase_timings = new ShenandoahPhaseTimings();
-
-  if (ShenandoahAllocationTrace) {
-    _alloc_tracker = new ShenandoahAllocTracker();
+  //
+  // Create regions and region sets
+  //
+
+  _regions = NEW_C_HEAP_ARRAY(ShenandoahHeapRegion*, _num_regions, mtGC);
+  _free_set = new ShenandoahFreeSet(this, _num_regions);
+  _collection_set = new ShenandoahCollectionSet(this, (HeapWord*)sh_rs.base());
+
+  {
+    ShenandoahHeapLocker locker(lock());
+
+    size_t size_words = ShenandoahHeapRegion::region_size_words();
+
+    for (size_t i = 0; i < _num_regions; i++) {
+      HeapWord* start = (HeapWord*)sh_rs.base() + size_words * i;
+      bool is_committed = i < num_committed_regions;
+      ShenandoahHeapRegion* r = new ShenandoahHeapRegion(this, start, size_words, i, is_committed);
+
+      _marking_context->initialize_top_at_mark_start(r);
+      _regions[i] = r;
+      assert(!collection_set()->is_in(i), "New region should not be in collection set");
+    }
+
+    // Initialize to complete
+    _marking_context->mark_complete();
+
+    _free_set->rebuild();
   }
 
-  ShenandoahStringDedup::initialize();
-
-  _control_thread = new ShenandoahControlThread();
-
-  ShenandoahCodeRoots::initialize();
-
-  log_info(gc, init)("Safepointing mechanism: %s",
-                     SafepointMechanism::uses_thread_local_poll() ? "thread-local poll" :
-                     (SafepointMechanism::uses_global_page_poll() ? "global-page poll" : "unknown"));
+  if (ShenandoahAlwaysPreTouch) {
+    assert(!AlwaysPreTouch, "Should have been overridden");
+
+    // For NUMA, it is important to pre-touch the storage under bitmaps with worker threads,
+    // before initialize() below zeroes it with initializing thread. For any given region,
+    // we touch the region and the corresponding bitmaps from the same thread.
+    ShenandoahPushWorkerScope scope(workers(), _max_workers, false);
+
+    log_info(gc, init)("Pretouch " SIZE_FORMAT " regions; page sizes: " SIZE_FORMAT " heap, " SIZE_FORMAT " bitmap",
+                       _num_regions, heap_page_size, bitmap_page_size);
+    ShenandoahPretouchTask cl(bitmap.base(), _bitmap_size, heap_page_size, bitmap_page_size);
+    _workers->run_task(&cl);
+  }
+
+  //
+  // Initialize the rest of GC subsystems
+  //
 
   _liveness_cache = NEW_C_HEAP_ARRAY(jushort*, _max_workers, mtGC);
   for (uint worker = 0; worker < _max_workers; worker++) {
@@ -304,6 +278,42 @@
     Copy::fill_to_bytes(_liveness_cache[worker], _num_regions * sizeof(jushort));
   }
 
+  // The call below uses stuff (the SATB* things) that are in G1, but probably
+  // belong into a shared location.
+  ShenandoahBarrierSet::satb_mark_queue_set().initialize(this,
+                                                         SATB_Q_CBL_mon,
+                                                         20 /* G1SATBProcessCompletedThreshold */,
+                                                         60 /* G1SATBBufferEnqueueingThresholdPercent */);
+
+  _monitoring_support = new ShenandoahMonitoringSupport(this);
+  _phase_timings = new ShenandoahPhaseTimings();
+  ShenandoahStringDedup::initialize();
+  ShenandoahCodeRoots::initialize();
+
+  if (ShenandoahAllocationTrace) {
+    _alloc_tracker = new ShenandoahAllocTracker();
+  }
+
+  if (ShenandoahPacing) {
+    _pacer = new ShenandoahPacer(this);
+    _pacer->setup_for_idle();
+  } else {
+    _pacer = NULL;
+  }
+
+  _traversal_gc = heuristics()->can_do_traversal_gc() ?
+                  new ShenandoahTraversalGC(this, _num_regions) :
+                  NULL;
+
+  _control_thread = new ShenandoahControlThread();
+
+  log_info(gc, init)("Initialize Shenandoah heap with initial size " SIZE_FORMAT "%s",
+                     byte_size_in_proper_unit(_initial_size), proper_unit_for_byte_size(_initial_size));
+
+  log_info(gc, init)("Safepointing mechanism: %s",
+                     SafepointMechanism::uses_thread_local_poll() ? "thread-local poll" :
+                     (SafepointMechanism::uses_global_page_poll() ? "global-page poll" : "unknown"));
+
   return JNI_OK;
 }
 
@@ -383,6 +393,10 @@
   _soft_ref_policy(),
   _ref_processor(NULL),
   _marking_context(NULL),
+  _bitmap_size(0),
+  _bitmap_regions_per_slice(0),
+  _bitmap_bytes_per_slice(0),
+  _liveness_cache(NULL),
   _collection_set(NULL)
 {
   log_info(gc, init)("GC threads: " UINT32_FORMAT " parallel, " UINT32_FORMAT " concurrent", ParallelGCThreads, ConcGCThreads);
@@ -2768,6 +2782,7 @@
 
 jushort* ShenandoahHeap::get_liveness_cache(uint worker_id) {
 #ifdef ASSERT
+  assert(_liveness_cache != NULL, "sanity");
   assert(worker_id < _max_workers, "sanity");
   for (uint i = 0; i < num_regions(); i++) {
     assert(_liveness_cache[worker_id][i] == 0, "liveness cache should be empty");
@@ -2778,6 +2793,7 @@
 
 void ShenandoahHeap::flush_liveness_cache(uint worker_id) {
   assert(worker_id < _max_workers, "sanity");
+  assert(_liveness_cache != NULL, "sanity");
   jushort* ld = _liveness_cache[worker_id];
   for (uint i = 0; i < num_regions(); i++) {
     ShenandoahHeapRegion* r = get_region(i);
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp	Sun Mar 10 18:53:55 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp	Mon Mar 11 00:06:46 2019 +0100
@@ -486,7 +486,7 @@
   ShenandoahFreeSet*         free_set()          const { return _free_set;          }
   ShenandoahConcurrentMark*  concurrent_mark()         { return _scm;               }
   ShenandoahTraversalGC*     traversal_gc()            { return _traversal_gc;      }
-  ShenandoahPacer*           pacer() const             { return _pacer;             }
+  ShenandoahPacer*           pacer()             const { return _pacer;             }
 
   ShenandoahPhaseTimings*    phase_timings()     const { return _phase_timings;     }
   ShenandoahAllocTracker*    alloc_tracker()     const { return _alloc_tracker;     }
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp	Sun Mar 10 18:53:55 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp	Mon Mar 11 00:06:46 2019 +0100
@@ -56,7 +56,6 @@
 ShenandoahHeapRegion::ShenandoahHeapRegion(ShenandoahHeap* heap, HeapWord* start,
                                            size_t size_words, size_t index, bool committed) :
   _heap(heap),
-  _pacer(ShenandoahPacing ? heap->pacer() : NULL),
   _reserved(MemRegion(start, size_words)),
   _region_number(index),
   _new_top(NULL),
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp	Sun Mar 10 18:53:55 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp	Mon Mar 11 00:06:46 2019 +0100
@@ -227,7 +227,6 @@
 
   // Never updated fields
   ShenandoahHeap* _heap;
-  ShenandoahPacer* _pacer;
   MemRegion _reserved;
   size_t _region_number;
 
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp	Sun Mar 10 18:53:55 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp	Mon Mar 11 00:06:46 2019 +0100
@@ -94,7 +94,7 @@
 inline void ShenandoahHeapRegion::increase_live_data_gc_words(size_t s) {
   internal_increase_live_data(s);
   if (ShenandoahPacing) {
-    _pacer->report_mark(s);
+    _heap->pacer()->report_mark(s);
   }
 }