src/hotspot/share/gc/shared/referenceProcessor.cpp
changeset 50606 8f1d5d706bdd
parent 50605 7f63c74f0974
child 50920 d9160a3c97c1
--- a/src/hotspot/share/gc/shared/referenceProcessor.cpp	Tue May 29 09:26:00 2018 +0200
+++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp	Mon Jun 18 12:11:59 2018 +0200
@@ -99,13 +99,15 @@
                                        bool      mt_discovery,
                                        uint      mt_discovery_degree,
                                        bool      atomic_discovery,
-                                       BoolObjectClosure* is_alive_non_header)  :
+                                       BoolObjectClosure* is_alive_non_header,
+                                       bool      adjust_no_of_processing_threads)  :
   _is_subject_to_discovery(is_subject_to_discovery),
   _discovering_refs(false),
   _enqueuing_is_done(false),
   _is_alive_non_header(is_alive_non_header),
   _processing_is_mt(mt_processing),
-  _next_id(0)
+  _next_id(0),
+  _adjust_no_of_processing_threads(adjust_no_of_processing_threads)
 {
   assert(is_subject_to_discovery != NULL, "must be set");
 
@@ -679,7 +681,8 @@
 }
 
 void ReferenceProcessor::maybe_balance_queues(DiscoveredList refs_lists[]) {
-  if (_processing_is_mt && need_balance_queues(refs_lists)) {
+  assert(_processing_is_mt, "Should not call this otherwise");
+  if (need_balance_queues(refs_lists)) {
     balance_queues(refs_lists);
   }
 }
@@ -768,22 +771,30 @@
 #endif
 }
 
+bool ReferenceProcessor::is_mt_processing_set_up(AbstractRefProcTaskExecutor* task_executor) const {
+  return task_executor != NULL && _processing_is_mt;
+}
+
 void ReferenceProcessor::process_soft_ref_reconsider(BoolObjectClosure* is_alive,
                                                      OopClosure* keep_alive,
                                                      VoidClosure* complete_gc,
-                                                     AbstractRefProcTaskExecutor*  task_executor,
+                                                     AbstractRefProcTaskExecutor* task_executor,
                                                      ReferenceProcessorPhaseTimes* phase_times) {
   assert(!_processing_is_mt || task_executor != NULL, "Task executor must not be NULL when mt processing is set.");
 
-  phase_times->set_ref_discovered(REF_SOFT, total_count(_discoveredSoftRefs));
+  size_t const num_soft_refs = total_count(_discoveredSoftRefs);
+  phase_times->set_ref_discovered(REF_SOFT, num_soft_refs);
 
-  if (_current_soft_ref_policy == NULL) {
+  phase_times->set_processing_is_mt(_processing_is_mt);
+
+  if (num_soft_refs == 0 || _current_soft_ref_policy == NULL) {
+    log_debug(gc, ref)("Skipped phase1 of Reference Processing due to unavailable references");
     return;
   }
 
-  phase_times->set_processing_is_mt(_processing_is_mt);
+  RefProcMTDegreeAdjuster a(this, RefPhase1, num_soft_refs);
 
-  {
+  if (_processing_is_mt) {
     RefProcBalanceQueuesTimeTracker tt(RefPhase1, phase_times);
     maybe_balance_queues(_discoveredSoftRefs);
   }
@@ -793,7 +804,7 @@
   log_reflist("Phase1 Soft before", _discoveredSoftRefs, _max_num_queues);
   if (_processing_is_mt) {
     RefProcPhase1Task phase1(*this, phase_times, _current_soft_ref_policy);
-    task_executor->execute(phase1);
+    task_executor->execute(phase1, num_queues());
   } else {
     size_t removed = 0;
 
@@ -815,12 +826,23 @@
                                                       ReferenceProcessorPhaseTimes* phase_times) {
   assert(!_processing_is_mt || task_executor != NULL, "Task executor must not be NULL when mt processing is set.");
 
-  phase_times->set_ref_discovered(REF_WEAK, total_count(_discoveredWeakRefs));
-  phase_times->set_ref_discovered(REF_FINAL, total_count(_discoveredFinalRefs));
+  size_t const num_soft_refs = total_count(_discoveredSoftRefs);
+  size_t const num_weak_refs = total_count(_discoveredWeakRefs);
+  size_t const num_final_refs = total_count(_discoveredFinalRefs);
+  size_t const num_total_refs = num_soft_refs + num_weak_refs + num_final_refs;
+  phase_times->set_ref_discovered(REF_WEAK, num_weak_refs);
+  phase_times->set_ref_discovered(REF_FINAL, num_final_refs);
 
   phase_times->set_processing_is_mt(_processing_is_mt);
 
-  {
+  if (num_total_refs == 0) {
+    log_debug(gc, ref)("Skipped phase2 of Reference Processing due to unavailable references");
+    return;
+  }
+
+  RefProcMTDegreeAdjuster a(this, RefPhase2, num_total_refs);
+
+  if (_processing_is_mt) {
     RefProcBalanceQueuesTimeTracker tt(RefPhase2, phase_times);
     maybe_balance_queues(_discoveredSoftRefs);
     maybe_balance_queues(_discoveredWeakRefs);
@@ -834,7 +856,7 @@
   log_reflist("Phase2 Final before", _discoveredFinalRefs, _max_num_queues);
   if (_processing_is_mt) {
     RefProcPhase2Task phase2(*this, phase_times);
-    task_executor->execute(phase2);
+    task_executor->execute(phase2, num_queues());
   } else {
     RefProcWorkerTimeTracker t(phase_times->phase2_worker_time_sec(), 0);
     {
@@ -880,9 +902,18 @@
                                                   ReferenceProcessorPhaseTimes* phase_times) {
   assert(!_processing_is_mt || task_executor != NULL, "Task executor must not be NULL when mt processing is set.");
 
+  size_t const num_final_refs = total_count(_discoveredFinalRefs);
+
   phase_times->set_processing_is_mt(_processing_is_mt);
 
-  {
+  if (num_final_refs == 0) {
+    log_debug(gc, ref)("Skipped phase3 of Reference Processing due to unavailable references");
+    return;
+  }
+
+  RefProcMTDegreeAdjuster a(this, RefPhase3, num_final_refs);
+
+  if (_processing_is_mt) {
     RefProcBalanceQueuesTimeTracker tt(RefPhase3, phase_times);
     maybe_balance_queues(_discoveredFinalRefs);
   }
@@ -893,7 +924,7 @@
 
   if (_processing_is_mt) {
     RefProcPhase3Task phase3(*this, phase_times);
-    task_executor->execute(phase3);
+    task_executor->execute(phase3, num_queues());
   } else {
     RefProcSubPhasesWorkerTimeTracker tt2(FinalRefSubPhase3, phase_times, 0);
     for (uint i = 0; i < _max_num_queues; i++) {
@@ -910,11 +941,19 @@
                                               ReferenceProcessorPhaseTimes* phase_times) {
   assert(!_processing_is_mt || task_executor != NULL, "Task executor must not be NULL when mt processing is set.");
 
-  phase_times->set_ref_discovered(REF_PHANTOM, total_count(_discoveredPhantomRefs));
+  size_t const num_phantom_refs = total_count(_discoveredPhantomRefs);
+  phase_times->set_ref_discovered(REF_PHANTOM, num_phantom_refs);
 
   phase_times->set_processing_is_mt(_processing_is_mt);
 
-  {
+  if (num_phantom_refs == 0) {
+    log_debug(gc, ref)("Skipped phase4 of Reference Processing due to unavailable references");
+    return;
+  }
+
+  RefProcMTDegreeAdjuster a(this, RefPhase4, num_phantom_refs);
+
+  if (_processing_is_mt) {
     RefProcBalanceQueuesTimeTracker tt(RefPhase4, phase_times);
     maybe_balance_queues(_discoveredPhantomRefs);
   }
@@ -925,7 +964,7 @@
   log_reflist("Phase4 Phantom before", _discoveredPhantomRefs, _max_num_queues);
   if (_processing_is_mt) {
     RefProcPhase4Task phase4(*this, phase_times);
-    task_executor->execute(phase4);
+    task_executor->execute(phase4, num_queues());
   } else {
     size_t removed = 0;
 
@@ -1308,3 +1347,45 @@
    ShouldNotReachHere();
    return NULL;
 }
+
+uint RefProcMTDegreeAdjuster::ergo_proc_thread_count(size_t ref_count,
+                                                     uint max_threads,
+                                                     RefProcPhases phase) const {
+  assert(0 < max_threads, "must allow at least one thread");
+
+  if (use_max_threads(phase) || (ReferencesPerThread == 0)) {
+    return max_threads;
+  }
+
+  size_t thread_count = 1 + (ref_count / ReferencesPerThread);
+  return (uint)MIN3(thread_count,
+                    static_cast<size_t>(max_threads),
+                    (size_t)os::active_processor_count());
+}
+
+bool RefProcMTDegreeAdjuster::use_max_threads(RefProcPhases phase) const {
+  // Even a small number of references in either of those cases could produce large amounts of work.
+  return (phase == ReferenceProcessor::RefPhase1 || phase == ReferenceProcessor::RefPhase3);
+}
+
+RefProcMTDegreeAdjuster::RefProcMTDegreeAdjuster(ReferenceProcessor* rp,
+                                                 RefProcPhases phase,
+                                                 size_t ref_count):
+    _rp(rp),
+    _saved_mt_processing(_rp->processing_is_mt()),
+    _saved_num_queues(_rp->num_queues()) {
+  if (!_rp->processing_is_mt() || !_rp->adjust_no_of_processing_threads() || (ReferencesPerThread == 0)) {
+    return;
+  }
+
+  uint workers = ergo_proc_thread_count(ref_count, _rp->num_queues(), phase);
+
+  _rp->set_mt_processing(workers > 1);
+  _rp->set_active_mt_degree(workers);
+}
+
+RefProcMTDegreeAdjuster::~RefProcMTDegreeAdjuster() {
+  // Revert to previous status.
+  _rp->set_mt_processing(_saved_mt_processing);
+  _rp->set_active_mt_degree(_saved_num_queues);
+}