src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp

Print this page

        

@@ -565,10 +565,11 @@
   _overflow_list(NULL),
   _stats(cmsGen),
   _eden_chunk_array(NULL),     // may be set in ctor body
   _eden_chunk_capacity(0),     // -- ditto --
   _eden_chunk_index(0),        // -- ditto --
+  _eden_chunk_sampling_active(0),
   _survivor_plab_array(NULL),  // -- ditto --
   _survivor_chunk_array(NULL), // -- ditto --
   _survivor_chunk_capacity(0), // -- ditto --
   _survivor_chunk_index(0),    // -- ditto --
   _ser_pmc_preclean_ovflw(0),

@@ -2098,10 +2099,43 @@
   // For a mark-sweep, compute_new_size() will be called
   // in the heap's do_collection() method.
 }
 
 
+void CMSCollector::print_eden_and_survivor_chunk_arrays() {
+  DefNewGeneration* dng = _young_gen->as_DefNewGeneration();
+  EdenSpace* eden_space = dng->eden();
+  ContiguousSpace* from_space = dng->from();
+  ContiguousSpace* to_space   = dng->to();
+  // Eden
+  if (_eden_chunk_array) {
+    gclog_or_tty->print_cr("eden " PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "(" SIZE_FORMAT ")",
+                           eden_space->bottom(), eden_space->top(),
+                           eden_space->end(), eden_space->capacity());
+    gclog_or_tty->print_cr("_eden_chunk_index=" SIZE_FORMAT ", "
+                           "_eden_chunk_capacity=" SIZE_FORMAT,
+                           _eden_chunk_index, _eden_chunk_capacity);
+    for (size_t i = 0; i < _eden_chunk_index; i++) {
+      gclog_or_tty->print_cr("_eden_chunk_array[" SIZE_FORMAT "]=" PTR_FORMAT,
+                             i, _eden_chunk_array[i]);
+    }
+  }
+  // Survivor
+  if (_survivor_chunk_array) {
+    gclog_or_tty->print_cr("survivor " PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "(" SIZE_FORMAT ")",
+                           from_space->bottom(), from_space->top(),
+                           from_space->end(), from_space->capacity());
+    gclog_or_tty->print_cr("_survivor_chunk_index=" SIZE_FORMAT ", "
+                           "_survivor_chunk_capacity=" SIZE_FORMAT,
+                           _survivor_chunk_index, _survivor_chunk_capacity);
+    for (size_t i = 0; i < _survivor_chunk_index; i++) {
+      gclog_or_tty->print_cr("_survivor_chunk_array[" SIZE_FORMAT "]=" PTR_FORMAT,
+                             i, _survivor_chunk_array[i]);
+    }
+  }
+}
+
 void CMSCollector::getFreelistLocks() const {
   // Get locks for all free lists in all generations that this
   // collector is responsible for
   _cmsGen->freelistLock()->lock_without_safepoint_check();
 }

@@ -3589,10 +3623,14 @@
 
   // Whenever a CLD is found, it will be claimed before proceeding to mark
   // the klasses. The claimed marks need to be cleared before marking starts.
   ClassLoaderDataGraph::clear_claimed_marks();
 
+  if (CMSPrintEdenSurvivorChunks) {
+    print_eden_and_survivor_chunk_arrays();
+  }
+
   CMKlassClosure klass_closure(&notOlder);
   {
     COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;)
     gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
     gch->gen_process_strong_roots(_cmsGen->level(),

@@ -4360,11 +4398,13 @@
   assert(Thread::current()->is_ConcurrentGC_thread(), "Wrong thread");
   verify_work_stacks_empty();
   verify_overflow_empty();
   _abort_preclean = false;
   if (CMSPrecleaningEnabled) {
+    if (!CMSEdenChunksRecordAlways) {
     _eden_chunk_index = 0;
+    }
     size_t used = get_eden_used();
     size_t capacity = get_eden_capacity();
     // Don't start sampling unless we will get sufficiently
     // many samples.
     if (used < (capacity/(CMSScheduleRemarkSamplingRatio * 100)

@@ -4469,11 +4509,13 @@
   assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
          "Should collect samples while holding CMS token");
   if (!_start_sampling) {
     return;
   }
-  if (_eden_chunk_array) {
+  // When CMSEdenChunksRecordAlways is true, the eden chunk array
+  // is populated by the young generation.
+  if (_eden_chunk_array && !CMSEdenChunksRecordAlways) {
     if (_eden_chunk_index < _eden_chunk_capacity) {
       _eden_chunk_array[_eden_chunk_index] = *_top_addr;   // take sample
       assert(_eden_chunk_array[_eden_chunk_index] <= *_end_addr,
              "Unexpected state of Eden");
       // We'd like to check that what we just sampled is an oop-start address;

@@ -4951,10 +4993,14 @@
     // so here just in case a scavenge did not happen.
     gch->ensure_parsability(false);  // fill TLAB's, but no need to retire them
     // Update the saved marks which may affect the root scans.
     gch->save_marks();
 
+    if (CMSPrintEdenSurvivorChunks) {
+      print_eden_and_survivor_chunk_arrays();
+    }
+
     {
       COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;)
 
       // Note on the role of the mod union table:
       // Since the marker in "markFromRoots" marks concurrently with

@@ -5469,10 +5515,62 @@
   )
   assert(work_q->size() == 0 && _collector->overflow_list_is_empty(),
          "Else our work is not yet done");
 }
 
+// Record object boundaries in _eden_chunk_array by sampling the eden
+// top in the slow-path eden object allocation code path and record
+// the boundaries, if CMSEdenChunksRecordAlways is true. If
+// CMSEdenChunksRecordAlways is false, we use the other asynchronous
+// sampling in sample_eden() that activates during the part of the
+// preclean phase.
+void CMSCollector::sample_eden_chunk() {
+  // A CAS-based (lock-free) sampling mechanism. Since this is called
+  // from the young gen allocation code path (albeit the slow path),
+  // it's important that this code is quick.
+  if (CMSEdenChunksRecordAlways && _eden_chunk_array) {
+    bool do_sampling = false;
+    do {
+      jbyte sampling_active = _eden_chunk_sampling_active;
+      if (sampling_active == 0) {
+        // No sampling is ongoing. Try to get sampled.
+        jbyte result = Atomic::cmpxchg((jbyte)1,
+                                       &_eden_chunk_sampling_active,
+                                       (jbyte)0);
+        if (result == 0) {
+          // CAS success. Will take a sample.
+          do_sampling = true;
+          break;
+        }
+      } else {
+        break;
+      }
+    } while (true);
+    if (do_sampling) {
+      // Record a sample. This is the critical section. The contents
+      // of the _eden_chunk_array have to be non-decreasing in the
+      // address order.
+      _eden_chunk_array[_eden_chunk_index] = *_top_addr;
+      assert(_eden_chunk_array[_eden_chunk_index] <= *_end_addr,
+             "Unexpected state of Eden");
+      if (_eden_chunk_index == 0 ||
+          ((_eden_chunk_array[_eden_chunk_index] > _eden_chunk_array[_eden_chunk_index-1]) &&
+           (pointer_delta(_eden_chunk_array[_eden_chunk_index],
+                          _eden_chunk_array[_eden_chunk_index-1]) >= CMSSamplingGrain))) {
+        _eden_chunk_index++;  // commit sample
+      }
+      assert(_eden_chunk_sampling_active == 1, "Mutual exclusivity");
+      // Indicate that the current sampling has ended and let the next
+      // sampling attempt in.
+      jbyte result = Atomic::cmpxchg((jbyte)0,
+                                     &_eden_chunk_sampling_active,
+                                     (jbyte)1);
+      assert(result == 1, "CAS must succeed");
+    }
+  }
+}
+
 // Return a thread-local PLAB recording array, as appropriate.
 void* CMSCollector::get_data_recorder(int thr_num) {
   if (_survivor_plab_array != NULL &&
       (CMSPLABRecordAlways ||
        (_collectorState > Marking && _collectorState < FinalMarking))) {

@@ -9308,6 +9406,5 @@
 
     default:
       ShouldNotReachHere();
   }
 }
-