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, "