ysr@777: /* ysr@777: * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. ysr@777: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ysr@777: * ysr@777: * This code is free software; you can redistribute it and/or modify it ysr@777: * under the terms of the GNU General Public License version 2 only, as ysr@777: * published by the Free Software Foundation. ysr@777: * ysr@777: * This code is distributed in the hope that it will be useful, but WITHOUT ysr@777: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ysr@777: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ysr@777: * version 2 for more details (a copy is included in the LICENSE file that ysr@777: * accompanied this code). ysr@777: * ysr@777: * You should have received a copy of the GNU General Public License version ysr@777: * 2 along with this work; if not, write to the Free Software Foundation, ysr@777: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ysr@777: * ysr@777: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, ysr@777: * CA 95054 USA or visit www.sun.com if you need additional information or ysr@777: * have any questions. ysr@777: * ysr@777: */ ysr@777: ysr@777: #include "incls/_precompiled.incl" ysr@777: #include "incls/_concurrentG1RefineThread.cpp.incl" ysr@777: ysr@777: // ======= Concurrent Mark Thread ======== ysr@777: ysr@777: // The CM thread is created when the G1 garbage collector is used ysr@777: ysr@777: ConcurrentG1RefineThread:: ysr@777: ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r) : ysr@777: ConcurrentGCThread(), ysr@777: _cg1r(cg1r), ysr@777: _started(false), ysr@777: _in_progress(false), ysr@777: _do_traversal(false), ysr@777: _vtime_accum(0.0), ysr@777: _co_tracker(G1CRGroup), ysr@777: _interval_ms(5.0) ysr@777: { ysr@777: create_and_start(); ysr@777: } ysr@777: ysr@777: const long timeout = 200; // ms. ysr@777: ysr@777: void ConcurrentG1RefineThread::traversalBasedRefinement() { ysr@777: _cg1r->wait_for_ConcurrentG1Refine_enabled(); ysr@777: MutexLocker x(G1ConcRefine_mon); ysr@777: while (_cg1r->enabled()) { ysr@777: MutexUnlocker ux(G1ConcRefine_mon); ysr@777: ResourceMark rm; ysr@777: HandleMark hm; ysr@777: ysr@777: if (TraceG1Refine) gclog_or_tty->print_cr("G1-Refine starting pass"); ysr@777: _sts.join(); ysr@777: bool no_sleep = _cg1r->refine(); ysr@777: _sts.leave(); ysr@777: if (!no_sleep) { ysr@777: MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); ysr@777: // We do this only for the timeout; we don't expect this to be signalled. ysr@777: CGC_lock->wait(Mutex::_no_safepoint_check_flag, timeout); ysr@777: } ysr@777: } ysr@777: } ysr@777: ysr@777: void ConcurrentG1RefineThread::queueBasedRefinement() { ysr@777: DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); ysr@777: // Wait for completed log buffers to exist. ysr@777: { ysr@777: MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); ysr@777: while (!_do_traversal && !dcqs.process_completed_buffers() && ysr@777: !_should_terminate) { ysr@777: DirtyCardQ_CBL_mon->wait(Mutex::_no_safepoint_check_flag); ysr@777: } ysr@777: } ysr@777: ysr@777: if (_should_terminate) { ysr@777: return; ysr@777: } ysr@777: ysr@777: // Now we take them off (this doesn't hold locks while it applies ysr@777: // closures.) (If we did a full collection, then we'll do a full ysr@777: // traversal. ysr@777: _sts.join(); ysr@777: if (_do_traversal) { ysr@777: (void)_cg1r->refine(); ysr@777: switch (_cg1r->get_last_pya()) { ysr@777: case PYA_cancel: case PYA_continue: ysr@777: // Continue was caught and handled inside "refine". If it's still ysr@777: // "continue" when we get here, we're done. ysr@777: _do_traversal = false; ysr@777: break; ysr@777: case PYA_restart: ysr@777: assert(_do_traversal, "Because of Full GC."); ysr@777: break; ysr@777: } ysr@777: } else { ysr@777: int n_logs = 0; ysr@777: int lower_limit = 0; ysr@777: double start_vtime_sec; // only used when G1SmoothConcRefine is on ysr@777: int prev_buffer_num; // only used when G1SmoothConcRefine is on ysr@777: ysr@777: if (G1SmoothConcRefine) { ysr@777: lower_limit = 0; ysr@777: start_vtime_sec = os::elapsedVTime(); ysr@777: prev_buffer_num = (int) dcqs.completed_buffers_num(); ysr@777: } else { ysr@777: lower_limit = DCQBarrierProcessCompletedThreshold / 4; // For now. ysr@777: } ysr@777: while (dcqs.apply_closure_to_completed_buffer(0, lower_limit)) { ysr@777: double end_vtime_sec; ysr@777: double elapsed_vtime_sec; ysr@777: int elapsed_vtime_ms; ysr@777: int curr_buffer_num; ysr@777: ysr@777: if (G1SmoothConcRefine) { ysr@777: end_vtime_sec = os::elapsedVTime(); ysr@777: elapsed_vtime_sec = end_vtime_sec - start_vtime_sec; ysr@777: elapsed_vtime_ms = (int) (elapsed_vtime_sec * 1000.0); ysr@777: curr_buffer_num = (int) dcqs.completed_buffers_num(); ysr@777: ysr@777: if (curr_buffer_num > prev_buffer_num || ysr@777: curr_buffer_num > DCQBarrierProcessCompletedThreshold) { ysr@777: decreaseInterval(elapsed_vtime_ms); ysr@777: } else if (curr_buffer_num < prev_buffer_num) { ysr@777: increaseInterval(elapsed_vtime_ms); ysr@777: } ysr@777: } ysr@777: ysr@777: sample_young_list_rs_lengths(); ysr@777: _co_tracker.update(false); ysr@777: ysr@777: if (G1SmoothConcRefine) { ysr@777: prev_buffer_num = curr_buffer_num; ysr@777: _sts.leave(); ysr@777: os::sleep(Thread::current(), (jlong) _interval_ms, false); ysr@777: _sts.join(); iveresov@1051: start_vtime_sec = os::elapsedVTime(); ysr@777: } ysr@777: n_logs++; ysr@777: } ysr@777: // Make sure we harvest the PYA, if any. ysr@777: (void)_cg1r->get_pya(); ysr@777: } ysr@777: _sts.leave(); ysr@777: } ysr@777: ysr@777: void ConcurrentG1RefineThread::sample_young_list_rs_lengths() { ysr@777: G1CollectedHeap* g1h = G1CollectedHeap::heap(); ysr@777: G1CollectorPolicy* g1p = g1h->g1_policy(); ysr@777: if (g1p->adaptive_young_list_length()) { ysr@777: int regions_visited = 0; ysr@777: ysr@777: g1h->young_list_rs_length_sampling_init(); ysr@777: while (g1h->young_list_rs_length_sampling_more()) { ysr@777: g1h->young_list_rs_length_sampling_next(); ysr@777: ++regions_visited; ysr@777: ysr@777: // we try to yield every time we visit 10 regions ysr@777: if (regions_visited == 10) { ysr@777: if (_sts.should_yield()) { ysr@777: _sts.yield("G1 refine"); ysr@777: // we just abandon the iteration ysr@777: break; ysr@777: } ysr@777: regions_visited = 0; ysr@777: } ysr@777: } ysr@777: ysr@777: g1p->check_prediction_validity(); ysr@777: } ysr@777: } ysr@777: ysr@777: void ConcurrentG1RefineThread::run() { ysr@777: initialize_in_thread(); ysr@777: _vtime_start = os::elapsedVTime(); ysr@777: wait_for_universe_init(); ysr@777: ysr@777: _co_tracker.enable(); ysr@777: _co_tracker.start(); ysr@777: ysr@777: while (!_should_terminate) { ysr@777: // wait until started is set. ysr@777: if (G1RSBarrierUseQueue) { ysr@777: queueBasedRefinement(); ysr@777: } else { ysr@777: traversalBasedRefinement(); ysr@777: } ysr@777: _sts.join(); ysr@777: _co_tracker.update(); ysr@777: _sts.leave(); ysr@777: if (os::supports_vtime()) { ysr@777: _vtime_accum = (os::elapsedVTime() - _vtime_start); ysr@777: } else { ysr@777: _vtime_accum = 0.0; ysr@777: } ysr@777: } ysr@777: _sts.join(); ysr@777: _co_tracker.update(true); ysr@777: _sts.leave(); ysr@777: assert(_should_terminate, "just checking"); ysr@777: ysr@777: terminate(); ysr@777: } ysr@777: ysr@777: ysr@777: void ConcurrentG1RefineThread::yield() { ysr@777: if (TraceG1Refine) gclog_or_tty->print_cr("G1-Refine-yield"); ysr@777: _sts.yield("G1 refine"); ysr@777: if (TraceG1Refine) gclog_or_tty->print_cr("G1-Refine-yield-end"); ysr@777: } ysr@777: ysr@777: void ConcurrentG1RefineThread::stop() { ysr@777: // it is ok to take late safepoints here, if needed ysr@777: { ysr@777: MutexLockerEx mu(Terminator_lock); ysr@777: _should_terminate = true; ysr@777: } ysr@777: ysr@777: { ysr@777: MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); ysr@777: DirtyCardQ_CBL_mon->notify_all(); ysr@777: } ysr@777: ysr@777: { ysr@777: MutexLockerEx mu(Terminator_lock); ysr@777: while (!_has_terminated) { ysr@777: Terminator_lock->wait(); ysr@777: } ysr@777: } ysr@777: if (TraceG1Refine) gclog_or_tty->print_cr("G1-Refine-stop"); ysr@777: } ysr@777: ysr@777: void ConcurrentG1RefineThread::print() { ysr@777: gclog_or_tty->print("\"Concurrent G1 Refinement Thread\" "); ysr@777: Thread::print(); ysr@777: gclog_or_tty->cr(); ysr@777: } ysr@777: ysr@777: void ConcurrentG1RefineThread::set_do_traversal(bool b) { ysr@777: _do_traversal = b; ysr@777: }