mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-20 21:03:18 +00:00
8231672: Simplify the reference processing parallelization framework
Reviewed-by: tschatzl, ayang
This commit is contained in:
parent
392f962e0e
commit
6ef46ce386
@ -3051,7 +3051,7 @@ bool G1ParEvacuateFollowersClosure::offer_termination() {
|
||||
EventGCPhaseParallel event;
|
||||
G1ParScanThreadState* const pss = par_scan_state();
|
||||
start_term_time();
|
||||
const bool res = terminator()->offer_termination();
|
||||
const bool res = (terminator() == nullptr) ? true : terminator()->offer_termination();
|
||||
end_term_time();
|
||||
event.commit(GCId::current(), pss->worker_id(), G1GCPhaseTimes::phase_name(G1GCPhaseTimes::Termination));
|
||||
return res;
|
||||
@ -3182,99 +3182,35 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Parallel Reference Processing closures
|
||||
|
||||
// Implementation of AbstractRefProcTaskExecutor for parallel reference
|
||||
// processing during G1 evacuation pauses.
|
||||
|
||||
class G1STWRefProcTaskExecutor: public AbstractRefProcTaskExecutor {
|
||||
private:
|
||||
G1CollectedHeap* _g1h;
|
||||
G1ParScanThreadStateSet* _pss;
|
||||
G1ScannerTasksQueueSet* _queues;
|
||||
WorkGang* _workers;
|
||||
class G1STWRefProcProxyTask : public RefProcProxyTask {
|
||||
G1CollectedHeap& _g1h;
|
||||
G1ParScanThreadStateSet& _pss;
|
||||
TaskTerminator _terminator;
|
||||
G1ScannerTasksQueueSet& _task_queues;
|
||||
|
||||
public:
|
||||
G1STWRefProcTaskExecutor(G1CollectedHeap* g1h,
|
||||
G1ParScanThreadStateSet* per_thread_states,
|
||||
WorkGang* workers,
|
||||
G1ScannerTasksQueueSet *task_queues) :
|
||||
_g1h(g1h),
|
||||
_pss(per_thread_states),
|
||||
_queues(task_queues),
|
||||
_workers(workers)
|
||||
{
|
||||
g1h->ref_processor_stw()->set_active_mt_degree(workers->active_workers());
|
||||
G1STWRefProcProxyTask(uint max_workers, G1CollectedHeap& g1h, G1ParScanThreadStateSet& pss, G1ScannerTasksQueueSet& task_queues)
|
||||
: RefProcProxyTask("G1STWRefProcProxyTask", max_workers),
|
||||
_g1h(g1h),
|
||||
_pss(pss),
|
||||
_terminator(max_workers, &task_queues),
|
||||
_task_queues(task_queues) {}
|
||||
|
||||
void work(uint worker_id) override {
|
||||
assert(worker_id < _max_workers, "sanity");
|
||||
uint index = (_tm == RefProcThreadModel::Single) ? 0 : worker_id;
|
||||
_pss.state_for_worker(index)->set_ref_discoverer(nullptr);
|
||||
G1STWIsAliveClosure is_alive(&_g1h);
|
||||
G1CopyingKeepAliveClosure keep_alive(&_g1h, _pss.state_for_worker(index));
|
||||
G1ParEvacuateFollowersClosure complete_gc(&_g1h, _pss.state_for_worker(index), &_task_queues, _tm == RefProcThreadModel::Single ? nullptr : &_terminator, G1GCPhaseTimes::ObjCopy);
|
||||
_rp_task->rp_work(worker_id, &is_alive, &keep_alive, &complete_gc);
|
||||
}
|
||||
|
||||
// Executes the given task using concurrent marking worker threads.
|
||||
virtual void execute(ProcessTask& task, uint ergo_workers);
|
||||
};
|
||||
|
||||
// Gang task for possibly parallel reference processing
|
||||
|
||||
class G1STWRefProcTaskProxy: public AbstractGangTask {
|
||||
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
|
||||
ProcessTask& _proc_task;
|
||||
G1CollectedHeap* _g1h;
|
||||
G1ParScanThreadStateSet* _pss;
|
||||
G1ScannerTasksQueueSet* _task_queues;
|
||||
TaskTerminator* _terminator;
|
||||
|
||||
public:
|
||||
G1STWRefProcTaskProxy(ProcessTask& proc_task,
|
||||
G1CollectedHeap* g1h,
|
||||
G1ParScanThreadStateSet* per_thread_states,
|
||||
G1ScannerTasksQueueSet *task_queues,
|
||||
TaskTerminator* terminator) :
|
||||
AbstractGangTask("Process reference objects in parallel"),
|
||||
_proc_task(proc_task),
|
||||
_g1h(g1h),
|
||||
_pss(per_thread_states),
|
||||
_task_queues(task_queues),
|
||||
_terminator(terminator)
|
||||
{}
|
||||
|
||||
virtual void work(uint worker_id) {
|
||||
// The reference processing task executed by a single worker.
|
||||
ResourceMark rm;
|
||||
|
||||
G1STWIsAliveClosure is_alive(_g1h);
|
||||
|
||||
G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
|
||||
pss->set_ref_discoverer(NULL);
|
||||
|
||||
// Keep alive closure.
|
||||
G1CopyingKeepAliveClosure keep_alive(_g1h, pss);
|
||||
|
||||
// Complete GC closure
|
||||
G1ParEvacuateFollowersClosure drain_queue(_g1h, pss, _task_queues, _terminator, G1GCPhaseTimes::ObjCopy);
|
||||
|
||||
// Call the reference processing task's work routine.
|
||||
_proc_task.work(worker_id, is_alive, keep_alive, drain_queue);
|
||||
|
||||
// Note we cannot assert that the refs array is empty here as not all
|
||||
// of the processing tasks (specifically phase2 - pp2_work) execute
|
||||
// the complete_gc closure (which ordinarily would drain the queue) so
|
||||
// the queue may not be empty.
|
||||
void prepare_run_task_hook() override {
|
||||
_terminator.reset_for_reuse(_queue_count);
|
||||
}
|
||||
};
|
||||
|
||||
// Driver routine for parallel reference processing.
|
||||
// Creates an instance of the ref processing gang
|
||||
// task and has the worker threads execute it.
|
||||
void G1STWRefProcTaskExecutor::execute(ProcessTask& proc_task, uint ergo_workers) {
|
||||
assert(_workers != NULL, "Need parallel worker threads.");
|
||||
|
||||
assert(_workers->active_workers() >= ergo_workers,
|
||||
"Ergonomically chosen workers (%u) should be less than or equal to active workers (%u)",
|
||||
ergo_workers, _workers->active_workers());
|
||||
TaskTerminator terminator(ergo_workers, _queues);
|
||||
G1STWRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _pss, _queues, &terminator);
|
||||
|
||||
_workers->run_task(&proc_task_proxy, ergo_workers);
|
||||
}
|
||||
|
||||
// End of weak reference support closures
|
||||
|
||||
void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per_thread_states) {
|
||||
@ -3283,53 +3219,27 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per
|
||||
ReferenceProcessor* rp = _ref_processor_stw;
|
||||
assert(rp->discovery_enabled(), "should have been enabled");
|
||||
|
||||
// Closure to test whether a referent is alive.
|
||||
G1STWIsAliveClosure is_alive(this);
|
||||
|
||||
// Even when parallel reference processing is enabled, the processing
|
||||
// of JNI refs is serial and performed serially by the current thread
|
||||
// rather than by a worker. The following PSS will be used for processing
|
||||
// JNI refs.
|
||||
|
||||
// Use only a single queue for this PSS.
|
||||
G1ParScanThreadState* pss = per_thread_states->state_for_worker(0);
|
||||
pss->set_ref_discoverer(NULL);
|
||||
assert(pss->queue_is_empty(), "pre-condition");
|
||||
|
||||
// Keep alive closure.
|
||||
G1CopyingKeepAliveClosure keep_alive(this, pss);
|
||||
|
||||
// Serial Complete GC closure
|
||||
G1STWDrainQueueClosure drain_queue(this, pss);
|
||||
|
||||
// Setup the soft refs policy...
|
||||
rp->setup_policy(false);
|
||||
|
||||
ReferenceProcessorPhaseTimes* pt = phase_times()->ref_phase_times();
|
||||
ReferenceProcessorPhaseTimes& pt = *phase_times()->ref_phase_times();
|
||||
|
||||
ReferenceProcessorStats stats;
|
||||
if (!rp->processing_is_mt()) {
|
||||
// Serial reference processing...
|
||||
stats = rp->process_discovered_references(&is_alive,
|
||||
&keep_alive,
|
||||
&drain_queue,
|
||||
NULL,
|
||||
pt);
|
||||
} else {
|
||||
uint no_of_gc_workers = workers()->active_workers();
|
||||
uint no_of_gc_workers = workers()->active_workers();
|
||||
|
||||
// Parallel reference processing
|
||||
assert(no_of_gc_workers <= rp->max_num_queues(),
|
||||
"Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u",
|
||||
no_of_gc_workers, rp->max_num_queues());
|
||||
// Parallel reference processing
|
||||
assert(no_of_gc_workers <= rp->max_num_queues(),
|
||||
"Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u",
|
||||
no_of_gc_workers, rp->max_num_queues());
|
||||
|
||||
G1STWRefProcTaskExecutor par_task_executor(this, per_thread_states, workers(), _task_queues);
|
||||
stats = rp->process_discovered_references(&is_alive,
|
||||
&keep_alive,
|
||||
&drain_queue,
|
||||
&par_task_executor,
|
||||
pt);
|
||||
}
|
||||
rp->set_active_mt_degree(no_of_gc_workers);
|
||||
G1STWRefProcProxyTask task(rp->max_num_queues(), *this, *per_thread_states, *_task_queues);
|
||||
stats = rp->process_discovered_references(task, pt);
|
||||
|
||||
_gc_tracer_stw->report_gc_reference_stats(stats);
|
||||
|
||||
|
||||
@ -1458,71 +1458,34 @@ class G1CMDrainMarkingStackClosure : public VoidClosure {
|
||||
}
|
||||
};
|
||||
|
||||
// Implementation of AbstractRefProcTaskExecutor for parallel
|
||||
// reference processing at the end of G1 concurrent marking
|
||||
|
||||
class G1CMRefProcTaskExecutor : public AbstractRefProcTaskExecutor {
|
||||
private:
|
||||
G1CollectedHeap* _g1h;
|
||||
G1ConcurrentMark* _cm;
|
||||
WorkGang* _workers;
|
||||
uint _active_workers;
|
||||
class G1CMRefProcProxyTask : public RefProcProxyTask {
|
||||
G1CollectedHeap& _g1h;
|
||||
G1ConcurrentMark& _cm;
|
||||
|
||||
public:
|
||||
G1CMRefProcTaskExecutor(G1CollectedHeap* g1h,
|
||||
G1ConcurrentMark* cm,
|
||||
WorkGang* workers,
|
||||
uint n_workers) :
|
||||
_g1h(g1h), _cm(cm),
|
||||
_workers(workers), _active_workers(n_workers) { }
|
||||
G1CMRefProcProxyTask(uint max_workers, G1CollectedHeap& g1h, G1ConcurrentMark &cm)
|
||||
: RefProcProxyTask("G1CMRefProcProxyTask", max_workers),
|
||||
_g1h(g1h),
|
||||
_cm(cm) {}
|
||||
|
||||
virtual void execute(ProcessTask& task, uint ergo_workers);
|
||||
};
|
||||
|
||||
class G1CMRefProcTaskProxy : public AbstractGangTask {
|
||||
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
|
||||
ProcessTask& _proc_task;
|
||||
G1CollectedHeap* _g1h;
|
||||
G1ConcurrentMark* _cm;
|
||||
|
||||
public:
|
||||
G1CMRefProcTaskProxy(ProcessTask& proc_task,
|
||||
G1CollectedHeap* g1h,
|
||||
G1ConcurrentMark* cm) :
|
||||
AbstractGangTask("Process reference objects in parallel"),
|
||||
_proc_task(proc_task), _g1h(g1h), _cm(cm) {
|
||||
ReferenceProcessor* rp = _g1h->ref_processor_cm();
|
||||
assert(rp->processing_is_mt(), "shouldn't be here otherwise");
|
||||
void work(uint worker_id) override {
|
||||
assert(worker_id < _max_workers, "sanity");
|
||||
G1CMIsAliveClosure is_alive(&_g1h);
|
||||
uint index = (_tm == RefProcThreadModel::Single) ? 0 : worker_id;
|
||||
G1CMKeepAliveAndDrainClosure keep_alive(&_cm, _cm.task(index), _tm == RefProcThreadModel::Single);
|
||||
G1CMDrainMarkingStackClosure complete_gc(&_cm, _cm.task(index), _tm == RefProcThreadModel::Single);
|
||||
_rp_task->rp_work(worker_id, &is_alive, &keep_alive, &complete_gc);
|
||||
}
|
||||
|
||||
virtual void work(uint worker_id) {
|
||||
ResourceMark rm;
|
||||
G1CMTask* task = _cm->task(worker_id);
|
||||
G1CMIsAliveClosure g1_is_alive(_g1h);
|
||||
G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, task, false /* is_serial */);
|
||||
G1CMDrainMarkingStackClosure g1_par_drain(_cm, task, false /* is_serial */);
|
||||
|
||||
_proc_task.work(worker_id, g1_is_alive, g1_par_keep_alive, g1_par_drain);
|
||||
void prepare_run_task_hook() override {
|
||||
// We need to reset the concurrency level before each
|
||||
// proxy task execution, so that the termination protocol
|
||||
// and overflow handling in G1CMTask::do_marking_step() knows
|
||||
// how many workers to wait for.
|
||||
_cm.set_concurrency(_queue_count);
|
||||
}
|
||||
};
|
||||
|
||||
void G1CMRefProcTaskExecutor::execute(ProcessTask& proc_task, uint ergo_workers) {
|
||||
assert(_workers != NULL, "Need parallel worker threads.");
|
||||
assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
|
||||
assert(_workers->active_workers() >= ergo_workers,
|
||||
"Ergonomically chosen workers(%u) should be less than or equal to active workers(%u)",
|
||||
ergo_workers, _workers->active_workers());
|
||||
|
||||
G1CMRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _cm);
|
||||
|
||||
// We need to reset the concurrency level before each
|
||||
// proxy task execution, so that the termination protocol
|
||||
// and overflow handling in G1CMTask::do_marking_step() knows
|
||||
// how many workers to wait for.
|
||||
_cm->set_concurrency(ergo_workers);
|
||||
_workers->run_task(&proc_task_proxy, ergo_workers);
|
||||
}
|
||||
|
||||
void G1ConcurrentMark::weak_refs_work(bool clear_all_soft_refs) {
|
||||
ResourceMark rm;
|
||||
|
||||
@ -1541,23 +1504,6 @@ void G1ConcurrentMark::weak_refs_work(bool clear_all_soft_refs) {
|
||||
rp->setup_policy(clear_all_soft_refs);
|
||||
assert(_global_mark_stack.is_empty(), "mark stack should be empty");
|
||||
|
||||
// Instances of the 'Keep Alive' and 'Complete GC' closures used
|
||||
// in serial reference processing. Note these closures are also
|
||||
// used for serially processing (by the the current thread) the
|
||||
// JNI references during parallel reference processing.
|
||||
//
|
||||
// These closures do not need to synchronize with the worker
|
||||
// threads involved in parallel reference processing as these
|
||||
// instances are executed serially by the current thread (e.g.
|
||||
// reference processing is not multi-threaded and is thus
|
||||
// performed by the current thread instead of a gang worker).
|
||||
//
|
||||
// The gang tasks involved in parallel reference processing create
|
||||
// their own instances of these closures, which do their own
|
||||
// synchronization among themselves.
|
||||
G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0), true /* is_serial */);
|
||||
G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), true /* is_serial */);
|
||||
|
||||
// We need at least one active thread. If reference processing
|
||||
// is not multi-threaded we use the current (VMThread) thread,
|
||||
// otherwise we use the work gang from the G1CollectedHeap and
|
||||
@ -1576,19 +1522,11 @@ void G1ConcurrentMark::weak_refs_work(bool clear_all_soft_refs) {
|
||||
rp->set_active_mt_degree(active_workers);
|
||||
|
||||
// Parallel processing task executor.
|
||||
G1CMRefProcTaskExecutor par_task_executor(_g1h, this,
|
||||
_g1h->workers(), active_workers);
|
||||
AbstractRefProcTaskExecutor* executor = (rp->processing_is_mt() ? &par_task_executor : NULL);
|
||||
|
||||
G1CMRefProcProxyTask task(rp->max_num_queues(), *_g1h, *this);
|
||||
ReferenceProcessorPhaseTimes pt(_gc_timer_cm, rp->max_num_queues());
|
||||
|
||||
// Process the weak references.
|
||||
const ReferenceProcessorStats& stats =
|
||||
rp->process_discovered_references(&g1_is_alive,
|
||||
&g1_keep_alive,
|
||||
&g1_drain_mark_stack,
|
||||
executor,
|
||||
&pt);
|
||||
const ReferenceProcessorStats& stats = rp->process_discovered_references(task, pt);
|
||||
_gc_tracer_cm->report_gc_reference_stats(stats);
|
||||
pt.print_all_references();
|
||||
|
||||
|
||||
@ -278,15 +278,14 @@ public:
|
||||
// This class manages data structures and methods for doing liveness analysis in
|
||||
// G1's concurrent cycle.
|
||||
class G1ConcurrentMark : public CHeapObj<mtGC> {
|
||||
friend class G1ConcurrentMarkThread;
|
||||
friend class G1CMRefProcTaskProxy;
|
||||
friend class G1CMRefProcTaskExecutor;
|
||||
friend class G1CMKeepAliveAndDrainClosure;
|
||||
friend class G1CMDrainMarkingStackClosure;
|
||||
friend class G1CMBitMapClosure;
|
||||
friend class G1CMConcurrentMarkingTask;
|
||||
friend class G1CMDrainMarkingStackClosure;
|
||||
friend class G1CMKeepAliveAndDrainClosure;
|
||||
friend class G1CMRefProcProxyTask;
|
||||
friend class G1CMRemarkTask;
|
||||
friend class G1CMTask;
|
||||
friend class G1ConcurrentMarkThread;
|
||||
|
||||
G1ConcurrentMarkThread* _cm_thread; // The thread doing the work
|
||||
G1CollectedHeap* _g1h; // The heap
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
#include "gc/g1/g1FullGCMarker.inline.hpp"
|
||||
#include "gc/g1/g1FullGCMarkTask.hpp"
|
||||
#include "gc/g1/g1FullGCPrepareTask.hpp"
|
||||
#include "gc/g1/g1FullGCReferenceProcessorExecutor.hpp"
|
||||
#include "gc/g1/g1FullGCScope.hpp"
|
||||
#include "gc/g1/g1OopClosures.hpp"
|
||||
#include "gc/g1/g1Policy.hpp"
|
||||
@ -242,6 +241,24 @@ void G1FullCollector::before_marking_update_attribute_table(HeapRegion* hr) {
|
||||
}
|
||||
}
|
||||
|
||||
class G1FullGCRefProcProxyTask : public RefProcProxyTask {
|
||||
G1FullCollector& _collector;
|
||||
|
||||
public:
|
||||
G1FullGCRefProcProxyTask(G1FullCollector &collector, uint max_workers)
|
||||
: RefProcProxyTask("G1FullGCRefProcProxyTask", max_workers),
|
||||
_collector(collector) {}
|
||||
|
||||
void work(uint worker_id) override {
|
||||
assert(worker_id < _max_workers, "sanity");
|
||||
G1IsAliveClosure is_alive(&_collector);
|
||||
uint index = (_tm == RefProcThreadModel::Single) ? 0 : worker_id;
|
||||
G1FullKeepAliveClosure keep_alive(_collector.marker(index));
|
||||
G1FollowStackClosure* complete_gc = _collector.marker(index)->stack_closure();
|
||||
_rp_task->rp_work(worker_id, &is_alive, &keep_alive, complete_gc);
|
||||
}
|
||||
};
|
||||
|
||||
void G1FullCollector::phase1_mark_live_objects() {
|
||||
// Recursively traverse all live objects and mark them.
|
||||
GCTraceTime(Info, gc, phases) info("Phase 1: Mark live objects", scope()->timer());
|
||||
@ -253,9 +270,18 @@ void G1FullCollector::phase1_mark_live_objects() {
|
||||
}
|
||||
|
||||
{
|
||||
// Process references discovered during marking.
|
||||
G1FullGCReferenceProcessingExecutor reference_processing(this);
|
||||
reference_processing.execute(scope()->timer(), scope()->tracer());
|
||||
uint old_active_mt_degree = reference_processor()->num_queues();
|
||||
reference_processor()->set_active_mt_degree(workers());
|
||||
GCTraceTime(Debug, gc, phases) debug("Phase 1: Reference Processing", scope()->timer());
|
||||
// Process reference objects found during marking.
|
||||
ReferenceProcessorPhaseTimes pt(scope()->timer(), reference_processor()->max_num_queues());
|
||||
G1FullGCRefProcProxyTask task(*this, reference_processor()->max_num_queues());
|
||||
const ReferenceProcessorStats& stats = reference_processor()->process_discovered_references(task, pt);
|
||||
scope()->tracer()->report_gc_reference_stats(stats);
|
||||
pt.print_all_references();
|
||||
assert(marker(0)->oop_stack()->is_empty(), "Should be no oops on the stack");
|
||||
|
||||
reference_processor()->set_active_mt_degree(old_active_mt_degree);
|
||||
}
|
||||
|
||||
// Weak oops cleanup.
|
||||
|
||||
@ -29,7 +29,6 @@
|
||||
#include "gc/g1/g1FullGCMarker.hpp"
|
||||
#include "gc/g1/g1FullGCMarkTask.hpp"
|
||||
#include "gc/g1/g1FullGCOopClosures.inline.hpp"
|
||||
#include "gc/g1/g1FullGCReferenceProcessorExecutor.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "memory/iterator.inline.hpp"
|
||||
|
||||
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.hpp"
|
||||
#include "gc/g1/g1FullCollector.hpp"
|
||||
#include "gc/g1/g1FullGCMarker.hpp"
|
||||
#include "gc/g1/g1FullGCOopClosures.inline.hpp"
|
||||
#include "gc/g1/g1FullGCReferenceProcessorExecutor.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "gc/shared/referenceProcessorPhaseTimes.hpp"
|
||||
#include "memory/iterator.inline.hpp"
|
||||
|
||||
G1FullGCReferenceProcessingExecutor::G1FullGCReferenceProcessingExecutor(G1FullCollector* collector) :
|
||||
_collector(collector),
|
||||
_reference_processor(collector->reference_processor()),
|
||||
_old_mt_degree(_reference_processor->num_queues()) {
|
||||
_reference_processor->set_active_mt_degree(_collector->workers());
|
||||
}
|
||||
|
||||
G1FullGCReferenceProcessingExecutor::~G1FullGCReferenceProcessingExecutor() {
|
||||
_reference_processor->set_active_mt_degree(_old_mt_degree);
|
||||
}
|
||||
|
||||
G1FullGCReferenceProcessingExecutor::G1RefProcTaskProxy::G1RefProcTaskProxy(ProcessTask& proc_task,
|
||||
G1FullCollector* collector) :
|
||||
AbstractGangTask("G1 reference processing task"),
|
||||
_proc_task(proc_task),
|
||||
_collector(collector) { }
|
||||
|
||||
void G1FullGCReferenceProcessingExecutor::G1RefProcTaskProxy::work(uint worker_id) {
|
||||
G1FullGCMarker* marker = _collector->marker(worker_id);
|
||||
G1IsAliveClosure is_alive(_collector);
|
||||
G1FullKeepAliveClosure keep_alive(marker);
|
||||
_proc_task.work(worker_id,
|
||||
is_alive,
|
||||
keep_alive,
|
||||
*marker->stack_closure());
|
||||
}
|
||||
|
||||
void G1FullGCReferenceProcessingExecutor::run_task(AbstractGangTask* task) {
|
||||
G1CollectedHeap::heap()->workers()->run_task(task, _collector->workers());
|
||||
}
|
||||
|
||||
void G1FullGCReferenceProcessingExecutor::run_task(AbstractGangTask* task, uint workers) {
|
||||
G1CollectedHeap::heap()->workers()->run_task(task, workers);
|
||||
}
|
||||
|
||||
void G1FullGCReferenceProcessingExecutor::execute(ProcessTask& proc_task, uint ergo_workers) {
|
||||
G1RefProcTaskProxy proc_task_proxy(proc_task, _collector);
|
||||
run_task(&proc_task_proxy, ergo_workers);
|
||||
}
|
||||
|
||||
void G1FullGCReferenceProcessingExecutor::execute(STWGCTimer* timer, G1FullGCTracer* tracer) {
|
||||
GCTraceTime(Debug, gc, phases) debug("Phase 1: Reference Processing", timer);
|
||||
// Process reference objects found during marking.
|
||||
G1FullGCMarker* marker = _collector->marker(0);
|
||||
G1IsAliveClosure is_alive(_collector);
|
||||
G1FullKeepAliveClosure keep_alive(marker);
|
||||
ReferenceProcessorPhaseTimes pt(timer, _reference_processor->max_num_queues());
|
||||
AbstractRefProcTaskExecutor* executor = _reference_processor->processing_is_mt() ? this : NULL;
|
||||
|
||||
// Process discovered references, use this executor if multi-threaded
|
||||
// processing is enabled.
|
||||
const ReferenceProcessorStats& stats =
|
||||
_reference_processor->process_discovered_references(&is_alive,
|
||||
&keep_alive,
|
||||
marker->stack_closure(),
|
||||
executor,
|
||||
&pt);
|
||||
|
||||
tracer->report_gc_reference_stats(stats);
|
||||
pt.print_all_references();
|
||||
|
||||
assert(marker->oop_stack()->is_empty(), "Should be no oops on the stack");
|
||||
}
|
||||
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_G1_G1FULLGCREFERENCEPROCESSOREXECUTOR_HPP
|
||||
#define SHARE_GC_G1_G1FULLGCREFERENCEPROCESSOREXECUTOR_HPP
|
||||
|
||||
#include "gc/g1/g1FullGCCompactionPoint.hpp"
|
||||
#include "gc/g1/g1FullGCScope.hpp"
|
||||
#include "gc/g1/g1FullGCTask.hpp"
|
||||
#include "gc/g1/g1RootProcessor.hpp"
|
||||
#include "gc/g1/heapRegionManager.hpp"
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "gc/shared/taskqueue.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
class G1FullGCTracer;
|
||||
class STWGCTimer;
|
||||
|
||||
class G1FullGCReferenceProcessingExecutor: public AbstractRefProcTaskExecutor {
|
||||
G1FullCollector* _collector;
|
||||
ReferenceProcessor* _reference_processor;
|
||||
uint _old_mt_degree;
|
||||
|
||||
public:
|
||||
G1FullGCReferenceProcessingExecutor(G1FullCollector* collector);
|
||||
~G1FullGCReferenceProcessingExecutor();
|
||||
|
||||
// Do reference processing.
|
||||
void execute(STWGCTimer* timer, G1FullGCTracer* tracer);
|
||||
|
||||
// Executes the given task using concurrent marking worker threads.
|
||||
virtual void execute(ProcessTask& task, uint ergo_workers);
|
||||
|
||||
private:
|
||||
void run_task(AbstractGangTask* task);
|
||||
void run_task(AbstractGangTask* task, uint workers);
|
||||
|
||||
class G1RefProcTaskProxy : public AbstractGangTask {
|
||||
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
|
||||
ProcessTask& _proc_task;
|
||||
G1FullCollector* _collector;
|
||||
|
||||
public:
|
||||
G1RefProcTaskProxy(ProcessTask& proc_task,
|
||||
G1FullCollector* scope);
|
||||
|
||||
virtual void work(uint worker_id);
|
||||
};
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_G1_G1FULLGCREFERENCEPROCESSOREXECUTOR_HPP
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
#include "gc/parallel/psParallelCompact.hpp"
|
||||
#include "gc/shared/taskqueue.hpp"
|
||||
#include "gc/shared/taskTerminator.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/stack.hpp"
|
||||
|
||||
@ -38,14 +39,13 @@ class ParallelCompactData;
|
||||
class ParMarkBitMap;
|
||||
|
||||
class ParCompactionManager : public CHeapObj<mtGC> {
|
||||
friend class MarkFromRootsTask;
|
||||
friend class ParallelCompactRefProcProxyTask;
|
||||
friend class ParallelScavengeRefProcProxyTask;
|
||||
friend class ParMarkBitMap;
|
||||
friend class PSParallelCompact;
|
||||
friend class CompactionWithStealingTask;
|
||||
friend class UpdateAndFillClosure;
|
||||
friend class RefProcTaskExecutor;
|
||||
friend class PCRefProcTask;
|
||||
friend class MarkFromRootsTask;
|
||||
friend class UpdateDensePrefixAndCompactionTask;
|
||||
|
||||
private:
|
||||
typedef GenericTaskQueue<oop, mtGC> OopTaskQueue;
|
||||
typedef GenericTaskQueueSet<OopTaskQueue, mtGC> OopTaskQueueSet;
|
||||
@ -187,8 +187,11 @@ class ParCompactionManager : public CHeapObj<mtGC> {
|
||||
class FollowStackClosure: public VoidClosure {
|
||||
private:
|
||||
ParCompactionManager* _compaction_manager;
|
||||
TaskTerminator* _terminator;
|
||||
uint _worker_id;
|
||||
public:
|
||||
FollowStackClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
|
||||
FollowStackClosure(ParCompactionManager* cm, TaskTerminator* terminator, uint worker_id)
|
||||
: _compaction_manager(cm), _terminator(terminator), _worker_id(worker_id) { }
|
||||
virtual void do_void();
|
||||
};
|
||||
|
||||
|
||||
@ -118,6 +118,9 @@ inline void ParCompactionManager::follow_klass(Klass* klass) {
|
||||
|
||||
inline void ParCompactionManager::FollowStackClosure::do_void() {
|
||||
_compaction_manager->follow_marking_stacks();
|
||||
if (_terminator != nullptr) {
|
||||
steal_marking_work(*_terminator, _worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@ -1996,7 +1996,7 @@ static void mark_from_roots_work(ParallelRootType::Value root_type, uint worker_
|
||||
cm->follow_marking_stacks();
|
||||
}
|
||||
|
||||
static void steal_marking_work(TaskTerminator& terminator, uint worker_id) {
|
||||
void steal_marking_work(TaskTerminator& terminator, uint worker_id) {
|
||||
assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc");
|
||||
|
||||
ParCompactionManager* cm =
|
||||
@ -2017,7 +2017,6 @@ static void steal_marking_work(TaskTerminator& terminator, uint worker_id) {
|
||||
}
|
||||
|
||||
class MarkFromRootsTask : public AbstractGangTask {
|
||||
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
|
||||
StrongRootsScope _strong_roots_scope; // needed for Threads::possibly_parallel_threads_do
|
||||
OopStorageSetStrongParState<false /* concurrent */, false /* is_const */> _oop_storage_set_par_state;
|
||||
SequentialSubTasksDone _subtasks;
|
||||
@ -2056,43 +2055,24 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class PCRefProcTask : public AbstractGangTask {
|
||||
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
|
||||
ProcessTask& _task;
|
||||
uint _ergo_workers;
|
||||
class ParallelCompactRefProcProxyTask : public RefProcProxyTask {
|
||||
TaskTerminator _terminator;
|
||||
|
||||
public:
|
||||
PCRefProcTask(ProcessTask& task, uint ergo_workers) :
|
||||
AbstractGangTask("PCRefProcTask"),
|
||||
_task(task),
|
||||
_ergo_workers(ergo_workers),
|
||||
_terminator(_ergo_workers, ParCompactionManager::oop_task_queues()) {
|
||||
ParallelCompactRefProcProxyTask(uint max_workers)
|
||||
: RefProcProxyTask("ParallelCompactRefProcProxyTask", max_workers),
|
||||
_terminator(_max_workers, ParCompactionManager::oop_task_queues()) {}
|
||||
|
||||
void work(uint worker_id) override {
|
||||
assert(worker_id < _max_workers, "sanity");
|
||||
ParCompactionManager* cm = (_tm == RefProcThreadModel::Single) ? ParCompactionManager::get_vmthread_cm() : ParCompactionManager::gc_thread_compaction_manager(worker_id);
|
||||
PCMarkAndPushClosure keep_alive(cm);
|
||||
ParCompactionManager::FollowStackClosure complete_gc(cm, (_tm == RefProcThreadModel::Single) ? nullptr : &_terminator, worker_id);
|
||||
_rp_task->rp_work(worker_id, PSParallelCompact::is_alive_closure(), &keep_alive, &complete_gc);
|
||||
}
|
||||
|
||||
virtual void work(uint worker_id) {
|
||||
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
|
||||
assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc");
|
||||
|
||||
ParCompactionManager* cm =
|
||||
ParCompactionManager::gc_thread_compaction_manager(worker_id);
|
||||
PCMarkAndPushClosure mark_and_push_closure(cm);
|
||||
ParCompactionManager::FollowStackClosure follow_stack_closure(cm);
|
||||
_task.work(worker_id, *PSParallelCompact::is_alive_closure(),
|
||||
mark_and_push_closure, follow_stack_closure);
|
||||
|
||||
steal_marking_work(_terminator, worker_id);
|
||||
}
|
||||
};
|
||||
|
||||
class RefProcTaskExecutor: public AbstractRefProcTaskExecutor {
|
||||
void execute(ProcessTask& process_task, uint ergo_workers) {
|
||||
assert(ParallelScavengeHeap::heap()->workers().active_workers() == ergo_workers,
|
||||
"Ergonomically chosen workers (%u) must be equal to active workers (%u)",
|
||||
ergo_workers, ParallelScavengeHeap::heap()->workers().active_workers());
|
||||
|
||||
PCRefProcTask task(process_task, ergo_workers);
|
||||
ParallelScavengeHeap::heap()->workers().run_task(&task);
|
||||
void prepare_run_task_hook() override {
|
||||
_terminator.reset_for_reuse(_queue_count);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2102,12 +2082,8 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
|
||||
// Recursively traverse all live objects and mark them
|
||||
GCTraceTime(Info, gc, phases) tm("Marking Phase", &_gc_timer);
|
||||
|
||||
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
|
||||
uint active_gc_threads = ParallelScavengeHeap::heap()->workers().active_workers();
|
||||
|
||||
PCMarkAndPushClosure mark_and_push_closure(cm);
|
||||
ParCompactionManager::FollowStackClosure follow_stack_closure(cm);
|
||||
|
||||
// Need new claim bits before marking starts.
|
||||
ClassLoaderDataGraph::clear_claimed_marks();
|
||||
|
||||
@ -2126,16 +2102,8 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
|
||||
ReferenceProcessorPhaseTimes pt(&_gc_timer, ref_processor()->max_num_queues());
|
||||
|
||||
ref_processor()->set_active_mt_degree(active_gc_threads);
|
||||
if (ref_processor()->processing_is_mt()) {
|
||||
RefProcTaskExecutor task_executor;
|
||||
stats = ref_processor()->process_discovered_references(
|
||||
is_alive_closure(), &mark_and_push_closure, &follow_stack_closure,
|
||||
&task_executor, &pt);
|
||||
} else {
|
||||
stats = ref_processor()->process_discovered_references(
|
||||
is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL,
|
||||
&pt);
|
||||
}
|
||||
ParallelCompactRefProcProxyTask task(ref_processor()->max_num_queues());
|
||||
stats = ref_processor()->process_discovered_references(task, pt);
|
||||
|
||||
gc_tracer->report_gc_reference_stats(stats);
|
||||
pt.print_all_references();
|
||||
@ -2522,7 +2490,6 @@ static void compaction_with_stealing_work(TaskTerminator* terminator, uint worke
|
||||
}
|
||||
|
||||
class UpdateDensePrefixAndCompactionTask: public AbstractGangTask {
|
||||
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
|
||||
TaskQueue& _tq;
|
||||
TaskTerminator _terminator;
|
||||
uint _active_workers;
|
||||
|
||||
@ -27,10 +27,11 @@
|
||||
|
||||
#include "gc/parallel/mutableSpace.hpp"
|
||||
#include "gc/parallel/objectStartArray.hpp"
|
||||
#include "gc/parallel/parMarkBitMap.hpp"
|
||||
#include "gc/parallel/parallelScavengeHeap.hpp"
|
||||
#include "gc/parallel/parMarkBitMap.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/collectorCounters.hpp"
|
||||
#include "gc/shared/taskTerminator.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
@ -1390,4 +1391,6 @@ class FillClosure: public ParMarkBitMapClosure {
|
||||
ObjectStartArray* const _start_array;
|
||||
};
|
||||
|
||||
void steal_marking_work(TaskTerminator& terminator, uint worker_id);
|
||||
|
||||
#endif // SHARE_GC_PARALLEL_PSPARALLELCOMPACT_HPP
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -52,8 +52,6 @@ class ParCompactionManager;
|
||||
class PSPromotionManager {
|
||||
friend class PSScavenge;
|
||||
friend class ScavengeRootsTask;
|
||||
friend class PSRefProcTaskExecutor;
|
||||
friend class PSRefProcTask;
|
||||
|
||||
private:
|
||||
typedef OverflowTaskQueue<ScannerTask, mtGC> PSScannerTasksQueue;
|
||||
|
||||
@ -179,54 +179,46 @@ public:
|
||||
class PSEvacuateFollowersClosure: public VoidClosure {
|
||||
private:
|
||||
PSPromotionManager* _promotion_manager;
|
||||
TaskTerminator* _terminator;
|
||||
uint _worker_id;
|
||||
|
||||
public:
|
||||
PSEvacuateFollowersClosure(PSPromotionManager* pm) : _promotion_manager(pm) {}
|
||||
PSEvacuateFollowersClosure(PSPromotionManager* pm, TaskTerminator* terminator, uint worker_id)
|
||||
: _promotion_manager(pm), _terminator(terminator), _worker_id(worker_id) {}
|
||||
|
||||
virtual void do_void() {
|
||||
assert(_promotion_manager != NULL, "Sanity");
|
||||
assert(_promotion_manager != nullptr, "Sanity");
|
||||
_promotion_manager->drain_stacks(true);
|
||||
guarantee(_promotion_manager->stacks_empty(),
|
||||
"stacks should be empty at this point");
|
||||
}
|
||||
};
|
||||
|
||||
class PSRefProcTaskExecutor: public AbstractRefProcTaskExecutor {
|
||||
virtual void execute(ProcessTask& process_task, uint ergo_workers);
|
||||
};
|
||||
|
||||
class PSRefProcTask : public AbstractGangTask {
|
||||
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
|
||||
TaskTerminator _terminator;
|
||||
ProcessTask& _task;
|
||||
uint _active_workers;
|
||||
|
||||
public:
|
||||
PSRefProcTask(ProcessTask& task, uint active_workers)
|
||||
: AbstractGangTask("PSRefProcTask"),
|
||||
_terminator(active_workers, PSPromotionManager::stack_array_depth()),
|
||||
_task(task),
|
||||
_active_workers(active_workers) {
|
||||
}
|
||||
|
||||
virtual void work(uint worker_id) {
|
||||
PSPromotionManager* promotion_manager =
|
||||
PSPromotionManager::gc_thread_promotion_manager(worker_id);
|
||||
assert(promotion_manager != NULL, "sanity check");
|
||||
PSKeepAliveClosure keep_alive(promotion_manager);
|
||||
PSEvacuateFollowersClosure evac_followers(promotion_manager);
|
||||
PSIsAliveClosure is_alive;
|
||||
_task.work(worker_id, is_alive, keep_alive, evac_followers);
|
||||
|
||||
if (_task.marks_oops_alive() && _active_workers > 1) {
|
||||
steal_work(_terminator, worker_id);
|
||||
if (_terminator != nullptr) {
|
||||
steal_work(*_terminator, _worker_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void PSRefProcTaskExecutor::execute(ProcessTask& process_task, uint ergo_workers) {
|
||||
PSRefProcTask task(process_task, ergo_workers);
|
||||
ParallelScavengeHeap::heap()->workers().run_task(&task);
|
||||
}
|
||||
class ParallelScavengeRefProcProxyTask : public RefProcProxyTask {
|
||||
TaskTerminator _terminator;
|
||||
|
||||
public:
|
||||
ParallelScavengeRefProcProxyTask(uint max_workers)
|
||||
: RefProcProxyTask("ParallelScavengeRefProcProxyTask", max_workers),
|
||||
_terminator(max_workers, ParCompactionManager::oop_task_queues()) {}
|
||||
|
||||
void work(uint worker_id) override {
|
||||
assert(worker_id < _max_workers, "sanity");
|
||||
PSPromotionManager* promotion_manager = (_tm == RefProcThreadModel::Single) ? PSPromotionManager::vm_thread_promotion_manager() : PSPromotionManager::gc_thread_promotion_manager(worker_id);
|
||||
PSIsAliveClosure is_alive;
|
||||
PSKeepAliveClosure keep_alive(promotion_manager);;
|
||||
PSEvacuateFollowersClosure complete_gc(promotion_manager, (_marks_oops_alive && _tm == RefProcThreadModel::Multi) ? &_terminator : nullptr, worker_id);;
|
||||
_rp_task->rp_work(worker_id, &is_alive, &keep_alive, &complete_gc);
|
||||
}
|
||||
|
||||
void prepare_run_task_hook() override {
|
||||
_terminator.reset_for_reuse(_queue_count);
|
||||
}
|
||||
};
|
||||
|
||||
// This method contains all heap specific policy for invoking scavenge.
|
||||
// PSScavenge::invoke_no_policy() will do nothing but attempt to
|
||||
@ -496,19 +488,11 @@ bool PSScavenge::invoke_no_policy() {
|
||||
|
||||
reference_processor()->setup_policy(false); // not always_clear
|
||||
reference_processor()->set_active_mt_degree(active_workers);
|
||||
PSKeepAliveClosure keep_alive(promotion_manager);
|
||||
PSEvacuateFollowersClosure evac_followers(promotion_manager);
|
||||
ReferenceProcessorStats stats;
|
||||
ReferenceProcessorPhaseTimes pt(&_gc_timer, reference_processor()->max_num_queues());
|
||||
if (reference_processor()->processing_is_mt()) {
|
||||
PSRefProcTaskExecutor task_executor;
|
||||
stats = reference_processor()->process_discovered_references(
|
||||
&_is_alive_closure, &keep_alive, &evac_followers, &task_executor,
|
||||
&pt);
|
||||
} else {
|
||||
stats = reference_processor()->process_discovered_references(
|
||||
&_is_alive_closure, &keep_alive, &evac_followers, NULL, &pt);
|
||||
}
|
||||
|
||||
ParallelScavengeRefProcProxyTask task(reference_processor()->max_num_queues());
|
||||
stats = reference_processor()->process_discovered_references(task, pt);
|
||||
|
||||
_gc_tracer.report_gc_reference_stats(stats);
|
||||
pt.print_all_references();
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/serial/defNewGeneration.inline.hpp"
|
||||
#include "gc/serial/serialGcRefProcProxyTask.hpp"
|
||||
#include "gc/serial/serialHeap.inline.hpp"
|
||||
#include "gc/serial/tenuredGeneration.hpp"
|
||||
#include "gc/shared/adaptiveSizePolicy.hpp"
|
||||
@ -37,8 +38,8 @@
|
||||
#include "gc/shared/gcTimer.hpp"
|
||||
#include "gc/shared/gcTrace.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "gc/shared/generationSpec.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "gc/shared/preservedMarks.inline.hpp"
|
||||
#include "gc/shared/referencePolicy.hpp"
|
||||
#include "gc/shared/referenceProcessorPhaseTimes.hpp"
|
||||
@ -587,9 +588,8 @@ void DefNewGeneration::collect(bool full,
|
||||
ReferenceProcessor* rp = ref_processor();
|
||||
rp->setup_policy(clear_all_soft_refs);
|
||||
ReferenceProcessorPhaseTimes pt(_gc_timer, rp->max_num_queues());
|
||||
const ReferenceProcessorStats& stats =
|
||||
rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
|
||||
NULL, &pt);
|
||||
SerialGCRefProcProxyTask task(is_alive, keep_alive, evacuate_followers);
|
||||
const ReferenceProcessorStats& stats = rp->process_discovered_references(task, pt);
|
||||
gc_tracer.report_gc_reference_stats(stats);
|
||||
gc_tracer.report_tenuring_threshold(tenuring_threshold());
|
||||
pt.print_all_references();
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
#include "code/icBuffer.hpp"
|
||||
#include "compiler/oopMap.hpp"
|
||||
#include "gc/serial/genMarkSweep.hpp"
|
||||
#include "gc/serial/serialGcRefProcProxyTask.hpp"
|
||||
#include "gc/shared/collectedHeap.inline.hpp"
|
||||
#include "gc/shared/gcHeapSummary.hpp"
|
||||
#include "gc/shared/gcTimer.hpp"
|
||||
@ -199,9 +200,8 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
|
||||
|
||||
ref_processor()->setup_policy(clear_all_softrefs);
|
||||
ReferenceProcessorPhaseTimes pt(_gc_timer, ref_processor()->max_num_queues());
|
||||
const ReferenceProcessorStats& stats =
|
||||
ref_processor()->process_discovered_references(
|
||||
&is_alive, &keep_alive, &follow_stack_closure, NULL, &pt);
|
||||
SerialGCRefProcProxyTask task(is_alive, keep_alive, follow_stack_closure);
|
||||
const ReferenceProcessorStats& stats = ref_processor()->process_discovered_references(task, pt);
|
||||
pt.print_all_references();
|
||||
gc_tracer()->report_gc_reference_stats(stats);
|
||||
}
|
||||
|
||||
48
src/hotspot/share/gc/serial/serialGcRefProcProxyTask.hpp
Normal file
48
src/hotspot/share/gc/serial/serialGcRefProcProxyTask.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_SERIAL_SERIALGCREFPROCPROXYTASK_HPP
|
||||
#define SHARE_GC_SERIAL_SERIALGCREFPROCPROXYTASK_HPP
|
||||
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
|
||||
class SerialGCRefProcProxyTask : public RefProcProxyTask {
|
||||
BoolObjectClosure& _is_alive;
|
||||
OopClosure& _keep_alive;
|
||||
VoidClosure& _complete_gc;
|
||||
|
||||
public:
|
||||
SerialGCRefProcProxyTask(BoolObjectClosure& is_alive, OopClosure& keep_alive, VoidClosure& complete_gc)
|
||||
: RefProcProxyTask("SerialGCRefProcProxyTask", 1),
|
||||
_is_alive(is_alive),
|
||||
_keep_alive(keep_alive),
|
||||
_complete_gc(complete_gc) {}
|
||||
|
||||
void work(uint worker_id) override {
|
||||
assert(worker_id < _max_workers, "sanity");
|
||||
_rp_task->rp_work(worker_id, &_is_alive, &_keep_alive, &_complete_gc);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SHARE_GC_SERIAL_SERIALGCREFPROCPROXYTASK_HPP */
|
||||
@ -196,12 +196,8 @@ void ReferenceProcessor::verify_total_count_zero(DiscoveredList lists[], const c
|
||||
}
|
||||
#endif
|
||||
|
||||
ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times) {
|
||||
ReferenceProcessorStats ReferenceProcessor::process_discovered_references(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times) {
|
||||
|
||||
double start_time = os::elapsedTime();
|
||||
|
||||
@ -225,29 +221,28 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
|
||||
total_count(_discoveredPhantomRefs));
|
||||
|
||||
{
|
||||
RefProcTotalPhaseTimesTracker tt(RefPhase1, phase_times, this);
|
||||
process_soft_ref_reconsider(is_alive, keep_alive, complete_gc,
|
||||
task_executor, phase_times);
|
||||
RefProcTotalPhaseTimesTracker tt(RefPhase1, &phase_times);
|
||||
process_soft_ref_reconsider(proxy_task, phase_times);
|
||||
}
|
||||
|
||||
update_soft_ref_master_clock();
|
||||
|
||||
{
|
||||
RefProcTotalPhaseTimesTracker tt(RefPhase2, phase_times, this);
|
||||
process_soft_weak_final_refs(is_alive, keep_alive, complete_gc, task_executor, phase_times);
|
||||
RefProcTotalPhaseTimesTracker tt(RefPhase2, &phase_times);
|
||||
process_soft_weak_final_refs(proxy_task, phase_times);
|
||||
}
|
||||
|
||||
{
|
||||
RefProcTotalPhaseTimesTracker tt(RefPhase3, phase_times, this);
|
||||
process_final_keep_alive(keep_alive, complete_gc, task_executor, phase_times);
|
||||
RefProcTotalPhaseTimesTracker tt(RefPhase3, &phase_times);
|
||||
process_final_keep_alive(proxy_task, phase_times);
|
||||
}
|
||||
|
||||
{
|
||||
RefProcTotalPhaseTimesTracker tt(RefPhase4, phase_times, this);
|
||||
process_phantom_refs(is_alive, keep_alive, complete_gc, task_executor, phase_times);
|
||||
RefProcTotalPhaseTimesTracker tt(RefPhase4, &phase_times);
|
||||
process_phantom_refs(proxy_task, phase_times);
|
||||
}
|
||||
|
||||
phase_times->set_total_time_ms((os::elapsedTime() - start_time) * 1000);
|
||||
phase_times.set_total_time_ms((os::elapsedTime() - start_time) * 1000);
|
||||
|
||||
return stats;
|
||||
}
|
||||
@ -441,9 +436,9 @@ size_t ReferenceProcessor::process_final_keep_alive_work(DiscoveredList& refs_li
|
||||
}
|
||||
|
||||
size_t ReferenceProcessor::process_phantom_refs_work(DiscoveredList& refs_list,
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc) {
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc) {
|
||||
DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
|
||||
while (iter.has_next()) {
|
||||
iter.load_ptrs(DEBUG_ONLY(!discovery_is_atomic() /* allow_null_referent */));
|
||||
@ -516,41 +511,45 @@ size_t ReferenceProcessor::total_reference_count(ReferenceType type) const {
|
||||
return total_count(list);
|
||||
}
|
||||
|
||||
class RefProcPhase1Task : public AbstractRefProcTaskExecutor::ProcessTask {
|
||||
|
||||
|
||||
class RefProcPhase1Task : public RefProcTask {
|
||||
public:
|
||||
RefProcPhase1Task(ReferenceProcessor& ref_processor,
|
||||
RefProcPhase1Task(ReferenceProcessor& ref_processor,
|
||||
ReferenceProcessorPhaseTimes* phase_times,
|
||||
ReferencePolicy* policy)
|
||||
: ProcessTask(ref_processor, true /* marks_oops_alive */, phase_times),
|
||||
ReferencePolicy* policy)
|
||||
: RefProcTask(ref_processor,
|
||||
phase_times),
|
||||
_policy(policy) { }
|
||||
|
||||
virtual void work(uint worker_id,
|
||||
BoolObjectClosure& is_alive,
|
||||
OopClosure& keep_alive,
|
||||
VoidClosure& complete_gc)
|
||||
{
|
||||
void rp_work(uint worker_id,
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc) override {
|
||||
ResourceMark rm;
|
||||
RefProcSubPhasesWorkerTimeTracker tt(ReferenceProcessor::SoftRefSubPhase1, _phase_times, worker_id);
|
||||
size_t const removed = _ref_processor.process_soft_ref_reconsider_work(_ref_processor._discoveredSoftRefs[worker_id],
|
||||
_policy,
|
||||
&is_alive,
|
||||
&keep_alive,
|
||||
&complete_gc);
|
||||
is_alive,
|
||||
keep_alive,
|
||||
complete_gc);
|
||||
_phase_times->add_ref_cleared(REF_SOFT, removed);
|
||||
}
|
||||
|
||||
private:
|
||||
ReferencePolicy* _policy;
|
||||
};
|
||||
|
||||
class RefProcPhase2Task: public AbstractRefProcTaskExecutor::ProcessTask {
|
||||
class RefProcPhase2Task: public RefProcTask {
|
||||
void run_phase2(uint worker_id,
|
||||
DiscoveredList list[],
|
||||
BoolObjectClosure& is_alive,
|
||||
OopClosure& keep_alive,
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
bool do_enqueue_and_clear,
|
||||
ReferenceType ref_type) {
|
||||
size_t const removed = _ref_processor.process_soft_weak_final_refs_work(list[worker_id],
|
||||
&is_alive,
|
||||
&keep_alive,
|
||||
is_alive,
|
||||
keep_alive,
|
||||
do_enqueue_and_clear);
|
||||
_phase_times->add_ref_cleared(ref_type, removed);
|
||||
}
|
||||
@ -558,12 +557,14 @@ class RefProcPhase2Task: public AbstractRefProcTaskExecutor::ProcessTask {
|
||||
public:
|
||||
RefProcPhase2Task(ReferenceProcessor& ref_processor,
|
||||
ReferenceProcessorPhaseTimes* phase_times)
|
||||
: ProcessTask(ref_processor, false /* marks_oops_alive */, phase_times) { }
|
||||
: RefProcTask(ref_processor,
|
||||
phase_times) {}
|
||||
|
||||
virtual void work(uint worker_id,
|
||||
BoolObjectClosure& is_alive,
|
||||
OopClosure& keep_alive,
|
||||
VoidClosure& complete_gc) {
|
||||
void rp_work(uint worker_id,
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc) override {
|
||||
ResourceMark rm;
|
||||
RefProcWorkerTimeTracker t(_phase_times->phase2_worker_time_sec(), worker_id);
|
||||
{
|
||||
RefProcSubPhasesWorkerTimeTracker tt(ReferenceProcessor::SoftRefSubPhase2, _phase_times, worker_id);
|
||||
@ -579,42 +580,44 @@ public:
|
||||
}
|
||||
// Close the reachable set; needed for collectors which keep_alive_closure do
|
||||
// not immediately complete their work.
|
||||
complete_gc.do_void();
|
||||
complete_gc->do_void();
|
||||
}
|
||||
};
|
||||
|
||||
class RefProcPhase3Task: public AbstractRefProcTaskExecutor::ProcessTask {
|
||||
class RefProcPhase3Task: public RefProcTask {
|
||||
public:
|
||||
RefProcPhase3Task(ReferenceProcessor& ref_processor,
|
||||
RefProcPhase3Task(ReferenceProcessor& ref_processor,
|
||||
ReferenceProcessorPhaseTimes* phase_times)
|
||||
: ProcessTask(ref_processor, true /* marks_oops_alive */, phase_times) { }
|
||||
: RefProcTask(ref_processor,
|
||||
phase_times) {}
|
||||
|
||||
virtual void work(uint worker_id,
|
||||
BoolObjectClosure& is_alive,
|
||||
OopClosure& keep_alive,
|
||||
VoidClosure& complete_gc)
|
||||
{
|
||||
void rp_work(uint worker_id,
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc) override {
|
||||
ResourceMark rm;
|
||||
RefProcSubPhasesWorkerTimeTracker tt(ReferenceProcessor::FinalRefSubPhase3, _phase_times, worker_id);
|
||||
_ref_processor.process_final_keep_alive_work(_ref_processor._discoveredFinalRefs[worker_id], &keep_alive, &complete_gc);
|
||||
_ref_processor.process_final_keep_alive_work(_ref_processor._discoveredFinalRefs[worker_id], keep_alive, complete_gc);
|
||||
}
|
||||
};
|
||||
|
||||
class RefProcPhase4Task: public AbstractRefProcTaskExecutor::ProcessTask {
|
||||
class RefProcPhase4Task: public RefProcTask {
|
||||
public:
|
||||
RefProcPhase4Task(ReferenceProcessor& ref_processor,
|
||||
RefProcPhase4Task(ReferenceProcessor& ref_processor,
|
||||
ReferenceProcessorPhaseTimes* phase_times)
|
||||
: ProcessTask(ref_processor, false /* marks_oops_alive */, phase_times) { }
|
||||
: RefProcTask(ref_processor,
|
||||
phase_times) {}
|
||||
|
||||
virtual void work(uint worker_id,
|
||||
BoolObjectClosure& is_alive,
|
||||
OopClosure& keep_alive,
|
||||
VoidClosure& complete_gc)
|
||||
{
|
||||
void rp_work(uint worker_id,
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc) override {
|
||||
ResourceMark rm;
|
||||
RefProcSubPhasesWorkerTimeTracker tt(ReferenceProcessor::PhantomRefSubPhase4, _phase_times, worker_id);
|
||||
size_t const removed = _ref_processor.process_phantom_refs_work(_ref_processor._discoveredPhantomRefs[worker_id],
|
||||
&is_alive,
|
||||
&keep_alive,
|
||||
&complete_gc);
|
||||
is_alive,
|
||||
keep_alive,
|
||||
complete_gc);
|
||||
_phase_times->add_ref_cleared(REF_PHANTOM, removed);
|
||||
}
|
||||
};
|
||||
@ -771,16 +774,33 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[])
|
||||
#endif
|
||||
}
|
||||
|
||||
void ReferenceProcessor::process_soft_ref_reconsider(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times) {
|
||||
assert(!processing_is_mt() || task_executor != NULL, "Task executor must not be NULL when mt processing is set.");
|
||||
void ReferenceProcessor::run_task(RefProcTask& task, RefProcProxyTask& proxy_task, bool marks_oops_alive) {
|
||||
log_debug(gc, ref)("ReferenceProcessor::execute queues: %d, %s, marks_oops_alive: %s",
|
||||
num_queues(),
|
||||
processing_is_mt() ? "RefProcThreadModel::Multi" : "RefProcThreadModel::Single",
|
||||
marks_oops_alive ? "true" : "false");
|
||||
|
||||
proxy_task.prepare_run_task(task, num_queues(), processing_is_mt() ? RefProcThreadModel::Multi : RefProcThreadModel::Single, marks_oops_alive);
|
||||
if (processing_is_mt()) {
|
||||
WorkGang* gang = Universe::heap()->safepoint_workers();
|
||||
assert(gang != NULL, "can not dispatch multi threaded without a work gang");
|
||||
assert(gang->active_workers() >= num_queues(),
|
||||
"Ergonomically chosen workers(%u) should be less than or equal to active workers(%u)",
|
||||
num_queues(), gang->active_workers());
|
||||
gang->run_task(&proxy_task, num_queues());
|
||||
} else {
|
||||
for (unsigned i = 0; i < _max_num_queues; ++i) {
|
||||
proxy_task.work(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReferenceProcessor::process_soft_ref_reconsider(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times) {
|
||||
|
||||
size_t const num_soft_refs = total_count(_discoveredSoftRefs);
|
||||
phase_times->set_ref_discovered(REF_SOFT, num_soft_refs);
|
||||
phase_times->set_processing_is_mt(processing_is_mt());
|
||||
phase_times.set_ref_discovered(REF_SOFT, num_soft_refs);
|
||||
phase_times.set_processing_is_mt(processing_is_mt());
|
||||
|
||||
if (num_soft_refs == 0) {
|
||||
log_debug(gc, ref)("Skipped phase 1 of Reference Processing: no references");
|
||||
@ -795,45 +815,29 @@ void ReferenceProcessor::process_soft_ref_reconsider(BoolObjectClosure* is_alive
|
||||
RefProcMTDegreeAdjuster a(this, RefPhase1, num_soft_refs);
|
||||
|
||||
if (processing_is_mt()) {
|
||||
RefProcBalanceQueuesTimeTracker tt(RefPhase1, phase_times);
|
||||
RefProcBalanceQueuesTimeTracker tt(RefPhase1, &phase_times);
|
||||
maybe_balance_queues(_discoveredSoftRefs);
|
||||
}
|
||||
|
||||
RefProcPhaseTimeTracker tt(RefPhase1, phase_times);
|
||||
RefProcPhaseTimeTracker tt(RefPhase1, &phase_times);
|
||||
|
||||
log_reflist("Phase 1 Soft before", _discoveredSoftRefs, _max_num_queues);
|
||||
if (processing_is_mt()) {
|
||||
RefProcPhase1Task phase1(*this, phase_times, _current_soft_ref_policy);
|
||||
task_executor->execute(phase1, num_queues());
|
||||
} else {
|
||||
size_t removed = 0;
|
||||
|
||||
RefProcSubPhasesWorkerTimeTracker tt2(SoftRefSubPhase1, phase_times, 0);
|
||||
for (uint i = 0; i < _max_num_queues; i++) {
|
||||
removed += process_soft_ref_reconsider_work(_discoveredSoftRefs[i], _current_soft_ref_policy,
|
||||
is_alive, keep_alive, complete_gc);
|
||||
}
|
||||
|
||||
phase_times->add_ref_cleared(REF_SOFT, removed);
|
||||
}
|
||||
RefProcPhase1Task phase1(*this, &phase_times, _current_soft_ref_policy);
|
||||
run_task(phase1, proxy_task, true);
|
||||
log_reflist("Phase 1 Soft after", _discoveredSoftRefs, _max_num_queues);
|
||||
}
|
||||
|
||||
void ReferenceProcessor::process_soft_weak_final_refs(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times) {
|
||||
assert(!processing_is_mt() || task_executor != NULL, "Task executor must not be NULL when mt processing is set.");
|
||||
void ReferenceProcessor::process_soft_weak_final_refs(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times) {
|
||||
|
||||
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_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());
|
||||
phase_times.set_processing_is_mt(processing_is_mt());
|
||||
|
||||
if (num_total_refs == 0) {
|
||||
log_debug(gc, ref)("Skipped phase 2 of Reference Processing: no references");
|
||||
@ -843,68 +847,31 @@ void ReferenceProcessor::process_soft_weak_final_refs(BoolObjectClosure* is_aliv
|
||||
RefProcMTDegreeAdjuster a(this, RefPhase2, num_total_refs);
|
||||
|
||||
if (processing_is_mt()) {
|
||||
RefProcBalanceQueuesTimeTracker tt(RefPhase2, phase_times);
|
||||
RefProcBalanceQueuesTimeTracker tt(RefPhase2, &phase_times);
|
||||
maybe_balance_queues(_discoveredSoftRefs);
|
||||
maybe_balance_queues(_discoveredWeakRefs);
|
||||
maybe_balance_queues(_discoveredFinalRefs);
|
||||
}
|
||||
|
||||
RefProcPhaseTimeTracker tt(RefPhase2, phase_times);
|
||||
RefProcPhaseTimeTracker tt(RefPhase2, &phase_times);
|
||||
|
||||
log_reflist("Phase 2 Soft before", _discoveredSoftRefs, _max_num_queues);
|
||||
log_reflist("Phase 2 Weak before", _discoveredWeakRefs, _max_num_queues);
|
||||
log_reflist("Phase 2 Final before", _discoveredFinalRefs, _max_num_queues);
|
||||
if (processing_is_mt()) {
|
||||
RefProcPhase2Task phase2(*this, phase_times);
|
||||
task_executor->execute(phase2, num_queues());
|
||||
} else {
|
||||
RefProcWorkerTimeTracker t(phase_times->phase2_worker_time_sec(), 0);
|
||||
{
|
||||
size_t removed = 0;
|
||||
|
||||
RefProcSubPhasesWorkerTimeTracker tt2(SoftRefSubPhase2, phase_times, 0);
|
||||
for (uint i = 0; i < _max_num_queues; i++) {
|
||||
removed += process_soft_weak_final_refs_work(_discoveredSoftRefs[i], is_alive, keep_alive, true /* do_enqueue */);
|
||||
}
|
||||
RefProcPhase2Task phase2(*this, &phase_times);
|
||||
run_task(phase2, proxy_task, false);
|
||||
|
||||
phase_times->add_ref_cleared(REF_SOFT, removed);
|
||||
}
|
||||
{
|
||||
size_t removed = 0;
|
||||
|
||||
RefProcSubPhasesWorkerTimeTracker tt2(WeakRefSubPhase2, phase_times, 0);
|
||||
for (uint i = 0; i < _max_num_queues; i++) {
|
||||
removed += process_soft_weak_final_refs_work(_discoveredWeakRefs[i], is_alive, keep_alive, true /* do_enqueue */);
|
||||
}
|
||||
|
||||
phase_times->add_ref_cleared(REF_WEAK, removed);
|
||||
}
|
||||
{
|
||||
size_t removed = 0;
|
||||
|
||||
RefProcSubPhasesWorkerTimeTracker tt2(FinalRefSubPhase2, phase_times, 0);
|
||||
for (uint i = 0; i < _max_num_queues; i++) {
|
||||
removed += process_soft_weak_final_refs_work(_discoveredFinalRefs[i], is_alive, keep_alive, false /* do_enqueue */);
|
||||
}
|
||||
|
||||
phase_times->add_ref_cleared(REF_FINAL, removed);
|
||||
}
|
||||
complete_gc->do_void();
|
||||
}
|
||||
verify_total_count_zero(_discoveredSoftRefs, "SoftReference");
|
||||
verify_total_count_zero(_discoveredWeakRefs, "WeakReference");
|
||||
log_reflist("Phase 2 Final after", _discoveredFinalRefs, _max_num_queues);
|
||||
}
|
||||
|
||||
void ReferenceProcessor::process_final_keep_alive(OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times) {
|
||||
assert(!processing_is_mt() || task_executor != NULL, "Task executor must not be NULL when mt processing is set.");
|
||||
void ReferenceProcessor::process_final_keep_alive(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times) {
|
||||
|
||||
size_t const num_final_refs = total_count(_discoveredFinalRefs);
|
||||
|
||||
phase_times->set_processing_is_mt(processing_is_mt());
|
||||
phase_times.set_processing_is_mt(processing_is_mt());
|
||||
|
||||
if (num_final_refs == 0) {
|
||||
log_debug(gc, ref)("Skipped phase 3 of Reference Processing: no references");
|
||||
@ -914,37 +881,25 @@ void ReferenceProcessor::process_final_keep_alive(OopClosure* keep_alive,
|
||||
RefProcMTDegreeAdjuster a(this, RefPhase3, num_final_refs);
|
||||
|
||||
if (processing_is_mt()) {
|
||||
RefProcBalanceQueuesTimeTracker tt(RefPhase3, phase_times);
|
||||
RefProcBalanceQueuesTimeTracker tt(RefPhase3, &phase_times);
|
||||
maybe_balance_queues(_discoveredFinalRefs);
|
||||
}
|
||||
|
||||
// Phase 3:
|
||||
// . Traverse referents of final references and keep them and followers alive.
|
||||
RefProcPhaseTimeTracker tt(RefPhase3, phase_times);
|
||||
RefProcPhaseTimeTracker tt(RefPhase3, &phase_times);
|
||||
RefProcPhase3Task phase3(*this, &phase_times);
|
||||
run_task(phase3, proxy_task, true);
|
||||
|
||||
if (processing_is_mt()) {
|
||||
RefProcPhase3Task phase3(*this, phase_times);
|
||||
task_executor->execute(phase3, num_queues());
|
||||
} else {
|
||||
RefProcSubPhasesWorkerTimeTracker tt2(FinalRefSubPhase3, phase_times, 0);
|
||||
for (uint i = 0; i < _max_num_queues; i++) {
|
||||
process_final_keep_alive_work(_discoveredFinalRefs[i], keep_alive, complete_gc);
|
||||
}
|
||||
}
|
||||
verify_total_count_zero(_discoveredFinalRefs, "FinalReference");
|
||||
}
|
||||
|
||||
void ReferenceProcessor::process_phantom_refs(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times) {
|
||||
assert(!processing_is_mt() || task_executor != NULL, "Task executor must not be NULL when mt processing is set.");
|
||||
void ReferenceProcessor::process_phantom_refs(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times) {
|
||||
|
||||
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());
|
||||
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 phase 4 of Reference Processing: no references");
|
||||
@ -954,27 +909,18 @@ void ReferenceProcessor::process_phantom_refs(BoolObjectClosure* is_alive,
|
||||
RefProcMTDegreeAdjuster a(this, RefPhase4, num_phantom_refs);
|
||||
|
||||
if (processing_is_mt()) {
|
||||
RefProcBalanceQueuesTimeTracker tt(RefPhase4, phase_times);
|
||||
RefProcBalanceQueuesTimeTracker tt(RefPhase4, &phase_times);
|
||||
maybe_balance_queues(_discoveredPhantomRefs);
|
||||
}
|
||||
|
||||
// Phase 4: Walk phantom references appropriately.
|
||||
RefProcPhaseTimeTracker tt(RefPhase4, phase_times);
|
||||
RefProcPhaseTimeTracker tt(RefPhase4, &phase_times);
|
||||
|
||||
log_reflist("Phase 4 Phantom before", _discoveredPhantomRefs, _max_num_queues);
|
||||
if (processing_is_mt()) {
|
||||
RefProcPhase4Task phase4(*this, phase_times);
|
||||
task_executor->execute(phase4, num_queues());
|
||||
} else {
|
||||
size_t removed = 0;
|
||||
|
||||
RefProcSubPhasesWorkerTimeTracker tt(PhantomRefSubPhase4, phase_times, 0);
|
||||
for (uint i = 0; i < _max_num_queues; i++) {
|
||||
removed += process_phantom_refs_work(_discoveredPhantomRefs[i], is_alive, keep_alive, complete_gc);
|
||||
}
|
||||
RefProcPhase4Task phase4(*this, &phase_times);
|
||||
run_task(phase4, proxy_task, false);
|
||||
|
||||
phase_times->add_ref_cleared(REF_PHANTOM, removed);
|
||||
}
|
||||
verify_total_count_zero(_discoveredPhantomRefs, "PhantomReference");
|
||||
}
|
||||
|
||||
|
||||
@ -28,13 +28,15 @@
|
||||
#include "gc/shared/referenceDiscoverer.hpp"
|
||||
#include "gc/shared/referencePolicy.hpp"
|
||||
#include "gc/shared/referenceProcessorStats.hpp"
|
||||
#include "gc/shared/workgroup.hpp"
|
||||
#include "memory/referenceType.hpp"
|
||||
#include "oops/instanceRefKlass.hpp"
|
||||
|
||||
class AbstractRefProcTaskExecutor;
|
||||
class GCTimer;
|
||||
class ReferencePolicy;
|
||||
class ReferenceProcessorPhaseTimes;
|
||||
class RefProcTask;
|
||||
class RefProcProxyTask;
|
||||
|
||||
// List of discovered references.
|
||||
class DiscoveredList {
|
||||
@ -235,33 +237,24 @@ private:
|
||||
DiscoveredList* _discoveredFinalRefs;
|
||||
DiscoveredList* _discoveredPhantomRefs;
|
||||
|
||||
void run_task(RefProcTask& task, RefProcProxyTask& proxy_task, bool marks_oops_alive);
|
||||
|
||||
// Phase 1: Re-evaluate soft ref policy.
|
||||
void process_soft_ref_reconsider(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times);
|
||||
void process_soft_ref_reconsider(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times);
|
||||
|
||||
// Phase 2: Drop Soft/Weak/Final references with a NULL or live referent, and clear
|
||||
// and enqueue non-Final references.
|
||||
void process_soft_weak_final_refs(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times);
|
||||
void process_soft_weak_final_refs(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times);
|
||||
|
||||
// Phase 3: Keep alive followers of Final references, and enqueue.
|
||||
void process_final_keep_alive(OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times);
|
||||
void process_final_keep_alive(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times);
|
||||
|
||||
// Phase 4: Drop and keep alive live Phantom references, or clear and enqueue if dead.
|
||||
void process_phantom_refs(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times);
|
||||
void process_phantom_refs(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times);
|
||||
|
||||
// Work methods used by the process_* methods. All methods return the number of
|
||||
// removed elements.
|
||||
@ -432,11 +425,8 @@ public:
|
||||
|
||||
// Process references found during GC (called by the garbage collector)
|
||||
ReferenceProcessorStats
|
||||
process_discovered_references(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor,
|
||||
ReferenceProcessorPhaseTimes* phase_times);
|
||||
process_discovered_references(RefProcProxyTask& proxy_task,
|
||||
ReferenceProcessorPhaseTimes& phase_times);
|
||||
|
||||
// If a discovery is in process that is being superceded, abandon it: all
|
||||
// the discovered lists will be empty, and all the objects on them will
|
||||
@ -596,42 +586,57 @@ class ReferenceProcessorAtomicMutator: StackObj {
|
||||
}
|
||||
};
|
||||
|
||||
// This class is an interface used to implement task execution for the
|
||||
// reference processing.
|
||||
class AbstractRefProcTaskExecutor {
|
||||
public:
|
||||
enum class RefProcThreadModel { Multi, Single };
|
||||
|
||||
// Abstract tasks to execute.
|
||||
class ProcessTask;
|
||||
|
||||
// Executes a task using worker threads.
|
||||
virtual void execute(ProcessTask& task, uint ergo_workers) = 0;
|
||||
};
|
||||
|
||||
// Abstract reference processing task to execute.
|
||||
class AbstractRefProcTaskExecutor::ProcessTask {
|
||||
/*
|
||||
* This is the (base) task that handles reference processing that does not depend on
|
||||
* the chosen GC (Serial, Parallel or G1). This RefProcTask will be called from a subclass
|
||||
* of RefProcProxyTask. The RefProcProxyTask will give the behaviour of the selected GC by
|
||||
* calling rp_work with the gc-specific closures.
|
||||
*/
|
||||
class RefProcTask : StackObj {
|
||||
protected:
|
||||
ReferenceProcessor& _ref_processor;
|
||||
// Indicates whether the phase could generate work that should be balanced across
|
||||
// threads after execution.
|
||||
bool _marks_oops_alive;
|
||||
ReferenceProcessor& _ref_processor;
|
||||
ReferenceProcessorPhaseTimes* _phase_times;
|
||||
|
||||
ProcessTask(ReferenceProcessor& ref_processor,
|
||||
bool marks_oops_alive,
|
||||
public:
|
||||
RefProcTask(ReferenceProcessor& ref_processor,
|
||||
ReferenceProcessorPhaseTimes* phase_times)
|
||||
: _ref_processor(ref_processor),
|
||||
_marks_oops_alive(marks_oops_alive),
|
||||
_phase_times(phase_times)
|
||||
{ }
|
||||
_phase_times(phase_times) {}
|
||||
|
||||
virtual void rp_work(uint worker_id,
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc) = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the (base) task that handles reference processing that do depend on
|
||||
* the chosen GC (Serial, Parallel or G1). This RefProcProxyTask will call a subclass
|
||||
* of RefProcTask that will handle reference processing in a generic way for Serial,
|
||||
* Parallel and G1. This proxy will add the relevant closures, task terminators etc.
|
||||
*/
|
||||
class RefProcProxyTask : public AbstractGangTask {
|
||||
protected:
|
||||
const uint _max_workers;
|
||||
RefProcTask* _rp_task;
|
||||
RefProcThreadModel _tm;
|
||||
uint _queue_count;
|
||||
bool _marks_oops_alive;
|
||||
|
||||
public:
|
||||
virtual void work(uint worker_id,
|
||||
BoolObjectClosure& is_alive,
|
||||
OopClosure& keep_alive,
|
||||
VoidClosure& complete_gc) = 0;
|
||||
RefProcProxyTask(const char* name, uint max_workers) : AbstractGangTask(name), _max_workers(max_workers), _rp_task(nullptr),_tm(RefProcThreadModel::Single), _queue_count(0), _marks_oops_alive(false) {}
|
||||
|
||||
bool marks_oops_alive() const { return _marks_oops_alive; }
|
||||
void prepare_run_task(RefProcTask& rp_task, uint queue_count, RefProcThreadModel tm, bool marks_oops_alive) {
|
||||
_rp_task = &rp_task;
|
||||
_tm = tm;
|
||||
_queue_count = queue_count;
|
||||
_marks_oops_alive = marks_oops_alive;
|
||||
prepare_run_task_hook();
|
||||
}
|
||||
|
||||
virtual void prepare_run_task_hook() {}
|
||||
};
|
||||
|
||||
// Temporarily change the number of workers based on given reference count.
|
||||
|
||||
@ -164,9 +164,8 @@ RefProcPhaseTimeTracker::~RefProcPhaseTimeTracker() {
|
||||
}
|
||||
|
||||
RefProcTotalPhaseTimesTracker::RefProcTotalPhaseTimesTracker(ReferenceProcessor::RefProcPhases phase_number,
|
||||
ReferenceProcessorPhaseTimes* phase_times,
|
||||
ReferenceProcessor* rp) :
|
||||
RefProcPhaseTimeBaseTracker(phase_enum_2_phase_string(phase_number), phase_number, phase_times), _rp(rp) {
|
||||
ReferenceProcessorPhaseTimes* phase_times) :
|
||||
RefProcPhaseTimeBaseTracker(phase_enum_2_phase_string(phase_number), phase_number, phase_times) {
|
||||
}
|
||||
|
||||
RefProcTotalPhaseTimesTracker::~RefProcTotalPhaseTimesTracker() {
|
||||
|
||||
@ -160,11 +160,9 @@ public:
|
||||
|
||||
// Highest level time tracker.
|
||||
class RefProcTotalPhaseTimesTracker : public RefProcPhaseTimeBaseTracker {
|
||||
ReferenceProcessor* _rp;
|
||||
public:
|
||||
RefProcTotalPhaseTimesTracker(ReferenceProcessor::RefProcPhases phase_number,
|
||||
ReferenceProcessorPhaseTimes* phase_times,
|
||||
ReferenceProcessor* rp);
|
||||
ReferenceProcessorPhaseTimes* phase_times);
|
||||
~RefProcTotalPhaseTimesTracker();
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user