--- 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);
+}