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:: iveresov@1230: ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next, iveresov@1230: int worker_id_offset, int worker_id) : ysr@777: ConcurrentGCThread(), iveresov@1230: _worker_id_offset(worker_id_offset), iveresov@1229: _worker_id(worker_id), iveresov@1229: _active(false), iveresov@1229: _next(next), ysr@777: _cg1r(cg1r), 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: 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) { iveresov@1229: DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); iveresov@1229: // Wait for completed log buffers to exist. iveresov@1229: { iveresov@1229: MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); iveresov@1229: while (((_worker_id == 0 && !dcqs.process_completed_buffers()) || iveresov@1229: (_worker_id > 0 && !is_active())) && iveresov@1229: !_should_terminate) { iveresov@1229: DirtyCardQ_CBL_mon->wait(Mutex::_no_safepoint_check_flag); iveresov@1229: } iveresov@1229: } iveresov@1229: iveresov@1229: if (_should_terminate) { iveresov@1229: return; iveresov@1229: } iveresov@1229: iveresov@1229: // Now we take them off (this doesn't hold locks while it applies iveresov@1229: // closures.) (If we did a full collection, then we'll do a full iveresov@1229: // traversal. iveresov@1229: _sts.join(); iveresov@1229: int n_logs = 0; iveresov@1229: int lower_limit = 0; iveresov@1229: double start_vtime_sec; // only used when G1SmoothConcRefine is on iveresov@1229: int prev_buffer_num; // only used when G1SmoothConcRefine is on iveresov@1229: // This thread activation threshold iveresov@1229: int threshold = DCQBarrierProcessCompletedThreshold * _worker_id; iveresov@1229: // Next thread activation threshold iveresov@1229: int next_threshold = threshold + DCQBarrierProcessCompletedThreshold; iveresov@1229: int deactivation_threshold = MAX2(threshold - DCQBarrierProcessCompletedThreshold / 2, 0); iveresov@1229: iveresov@1229: if (G1SmoothConcRefine) { iveresov@1229: lower_limit = 0; iveresov@1229: start_vtime_sec = os::elapsedVTime(); iveresov@1229: prev_buffer_num = (int) dcqs.completed_buffers_num(); ysr@777: } else { iveresov@1229: lower_limit = DCQBarrierProcessCompletedThreshold / 4; // For now. ysr@777: } iveresov@1230: while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, lower_limit)) { iveresov@1229: double end_vtime_sec; iveresov@1229: double elapsed_vtime_sec; iveresov@1229: int elapsed_vtime_ms; iveresov@1229: int curr_buffer_num = (int) dcqs.completed_buffers_num(); iveresov@1229: iveresov@1229: if (G1SmoothConcRefine) { iveresov@1229: end_vtime_sec = os::elapsedVTime(); iveresov@1229: elapsed_vtime_sec = end_vtime_sec - start_vtime_sec; iveresov@1229: elapsed_vtime_ms = (int) (elapsed_vtime_sec * 1000.0); iveresov@1229: iveresov@1229: if (curr_buffer_num > prev_buffer_num || iveresov@1229: curr_buffer_num > next_threshold) { iveresov@1229: decreaseInterval(elapsed_vtime_ms); iveresov@1229: } else if (curr_buffer_num < prev_buffer_num) { iveresov@1229: increaseInterval(elapsed_vtime_ms); iveresov@1229: } iveresov@1229: } iveresov@1229: if (_worker_id == 0) { iveresov@1229: sample_young_list_rs_lengths(); iveresov@1229: } else if (curr_buffer_num < deactivation_threshold) { iveresov@1229: // If the number of the buffer has fallen below our threshold iveresov@1229: // we should deactivate. The predecessor will reactivate this iveresov@1229: // thread should the number of the buffers cross the threshold again. iveresov@1229: MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); iveresov@1229: deactivate(); iveresov@1229: if (G1TraceConcurrentRefinement) { iveresov@1229: gclog_or_tty->print_cr("G1-Refine-deactivated worker %d", _worker_id); iveresov@1229: } iveresov@1229: break; iveresov@1229: } iveresov@1229: _co_tracker.update(false); iveresov@1229: iveresov@1229: // Check if we need to activate the next thread. iveresov@1229: if (curr_buffer_num > next_threshold && _next != NULL && !_next->is_active()) { iveresov@1229: MutexLockerEx x(DirtyCardQ_CBL_mon, Mutex::_no_safepoint_check_flag); iveresov@1229: _next->activate(); iveresov@1229: DirtyCardQ_CBL_mon->notify_all(); iveresov@1229: if (G1TraceConcurrentRefinement) { iveresov@1229: gclog_or_tty->print_cr("G1-Refine-activated worker %d", _next->_worker_id); iveresov@1229: } iveresov@1229: } iveresov@1229: iveresov@1229: if (G1SmoothConcRefine) { iveresov@1229: prev_buffer_num = curr_buffer_num; iveresov@1229: _sts.leave(); iveresov@1229: os::sleep(Thread::current(), (jlong) _interval_ms, false); iveresov@1229: _sts.join(); iveresov@1229: start_vtime_sec = os::elapsedVTime(); iveresov@1229: } iveresov@1229: n_logs++; iveresov@1229: } iveresov@1229: _co_tracker.update(false); ysr@777: _sts.leave(); iveresov@1229: 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() { johnc@1186: if (G1TraceConcurrentRefinement) gclog_or_tty->print_cr("G1-Refine-yield"); ysr@777: _sts.yield("G1 refine"); johnc@1186: if (G1TraceConcurrentRefinement) 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: } johnc@1186: if (G1TraceConcurrentRefinement) 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: }