1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp Wed Apr 27 01:25:04 2016 +0800 1.3 @@ -0,0 +1,268 @@ 1.4 +/* 1.5 + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "precompiled.hpp" 1.29 +#include "gc_implementation/g1/concurrentG1Refine.hpp" 1.30 +#include "gc_implementation/g1/concurrentG1RefineThread.hpp" 1.31 +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" 1.32 +#include "gc_implementation/g1/g1CollectorPolicy.hpp" 1.33 +#include "memory/resourceArea.hpp" 1.34 +#include "runtime/handles.inline.hpp" 1.35 +#include "runtime/mutexLocker.hpp" 1.36 + 1.37 +ConcurrentG1RefineThread:: 1.38 +ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next, 1.39 + uint worker_id_offset, uint worker_id) : 1.40 + ConcurrentGCThread(), 1.41 + _worker_id_offset(worker_id_offset), 1.42 + _worker_id(worker_id), 1.43 + _active(false), 1.44 + _next(next), 1.45 + _monitor(NULL), 1.46 + _cg1r(cg1r), 1.47 + _vtime_accum(0.0) 1.48 +{ 1.49 + 1.50 + // Each thread has its own monitor. The i-th thread is responsible for signalling 1.51 + // to thread i+1 if the number of buffers in the queue exceeds a threashold for this 1.52 + // thread. Monitors are also used to wake up the threads during termination. 1.53 + // The 0th worker in notified by mutator threads and has a special monitor. 1.54 + // The last worker is used for young gen rset size sampling. 1.55 + if (worker_id > 0) { 1.56 + _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true); 1.57 + } else { 1.58 + _monitor = DirtyCardQ_CBL_mon; 1.59 + } 1.60 + initialize(); 1.61 + create_and_start(); 1.62 +} 1.63 + 1.64 +void ConcurrentG1RefineThread::initialize() { 1.65 + if (_worker_id < cg1r()->worker_thread_num()) { 1.66 + // Current thread activation threshold 1.67 + _threshold = MIN2<int>(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(), 1.68 + cg1r()->yellow_zone()); 1.69 + // A thread deactivates once the number of buffer reached a deactivation threshold 1.70 + _deactivation_threshold = MAX2<int>(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone()); 1.71 + } else { 1.72 + set_active(true); 1.73 + } 1.74 +} 1.75 + 1.76 +void ConcurrentG1RefineThread::sample_young_list_rs_lengths() { 1.77 + G1CollectedHeap* g1h = G1CollectedHeap::heap(); 1.78 + G1CollectorPolicy* g1p = g1h->g1_policy(); 1.79 + if (g1p->adaptive_young_list_length()) { 1.80 + int regions_visited = 0; 1.81 + g1h->young_list()->rs_length_sampling_init(); 1.82 + while (g1h->young_list()->rs_length_sampling_more()) { 1.83 + g1h->young_list()->rs_length_sampling_next(); 1.84 + ++regions_visited; 1.85 + 1.86 + // we try to yield every time we visit 10 regions 1.87 + if (regions_visited == 10) { 1.88 + if (_sts.should_yield()) { 1.89 + _sts.yield("G1 refine"); 1.90 + // we just abandon the iteration 1.91 + break; 1.92 + } 1.93 + regions_visited = 0; 1.94 + } 1.95 + } 1.96 + 1.97 + g1p->revise_young_list_target_length_if_necessary(); 1.98 + } 1.99 +} 1.100 + 1.101 +void ConcurrentG1RefineThread::run_young_rs_sampling() { 1.102 + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 1.103 + _vtime_start = os::elapsedVTime(); 1.104 + while(!_should_terminate) { 1.105 + _sts.join(); 1.106 + sample_young_list_rs_lengths(); 1.107 + _sts.leave(); 1.108 + 1.109 + if (os::supports_vtime()) { 1.110 + _vtime_accum = (os::elapsedVTime() - _vtime_start); 1.111 + } else { 1.112 + _vtime_accum = 0.0; 1.113 + } 1.114 + 1.115 + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); 1.116 + if (_should_terminate) { 1.117 + break; 1.118 + } 1.119 + _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefinementServiceIntervalMillis); 1.120 + } 1.121 +} 1.122 + 1.123 +void ConcurrentG1RefineThread::wait_for_completed_buffers() { 1.124 + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 1.125 + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); 1.126 + while (!_should_terminate && !is_active()) { 1.127 + _monitor->wait(Mutex::_no_safepoint_check_flag); 1.128 + } 1.129 +} 1.130 + 1.131 +bool ConcurrentG1RefineThread::is_active() { 1.132 + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 1.133 + return _worker_id > 0 ? _active : dcqs.process_completed_buffers(); 1.134 +} 1.135 + 1.136 +void ConcurrentG1RefineThread::activate() { 1.137 + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); 1.138 + if (_worker_id > 0) { 1.139 + if (G1TraceConcRefinement) { 1.140 + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 1.141 + gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d", 1.142 + _worker_id, _threshold, (int)dcqs.completed_buffers_num()); 1.143 + } 1.144 + set_active(true); 1.145 + } else { 1.146 + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 1.147 + dcqs.set_process_completed(true); 1.148 + } 1.149 + _monitor->notify(); 1.150 +} 1.151 + 1.152 +void ConcurrentG1RefineThread::deactivate() { 1.153 + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); 1.154 + if (_worker_id > 0) { 1.155 + if (G1TraceConcRefinement) { 1.156 + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 1.157 + gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d", 1.158 + _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num()); 1.159 + } 1.160 + set_active(false); 1.161 + } else { 1.162 + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 1.163 + dcqs.set_process_completed(false); 1.164 + } 1.165 +} 1.166 + 1.167 +void ConcurrentG1RefineThread::run() { 1.168 + initialize_in_thread(); 1.169 + wait_for_universe_init(); 1.170 + 1.171 + if (_worker_id >= cg1r()->worker_thread_num()) { 1.172 + run_young_rs_sampling(); 1.173 + terminate(); 1.174 + return; 1.175 + } 1.176 + 1.177 + _vtime_start = os::elapsedVTime(); 1.178 + while (!_should_terminate) { 1.179 + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); 1.180 + 1.181 + // Wait for work 1.182 + wait_for_completed_buffers(); 1.183 + 1.184 + if (_should_terminate) { 1.185 + break; 1.186 + } 1.187 + 1.188 + _sts.join(); 1.189 + 1.190 + do { 1.191 + int curr_buffer_num = (int)dcqs.completed_buffers_num(); 1.192 + // If the number of the buffers falls down into the yellow zone, 1.193 + // that means that the transition period after the evacuation pause has ended. 1.194 + if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) { 1.195 + dcqs.set_completed_queue_padding(0); 1.196 + } 1.197 + 1.198 + if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) { 1.199 + // If the number of the buffer has fallen below our threshold 1.200 + // we should deactivate. The predecessor will reactivate this 1.201 + // thread should the number of the buffers cross the threshold again. 1.202 + deactivate(); 1.203 + break; 1.204 + } 1.205 + 1.206 + // Check if we need to activate the next thread. 1.207 + if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) { 1.208 + _next->activate(); 1.209 + } 1.210 + } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone())); 1.211 + 1.212 + // We can exit the loop above while being active if there was a yield request. 1.213 + if (is_active()) { 1.214 + deactivate(); 1.215 + } 1.216 + 1.217 + _sts.leave(); 1.218 + 1.219 + if (os::supports_vtime()) { 1.220 + _vtime_accum = (os::elapsedVTime() - _vtime_start); 1.221 + } else { 1.222 + _vtime_accum = 0.0; 1.223 + } 1.224 + } 1.225 + assert(_should_terminate, "just checking"); 1.226 + terminate(); 1.227 +} 1.228 + 1.229 + 1.230 +void ConcurrentG1RefineThread::yield() { 1.231 + if (G1TraceConcRefinement) { 1.232 + gclog_or_tty->print_cr("G1-Refine-yield"); 1.233 + } 1.234 + _sts.yield("G1 refine"); 1.235 + if (G1TraceConcRefinement) { 1.236 + gclog_or_tty->print_cr("G1-Refine-yield-end"); 1.237 + } 1.238 +} 1.239 + 1.240 +void ConcurrentG1RefineThread::stop() { 1.241 + // it is ok to take late safepoints here, if needed 1.242 + { 1.243 + MutexLockerEx mu(Terminator_lock); 1.244 + _should_terminate = true; 1.245 + } 1.246 + 1.247 + { 1.248 + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); 1.249 + _monitor->notify(); 1.250 + } 1.251 + 1.252 + { 1.253 + MutexLockerEx mu(Terminator_lock); 1.254 + while (!_has_terminated) { 1.255 + Terminator_lock->wait(); 1.256 + } 1.257 + } 1.258 + if (G1TraceConcRefinement) { 1.259 + gclog_or_tty->print_cr("G1-Refine-stop"); 1.260 + } 1.261 +} 1.262 + 1.263 +void ConcurrentG1RefineThread::print() const { 1.264 + print_on(tty); 1.265 +} 1.266 + 1.267 +void ConcurrentG1RefineThread::print_on(outputStream* st) const { 1.268 + st->print("\"G1 Concurrent Refinement Thread#%d\" ", _worker_id); 1.269 + Thread::print_on(st); 1.270 + st->cr(); 1.271 +}