src/share/vm/gc_implementation/g1/concurrentMark.cpp
Print this page
rev 4278 : [mq]: 8009536-fix
rev 4279 : 8009940: G1: assert(_finger == _heap_end) failed, concurrentMark.cpp:809
Summary: Skip reference processing if the global marking stack overflows during remark. Do not call set_phase() from within parallel reference processing; use reset_for_reuse() instead. CMTask-0 should reset the marking state only during the concurrent phase of the marking cycle; if an overflow occurs at any stage during the remark, the marking state will be reset after reference processing.
*** 782,800 ****
CMTaskQueue* queue = _task_queues->queue(i);
queue->set_empty();
}
}
! void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) {
assert(active_tasks <= _max_worker_id, "we should not have more");
_active_tasks = active_tasks;
// Need to update the three data structures below according to the
// number of active threads for this phase.
_terminator = ParallelTaskTerminator((int) active_tasks, _task_queues);
_first_overflow_barrier_sync.set_n_workers((int) active_tasks);
_second_overflow_barrier_sync.set_n_workers((int) active_tasks);
_concurrent = concurrent;
// We propagate this to all tasks, not just the active ones.
for (uint i = 0; i < _max_worker_id; ++i)
_tasks[i]->set_concurrent(concurrent);
--- 782,804 ----
CMTaskQueue* queue = _task_queues->queue(i);
queue->set_empty();
}
}
! void ConcurrentMark::set_concurrency(uint active_tasks) {
assert(active_tasks <= _max_worker_id, "we should not have more");
_active_tasks = active_tasks;
// Need to update the three data structures below according to the
// number of active threads for this phase.
_terminator = ParallelTaskTerminator((int) active_tasks, _task_queues);
_first_overflow_barrier_sync.set_n_workers((int) active_tasks);
_second_overflow_barrier_sync.set_n_workers((int) active_tasks);
+ }
+
+ void ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurrent) {
+ set_concurrency(active_tasks);
_concurrent = concurrent;
// We propagate this to all tasks, not just the active ones.
for (uint i = 0; i < _max_worker_id; ++i)
_tasks[i]->set_concurrent(concurrent);
*** 804,814 ****
} else {
// We currently assume that the concurrent flag has been set to
// false before we start remark. At this point we should also be
// in a STW phase.
assert(!concurrent_marking_in_progress(), "invariant");
! assert(_finger == _heap_end, "only way to get here");
update_g1_committed(true);
}
}
void ConcurrentMark::set_non_marking_state() {
--- 808,820 ----
} else {
// We currently assume that the concurrent flag has been set to
// false before we start remark. At this point we should also be
// in a STW phase.
assert(!concurrent_marking_in_progress(), "invariant");
! assert(_finger == _heap_end,
! err_msg("only way to get here: _finger: "PTR_FORMAT", _heap_end: "PTR_FORMAT,
! _finger, _heap_end));
update_g1_committed(true);
}
}
void ConcurrentMark::set_non_marking_state() {
*** 972,997 ****
if (verbose_low()) {
gclog_or_tty->print_cr("[%u] leaving first barrier", worker_id);
}
// let the task associated with with worker 0 do this
if (worker_id == 0) {
// task 0 is responsible for clearing the global data structures
// We should be here because of an overflow. During STW we should
// not clear the overflow flag since we rely on it being true when
// we exit this method to abort the pause and restart concurent
// marking.
! reset_marking_state(concurrent() /* clear_overflow */);
force_overflow()->update();
if (G1Log::fine()) {
gclog_or_tty->date_stamp(PrintGCDateStamps);
gclog_or_tty->stamp(PrintGCTimeStamps);
gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]");
}
}
// after this, each task should reset its own data structures then
// then go into the second barrier
}
--- 978,1011 ----
if (verbose_low()) {
gclog_or_tty->print_cr("[%u] leaving first barrier", worker_id);
}
+ // If we're executing the concurrent phase of marking, reset the marking
+ // state; otherwise the marking state is reset after reference processing,
+ // during the remark pause.
+ // If we reset here as a result of an overflow during the remark we will
+ // see assertion failures from any subsequent set_concurrency_and_phase()
+ // calls.
+ if (concurrent()) {
// let the task associated with with worker 0 do this
if (worker_id == 0) {
// task 0 is responsible for clearing the global data structures
// We should be here because of an overflow. During STW we should
// not clear the overflow flag since we rely on it being true when
// we exit this method to abort the pause and restart concurent
// marking.
! reset_marking_state(true /* clear_overflow */);
force_overflow()->update();
if (G1Log::fine()) {
gclog_or_tty->date_stamp(PrintGCDateStamps);
gclog_or_tty->stamp(PrintGCTimeStamps);
gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]");
}
}
+ }
// after this, each task should reset its own data structures then
// then go into the second barrier
}
*** 1005,1015 ****
}
_second_overflow_barrier_sync.enter();
if (concurrent()) {
ConcurrentGCThread::stsJoin();
}
! // at this point everything should be re-initialised and ready to go
if (verbose_low()) {
gclog_or_tty->print_cr("[%u] leaving second barrier", worker_id);
}
}
--- 1019,1029 ----
}
_second_overflow_barrier_sync.enter();
if (concurrent()) {
ConcurrentGCThread::stsJoin();
}
! // at this point everything should be re-initialized and ready to go
if (verbose_low()) {
gclog_or_tty->print_cr("[%u] leaving second barrier", worker_id);
}
}
*** 1221,1232 ****
assert(parallel_marking_threads() <= max_parallel_marking_threads(),
"Maximum number of marking threads exceeded");
uint active_workers = MAX2(1U, parallel_marking_threads());
! // Parallel task terminator is set in "set_phase()"
! set_phase(active_workers, true /* concurrent */);
CMConcurrentMarkingTask markingTask(this, cmThread());
if (use_parallel_marking_threads()) {
_parallel_workers->set_active_workers((int)active_workers);
// Don't set _n_par_threads because it affects MT in proceess_strong_roots()
--- 1235,1246 ----
assert(parallel_marking_threads() <= max_parallel_marking_threads(),
"Maximum number of marking threads exceeded");
uint active_workers = MAX2(1U, parallel_marking_threads());
! // Parallel task terminator is set in "set_concurrency_and_phase()"
! set_concurrency_and_phase(active_workers, true /* concurrent */);
CMConcurrentMarkingTask markingTask(this, cmThread());
if (use_parallel_marking_threads()) {
_parallel_workers->set_active_workers((int)active_workers);
// Don't set _n_par_threads because it affects MT in proceess_strong_roots()
*** 2359,2371 ****
assert(_workers != NULL, "Need parallel worker threads.");
assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
G1CMRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _cm);
! // We need to reset the phase for each task execution so that
! // the termination protocol of CMTask::do_marking_step works.
! _cm->set_phase(_active_workers, false /* concurrent */);
_g1h->set_par_threads(_active_workers);
_workers->run_task(&proc_task_proxy);
_g1h->set_par_threads(0);
}
--- 2373,2387 ----
assert(_workers != NULL, "Need parallel worker threads.");
assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
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 CMTask::do_marking_step() knows
! // how many workers to wait for.
! _cm->set_concurrency(_active_workers);
_g1h->set_par_threads(_active_workers);
_workers->run_task(&proc_task_proxy);
_g1h->set_par_threads(0);
}
*** 2387,2402 ****
--- 2403,2435 ----
assert(_workers != NULL, "Need parallel worker threads.");
assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
G1CMRefEnqueueTaskProxy enq_task_proxy(enq_task);
+ // Not strictly necessary but...
+ //
+ // We need to reset the concurrency level before each
+ // proxy task execution, so that the termination protocol
+ // and overflow handling in CMTask::do_marking_step() knows
+ // how many workers to wait for.
+ _cm->set_concurrency(_active_workers);
_g1h->set_par_threads(_active_workers);
_workers->run_task(&enq_task_proxy);
_g1h->set_par_threads(0);
}
void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
+ if (has_overflown()) {
+ // Skip processing the discovered references if we have
+ // overflown the global marking stack. Reference objects
+ // only get discovered once so it is OK to not
+ // de-populate the discovered reference lists. We could have,
+ // but the only benefit would be that, when marking restarts,
+ // less reference objects are discovered.
+ return;
+ }
+
ResourceMark rm;
HandleMark hm;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
*** 2448,2457 ****
--- 2481,2494 ----
// Parallel processing task executor.
G1CMRefProcTaskExecutor par_task_executor(g1h, this,
g1h->workers(), active_workers);
AbstractRefProcTaskExecutor* executor = (processing_is_mt ? &par_task_executor : NULL);
+ // Set the concurrency level. The phase was already set prior to
+ // executing the remark task.
+ set_concurrency(active_workers);
+
// Set the degree of MT processing here. If the discovery was done MT,
// the number of threads involved during discovery could differ from
// the number of active workers. This is OK as long as the discovered
// Reference lists are balanced (see balance_all_queues() and balance_queues()).
rp->set_active_mt_degree(active_workers);
*** 2538,2548 ****
if (active_workers == 0) {
assert(active_workers > 0, "Should have been set earlier");
active_workers = (uint) ParallelGCThreads;
g1h->workers()->set_active_workers(active_workers);
}
! set_phase(active_workers, false /* concurrent */);
// Leave _parallel_marking_threads at it's
// value originally calculated in the ConcurrentMark
// constructor and pass values of the active workers
// through the gang in the task.
--- 2575,2585 ----
if (active_workers == 0) {
assert(active_workers > 0, "Should have been set earlier");
active_workers = (uint) ParallelGCThreads;
g1h->workers()->set_active_workers(active_workers);
}
! set_concurrency_and_phase(active_workers, false /* concurrent */);
// Leave _parallel_marking_threads at it's
// value originally calculated in the ConcurrentMark
// constructor and pass values of the active workers
// through the gang in the task.
*** 2554,2564 ****
g1h->workers()->run_task(&remarkTask);
g1h->set_par_threads(0);
} else {
G1CollectedHeap::StrongRootsScope srs(g1h);
uint active_workers = 1;
! set_phase(active_workers, false /* concurrent */);
// Note - if there's no work gang then the VMThread will be
// the thread to execute the remark - serially. We have
// to pass true for the is_serial parameter so that
// CMTask::do_marking_step() doesn't enter the sync
--- 2591,2601 ----
g1h->workers()->run_task(&remarkTask);
g1h->set_par_threads(0);
} else {
G1CollectedHeap::StrongRootsScope srs(g1h);
uint active_workers = 1;
! set_concurrency_and_phase(active_workers, false /* concurrent */);
// Note - if there's no work gang then the VMThread will be
// the thread to execute the remark - serially. We have
// to pass true for the is_serial parameter so that
// CMTask::do_marking_step() doesn't enter the sync
*** 3945,3955 ****
(1) When the marking phase has been aborted (after a Full GC).
(2) When a global overflow (on the global stack) has been
triggered. Before the task aborts, it will actually sync up with
the other tasks to ensure that all the marking data structures
! (local queues, stacks, fingers etc.) are re-initialised so that
when do_marking_step() completes, the marking phase can
immediately restart.
(3) When enough completed SATB buffers are available. The
do_marking_step() method only tries to drain SATB buffers right
--- 3982,3992 ----
(1) When the marking phase has been aborted (after a Full GC).
(2) When a global overflow (on the global stack) has been
triggered. Before the task aborts, it will actually sync up with
the other tasks to ensure that all the marking data structures
! (local queues, stacks, fingers etc.) are re-initialized so that
when do_marking_step() completes, the marking phase can
immediately restart.
(3) When enough completed SATB buffers are available. The
do_marking_step() method only tries to drain SATB buffers right
*** 4392,4402 ****
if (!is_serial) {
// ...and enter the second barrier.
_cm->enter_second_sync_barrier(_worker_id);
}
! // At this point everything has bee re-initialised and we're
// ready to restart.
}
if (_cm->verbose_low()) {
gclog_or_tty->print_cr("[%u] <<<<<<<<<< ABORTING, target = %1.2lfms, "
--- 4429,4440 ----
if (!is_serial) {
// ...and enter the second barrier.
_cm->enter_second_sync_barrier(_worker_id);
}
! // At this point, if we're during the concurrent phase of
! // marking, everything has been re-initialized and we're
// ready to restart.
}
if (_cm->verbose_low()) {
gclog_or_tty->print_cr("[%u] <<<<<<<<<< ABORTING, target = %1.2lfms, "