hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp
changeset 30764 fec48bf5a827
parent 30613 a7815bb05ae2
child 30770 5ba2d9f2084d
equal deleted inserted replaced
30614:e45861098f5a 30764:fec48bf5a827
       
     1 /*
       
     2  * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "precompiled.hpp"
       
    26 #include "gc/g1/concurrentG1Refine.hpp"
       
    27 #include "gc/g1/concurrentG1RefineThread.hpp"
       
    28 #include "gc/g1/g1CollectedHeap.inline.hpp"
       
    29 #include "gc/g1/g1CollectorPolicy.hpp"
       
    30 #include "memory/resourceArea.hpp"
       
    31 #include "runtime/handles.inline.hpp"
       
    32 #include "runtime/mutexLocker.hpp"
       
    33 
       
    34 ConcurrentG1RefineThread::
       
    35 ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next,
       
    36                          CardTableEntryClosure* refine_closure,
       
    37                          uint worker_id_offset, uint worker_id) :
       
    38   ConcurrentGCThread(),
       
    39   _refine_closure(refine_closure),
       
    40   _worker_id_offset(worker_id_offset),
       
    41   _worker_id(worker_id),
       
    42   _active(false),
       
    43   _next(next),
       
    44   _monitor(NULL),
       
    45   _cg1r(cg1r),
       
    46   _vtime_accum(0.0)
       
    47 {
       
    48 
       
    49   // Each thread has its own monitor. The i-th thread is responsible for signaling
       
    50   // to thread i+1 if the number of buffers in the queue exceeds a threshold for this
       
    51   // thread. Monitors are also used to wake up the threads during termination.
       
    52   // The 0th worker in notified by mutator threads and has a special monitor.
       
    53   // The last worker is used for young gen rset size sampling.
       
    54   if (worker_id > 0) {
       
    55     _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true,
       
    56                            Monitor::_safepoint_check_never);
       
    57   } else {
       
    58     _monitor = DirtyCardQ_CBL_mon;
       
    59   }
       
    60   initialize();
       
    61   create_and_start();
       
    62 
       
    63   // set name
       
    64   set_name("G1 Refine#%d", worker_id);
       
    65 }
       
    66 
       
    67 void ConcurrentG1RefineThread::initialize() {
       
    68   if (_worker_id < cg1r()->worker_thread_num()) {
       
    69     // Current thread activation threshold
       
    70     _threshold = MIN2<int>(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(),
       
    71                            cg1r()->yellow_zone());
       
    72     // A thread deactivates once the number of buffer reached a deactivation threshold
       
    73     _deactivation_threshold = MAX2<int>(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone());
       
    74   } else {
       
    75     set_active(true);
       
    76   }
       
    77 }
       
    78 
       
    79 void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
       
    80   SuspendibleThreadSetJoiner sts_join;
       
    81   G1CollectedHeap* g1h = G1CollectedHeap::heap();
       
    82   G1CollectorPolicy* g1p = g1h->g1_policy();
       
    83   if (g1p->adaptive_young_list_length()) {
       
    84     int regions_visited = 0;
       
    85     g1h->young_list()->rs_length_sampling_init();
       
    86     while (g1h->young_list()->rs_length_sampling_more()) {
       
    87       g1h->young_list()->rs_length_sampling_next();
       
    88       ++regions_visited;
       
    89 
       
    90       // we try to yield every time we visit 10 regions
       
    91       if (regions_visited == 10) {
       
    92         if (sts_join.should_yield()) {
       
    93           sts_join.yield();
       
    94           // we just abandon the iteration
       
    95           break;
       
    96         }
       
    97         regions_visited = 0;
       
    98       }
       
    99     }
       
   100 
       
   101     g1p->revise_young_list_target_length_if_necessary();
       
   102   }
       
   103 }
       
   104 
       
   105 void ConcurrentG1RefineThread::run_young_rs_sampling() {
       
   106   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
       
   107   _vtime_start = os::elapsedVTime();
       
   108   while(!_should_terminate) {
       
   109     sample_young_list_rs_lengths();
       
   110 
       
   111     if (os::supports_vtime()) {
       
   112       _vtime_accum = (os::elapsedVTime() - _vtime_start);
       
   113     } else {
       
   114       _vtime_accum = 0.0;
       
   115     }
       
   116 
       
   117     MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
       
   118     if (_should_terminate) {
       
   119       break;
       
   120     }
       
   121     _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefinementServiceIntervalMillis);
       
   122   }
       
   123 }
       
   124 
       
   125 void ConcurrentG1RefineThread::wait_for_completed_buffers() {
       
   126   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
       
   127   MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
       
   128   while (!_should_terminate && !is_active()) {
       
   129     _monitor->wait(Mutex::_no_safepoint_check_flag);
       
   130   }
       
   131 }
       
   132 
       
   133 bool ConcurrentG1RefineThread::is_active() {
       
   134   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
       
   135   return _worker_id > 0 ? _active : dcqs.process_completed_buffers();
       
   136 }
       
   137 
       
   138 void ConcurrentG1RefineThread::activate() {
       
   139   MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
       
   140   if (_worker_id > 0) {
       
   141     if (G1TraceConcRefinement) {
       
   142       DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
       
   143       gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d",
       
   144                              _worker_id, _threshold, (int)dcqs.completed_buffers_num());
       
   145     }
       
   146     set_active(true);
       
   147   } else {
       
   148     DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
       
   149     dcqs.set_process_completed(true);
       
   150   }
       
   151   _monitor->notify();
       
   152 }
       
   153 
       
   154 void ConcurrentG1RefineThread::deactivate() {
       
   155   MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
       
   156   if (_worker_id > 0) {
       
   157     if (G1TraceConcRefinement) {
       
   158       DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
       
   159       gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d",
       
   160                              _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num());
       
   161     }
       
   162     set_active(false);
       
   163   } else {
       
   164     DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
       
   165     dcqs.set_process_completed(false);
       
   166   }
       
   167 }
       
   168 
       
   169 void ConcurrentG1RefineThread::run() {
       
   170   initialize_in_thread();
       
   171   wait_for_universe_init();
       
   172 
       
   173   if (_worker_id >= cg1r()->worker_thread_num()) {
       
   174     run_young_rs_sampling();
       
   175     terminate();
       
   176     return;
       
   177   }
       
   178 
       
   179   _vtime_start = os::elapsedVTime();
       
   180   while (!_should_terminate) {
       
   181     DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
       
   182 
       
   183     // Wait for work
       
   184     wait_for_completed_buffers();
       
   185 
       
   186     if (_should_terminate) {
       
   187       break;
       
   188     }
       
   189 
       
   190     {
       
   191       SuspendibleThreadSetJoiner sts_join;
       
   192 
       
   193       do {
       
   194         int curr_buffer_num = (int)dcqs.completed_buffers_num();
       
   195         // If the number of the buffers falls down into the yellow zone,
       
   196         // that means that the transition period after the evacuation pause has ended.
       
   197         if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) {
       
   198           dcqs.set_completed_queue_padding(0);
       
   199         }
       
   200 
       
   201         if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) {
       
   202           // If the number of the buffer has fallen below our threshold
       
   203           // we should deactivate. The predecessor will reactivate this
       
   204           // thread should the number of the buffers cross the threshold again.
       
   205           deactivate();
       
   206           break;
       
   207         }
       
   208 
       
   209         // Check if we need to activate the next thread.
       
   210         if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) {
       
   211           _next->activate();
       
   212         }
       
   213       } while (dcqs.apply_closure_to_completed_buffer(_refine_closure, _worker_id + _worker_id_offset, cg1r()->green_zone()));
       
   214 
       
   215       // We can exit the loop above while being active if there was a yield request.
       
   216       if (is_active()) {
       
   217         deactivate();
       
   218       }
       
   219     }
       
   220 
       
   221     if (os::supports_vtime()) {
       
   222       _vtime_accum = (os::elapsedVTime() - _vtime_start);
       
   223     } else {
       
   224       _vtime_accum = 0.0;
       
   225     }
       
   226   }
       
   227   assert(_should_terminate, "just checking");
       
   228   terminate();
       
   229 }
       
   230 
       
   231 void ConcurrentG1RefineThread::stop() {
       
   232   // it is ok to take late safepoints here, if needed
       
   233   {
       
   234     MutexLockerEx mu(Terminator_lock);
       
   235     _should_terminate = true;
       
   236   }
       
   237 
       
   238   {
       
   239     MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
       
   240     _monitor->notify();
       
   241   }
       
   242 
       
   243   {
       
   244     MutexLockerEx mu(Terminator_lock);
       
   245     while (!_has_terminated) {
       
   246       Terminator_lock->wait();
       
   247     }
       
   248   }
       
   249   if (G1TraceConcRefinement) {
       
   250     gclog_or_tty->print_cr("G1-Refine-stop");
       
   251   }
       
   252 }
       
   253