< prev index next >

src/hotspot/share/gc/parallel/psParallelCompact.cpp

Print this page

        

@@ -123,10 +123,15 @@
 ParallelCompactData::RegionData::dc_claimed = 0x8U << dc_shift;
 
 const ParallelCompactData::RegionData::region_sz_t
 ParallelCompactData::RegionData::dc_completed = 0xcU << dc_shift;
 
+const int ParallelCompactData::RegionData::UNUSED = 0;
+const int ParallelCompactData::RegionData::SHADOW = 1;
+const int ParallelCompactData::RegionData::FILLED = 2;
+const int ParallelCompactData::RegionData::FINISH = 3;
+
 SpaceInfo PSParallelCompact::_space_info[PSParallelCompact::last_space_id];
 
 SpanSubjectToDiscoveryClosure PSParallelCompact::_span_based_discoverer;
 ReferenceProcessor* PSParallelCompact::_ref_processor = NULL;
 

@@ -1021,10 +1026,11 @@
 }
 
 void PSParallelCompact::post_compact()
 {
   GCTraceTime(Info, gc, phases) tm("Post Compact", &_gc_timer);
+  ParCompactionManager::dequeue_shadow_region();
 
   for (unsigned int id = old_space_id; id < last_space_id; ++id) {
     // Clear the marking bitmap, summary data and split info.
     clear_data_covering_space(SpaceId(id));
     // Update top().  Must be done after clearing the bitmap and summary data.

@@ -2415,12 +2421,14 @@
       sd.addr_to_region_idx(sd.region_align_up(new_top));
 
     for (size_t cur = end_region - 1; cur + 1 > beg_region; --cur) {
       if (sd.region(cur)->claim_unsafe()) {
         ParCompactionManager* cm = ParCompactionManager::manager_array(worker_id);
+        if (sd.region(cur)->try_push()) {
         cm->region_stack()->push(cur);
         region_logger.handle(cur);
+        }
         // Assign regions to tasks in round-robin fashion.
         if (++worker_id == parallel_gc_threads) {
           worker_id = 0;
         }
       }

@@ -2596,14 +2604,19 @@
 
   guarantee(cm->region_stack()->is_empty(), "Not empty");
 
   size_t region_index = 0;
 
+  PSParallelCompact::initialize_steal_record(worker_id);
   while (true) {
     if (ParCompactionManager::steal(worker_id, region_index)) {
       PSParallelCompact::fill_and_update_region(cm, region_index);
       cm->drain_region_stacks();
+    } else if (PSParallelCompact::steal_shadow_region(cm, region_index)) {
+      // Keep working with the help of shadow regions
+      PSParallelCompact::fill_and_update_shadow_region(cm, region_index);
+      cm->drain_region_stacks();
     } else {
       if (terminator->offer_termination()) {
         break;
       }
       // Go around again.

@@ -2654,10 +2667,11 @@
   //         push
   //     push
   //
   // max push count is thus: last_space_id * (active_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING + 1)
   TaskQueue task_queue(last_space_id * (active_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING + 1));
+  enqueue_shadow_region();
   prepare_region_draining_tasks(active_gc_threads);
   enqueue_dense_prefix_tasks(task_queue, active_gc_threads);
 
   {
     GCTraceTime(Trace, gc, phases) tm("Par Compact", &_gc_timer);

@@ -2960,11 +2974,19 @@
 
   for (RegionData* cur = beg; cur < end; ++cur) {
     assert(cur->data_size() > 0, "region must have live data");
     cur->decrement_destination_count();
     if (cur < enqueue_end && cur->available() && cur->claim()) {
+      if (cur->try_push()) {
       cm->push_region(sd.region(cur));
+      } else if (cur->try_copy()) {
+        // Try to copy the content of the shadow region back to its corresponding
+        // heap region if the shadow region is filled
+        copy_back(sd.region_to_addr(cur->shadow_region()), sd.region_to_addr(cur));
+        cm->release_shadow_region(cur->shadow_region());
+        cur->set_completed();
+      }
     }
   }
 }
 
 size_t PSParallelCompact::next_src_region(MoveAndUpdateClosure& closure,

@@ -3038,32 +3060,24 @@
 
   assert(false, "no source region was found");
   return 0;
 }
 
-void PSParallelCompact::fill_region(ParCompactionManager* cm, size_t region_idx)
+void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosure& closure, size_t region_idx)
 {
   typedef ParMarkBitMap::IterationStatus IterationStatus;
   const size_t RegionSize = ParallelCompactData::RegionSize;
   ParMarkBitMap* const bitmap = mark_bitmap();
   ParallelCompactData& sd = summary_data();
   RegionData* const region_ptr = sd.region(region_idx);
 
-  // Get the items needed to construct the closure.
-  HeapWord* dest_addr = sd.region_to_addr(region_idx);
-  SpaceId dest_space_id = space_id(dest_addr);
-  ObjectStartArray* start_array = _space_info[dest_space_id].start_array();
-  HeapWord* new_top = _space_info[dest_space_id].new_top();
-  assert(dest_addr < new_top, "sanity");
-  const size_t words = MIN2(pointer_delta(new_top, dest_addr), RegionSize);
-
   // Get the source region and related info.
   size_t src_region_idx = region_ptr->source_region();
   SpaceId src_space_id = space_id(sd.region_to_addr(src_region_idx));
   HeapWord* src_space_top = _space_info[src_space_id].space()->top();
+  HeapWord* dest_addr = sd.region_to_addr(region_idx);
 
-  MoveAndUpdateClosure closure(bitmap, cm, start_array, dest_addr, words);
   closure.set_source(first_src_addr(dest_addr, src_space_id, src_region_idx));
 
   // Adjust src_region_idx to prepare for decrementing destination counts (the
   // destination count is not decremented when a region is copied to itself).
   if (src_region_idx == region_idx) {

@@ -3078,11 +3092,11 @@
     closure.copy_partial_obj();
     if (closure.is_full()) {
       decrement_destination_counts(cm, src_space_id, src_region_idx,
                                    closure.source());
       region_ptr->set_deferred_obj_addr(NULL);
-      region_ptr->set_completed();
+      closure.complete_region(cm, dest_addr, region_ptr);
       return;
     }
 
     HeapWord* const end_addr = sd.region_align_down(closure.source());
     if (sd.region_align_down(old_src_addr) != end_addr) {

@@ -3123,23 +3137,24 @@
 
     if (status == ParMarkBitMap::would_overflow) {
       // The last object did not fit.  Note that interior oop updates were
       // deferred, then copy enough of the object to fill the region.
       region_ptr->set_deferred_obj_addr(closure.destination());
+
       status = closure.copy_until_full(); // copies from closure.source()
 
       decrement_destination_counts(cm, src_space_id, src_region_idx,
                                    closure.source());
-      region_ptr->set_completed();
+      closure.complete_region(cm, dest_addr, region_ptr);
       return;
     }
 
     if (status == ParMarkBitMap::full) {
       decrement_destination_counts(cm, src_space_id, src_region_idx,
                                    closure.source());
       region_ptr->set_deferred_obj_addr(NULL);
-      region_ptr->set_completed();
+      closure.complete_region(cm, dest_addr, region_ptr);
       return;
     }
 
     decrement_destination_counts(cm, src_space_id, src_region_idx, end_addr);
 

@@ -3148,10 +3163,80 @@
     src_region_idx = next_src_region(closure, src_space_id, src_space_top,
                                      end_addr);
   } while (true);
 }
 
+void PSParallelCompact::fill_and_update_region(ParCompactionManager* cm, size_t region_idx) {
+  MoveAndUpdateClosure cl(mark_bitmap(), cm, region_idx);
+  fill_region(cm, cl, region_idx);
+}
+
+void PSParallelCompact::fill_shadow_region(ParCompactionManager* cm, size_t region_idx)
+{
+  // Acquire a shadow region at first
+  ParallelCompactData& sd = summary_data();
+  RegionData* const region_ptr = sd.region(region_idx);
+  size_t shadow_region = cm->acquire_shadow_region(region_ptr);
+  // The zero return value indicates the corresponding heap region is available,
+  // so use MoveAndUpdateClosure to fill the normal region. Otherwise, use
+  // ShadowClosure to fill the acquired shadow region.
+  if (shadow_region == 0) {
+    MoveAndUpdateClosure cl(mark_bitmap(), cm, region_idx);
+    region_ptr->mark_normal();
+    return fill_region(cm, cl, region_idx);
+  } else {
+    ShadowClosure cl(mark_bitmap(), cm, region_idx, shadow_region);
+    return fill_region(cm, cl, region_idx);
+  }
+}
+
+void PSParallelCompact::copy_back(HeapWord *shadow_addr, HeapWord *region_addr) {
+  Copy::aligned_conjoint_words(shadow_addr, region_addr, _summary_data.RegionSize);
+}
+
+bool PSParallelCompact::steal_shadow_region(ParCompactionManager* cm, size_t &region_idx) {
+  size_t record = cm->shadow_record();
+  ParallelCompactData& sd = _summary_data;
+  size_t old_new_top = sd.addr_to_region_idx(_space_info[old_space_id].new_top());
+  uint active_gc_threads = ParallelScavengeHeap::heap()->workers().active_workers();
+
+  while (record < old_new_top) {
+    if (sd.region(record)->try_steal()) {
+      region_idx = record;
+      return true;
+    }
+    record = cm->next_shadow_record(active_gc_threads);
+  }
+
+  return false;
+}
+
+void PSParallelCompact::enqueue_shadow_region() {
+  const ParallelCompactData& sd = PSParallelCompact::summary_data();
+
+  for (unsigned int id = old_space_id; id < last_space_id; ++id) {
+    SpaceInfo* const space_info = _space_info + id;
+    MutableSpace* const space = space_info->space();
+
+    const size_t beg_region =
+      sd.addr_to_region_idx(sd.region_align_up(MAX2(space_info->new_top(), space->top())));
+    const size_t end_region =
+      sd.addr_to_region_idx(sd.region_align_down(space->end()));
+
+    for (size_t cur = beg_region + 1; cur < end_region; ++cur) {
+      ParCompactionManager::enqueue_shadow_region(cur);
+    }
+  }
+}
+
+void PSParallelCompact::initialize_steal_record(uint which) {
+  ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which);
+
+  size_t record = _summary_data.addr_to_region_idx(_space_info[old_space_id].dense_prefix());
+  cm->set_shadow_record(record + which);
+}
+
 void PSParallelCompact::fill_blocks(size_t region_idx)
 {
   // Fill in the block table elements for the specified region.  Each block
   // table element holds the number of live words in the region that are to the
   // left of the first object that starts in the block.  Thus only blocks in

@@ -3220,13 +3305,13 @@
   _time_of_last_gc = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
 }
 
 ParMarkBitMap::IterationStatus MoveAndUpdateClosure::copy_until_full()
 {
-  if (source() != destination()) {
+  if (source() != copy_destination()) {
     DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());)
-    Copy::aligned_conjoint_words(source(), destination(), words_remaining());
+    Copy::aligned_conjoint_words(source(), copy_destination(), words_remaining());
   }
   update_state(words_remaining());
   assert(is_full(), "sanity");
   return ParMarkBitMap::full;
 }

@@ -3241,17 +3326,23 @@
     words = bitmap()->obj_size(source(), end_addr);
   }
 
   // This test is necessary; if omitted, the pointer updates to a partial object
   // that crosses the dense prefix boundary could be overwritten.
-  if (source() != destination()) {
+  if (source() != copy_destination()) {
     DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());)
-    Copy::aligned_conjoint_words(source(), destination(), words);
+    Copy::aligned_conjoint_words(source(), copy_destination(), words);
   }
   update_state(words);
 }
 
+void MoveAndUpdateClosure::complete_region(ParCompactionManager *cm, HeapWord *dest_addr,
+                                           PSParallelCompact::RegionData *region_ptr) {
+  assert(region_ptr->shadow_state() == ParallelCompactData::RegionData::FINISH, "Region should be finished");
+  region_ptr->set_completed();
+}
+
 ParMarkBitMapClosure::IterationStatus
 MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) {
   assert(destination() != NULL, "sanity");
   assert(bitmap()->obj_size(addr) == words, "bad size");
 

@@ -3266,24 +3357,40 @@
   // The start_array must be updated even if the object is not moving.
   if (_start_array != NULL) {
     _start_array->allocate_block(destination());
   }
 
-  if (destination() != source()) {
+  if (copy_destination() != source()) {
     DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());)
-    Copy::aligned_conjoint_words(source(), destination(), words);
+    Copy::aligned_conjoint_words(source(), copy_destination(), words);
   }
 
-  oop moved_oop = (oop) destination();
+  oop moved_oop = (oop) copy_destination();
   compaction_manager()->update_contents(moved_oop);
   assert(oopDesc::is_oop_or_null(moved_oop), "Expected an oop or NULL at " PTR_FORMAT, p2i(moved_oop));
 
   update_state(words);
-  assert(destination() == (HeapWord*)moved_oop + moved_oop->size(), "sanity");
+  assert(copy_destination() == (HeapWord*)moved_oop + moved_oop->size(), "sanity");
   return is_full() ? ParMarkBitMap::full : ParMarkBitMap::incomplete;
 }
 
+void ShadowClosure::complete_region(ParCompactionManager *cm, HeapWord *dest_addr,
+                                    PSParallelCompact::RegionData *region_ptr) {
+  assert(region_ptr->shadow_state() == ParallelCompactData::RegionData::SHADOW, "Region should be shadow");
+  // Record the shadow region index
+  region_ptr->set_shadow_region(_shadow);
+  // Mark the shadow region filled
+  region_ptr->mark_filled();
+  // Try to copy the content of the shadow region back to its corresponding
+  // heap region if available
+  if (((region_ptr->available() && region_ptr->claim()) || region_ptr->claimed()) && region_ptr->try_copy()) {
+    region_ptr->set_completed();
+    PSParallelCompact::copy_back(PSParallelCompact::summary_data().region_to_addr(_shadow), dest_addr);
+    cm->release_shadow_region(_shadow);
+  }
+}
+
 UpdateOnlyClosure::UpdateOnlyClosure(ParMarkBitMap* mbm,
                                      ParCompactionManager* cm,
                                      PSParallelCompact::SpaceId space_id) :
   ParMarkBitMapClosure(mbm, cm),
   _space_id(space_id),
< prev index next >