src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp

changeset 0
f90c822e73f8
child 6876
710a3c8b516e
     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 +}

mercurial