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

Mon, 02 Aug 2010 12:51:43 -0700

author
johnc
date
Mon, 02 Aug 2010 12:51:43 -0700
changeset 2060
2d160770d2e5
parent 1907
c18cbe5936b8
child 2314
f95d63e2154a
permissions
-rw-r--r--

6814437: G1: remove the _new_refs array
Summary: The per-worker _new_refs array is used to hold references that point into the collection set. It is populated during RSet updating and subsequently processed. In the event of an evacuation failure it processed again to recreate the RSets of regions in the collection set. Remove the per-worker _new_refs array by processing the references directly. Use a DirtyCardQueue to hold the cards containing the references so that the RSets of regions in the collection set can be recreated when handling an evacuation failure.
Reviewed-by: iveresov, jmasa, tonyp

     1 /*
     2  * Copyright (c) 2001, 2010, 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  */
    25 #include "incls/_precompiled.incl"
    26 #include "incls/_concurrentG1RefineThread.cpp.incl"
    28 ConcurrentG1RefineThread::
    29 ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next,
    30                          int worker_id_offset, int worker_id) :
    31   ConcurrentGCThread(),
    32   _worker_id_offset(worker_id_offset),
    33   _worker_id(worker_id),
    34   _active(false),
    35   _next(next),
    36   _monitor(NULL),
    37   _cg1r(cg1r),
    38   _vtime_accum(0.0)
    39 {
    41   // Each thread has its own monitor. The i-th thread is responsible for signalling
    42   // to thread i+1 if the number of buffers in the queue exceeds a threashold for this
    43   // thread. Monitors are also used to wake up the threads during termination.
    44   // The 0th worker in notified by mutator threads and has a special monitor.
    45   // The last worker is used for young gen rset size sampling.
    46   if (worker_id > 0) {
    47     _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true);
    48   } else {
    49     _monitor = DirtyCardQ_CBL_mon;
    50   }
    51   initialize();
    52   create_and_start();
    53 }
    55 void ConcurrentG1RefineThread::initialize() {
    56   if (_worker_id < cg1r()->worker_thread_num()) {
    57     // Current thread activation threshold
    58     _threshold = MIN2<int>(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(),
    59                            cg1r()->yellow_zone());
    60     // A thread deactivates once the number of buffer reached a deactivation threshold
    61     _deactivation_threshold = MAX2<int>(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone());
    62   } else {
    63     set_active(true);
    64   }
    65 }
    67 void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
    68   G1CollectedHeap* g1h = G1CollectedHeap::heap();
    69   G1CollectorPolicy* g1p = g1h->g1_policy();
    70   if (g1p->adaptive_young_list_length()) {
    71     int regions_visited = 0;
    72     g1h->young_list()->rs_length_sampling_init();
    73     while (g1h->young_list()->rs_length_sampling_more()) {
    74       g1h->young_list()->rs_length_sampling_next();
    75       ++regions_visited;
    77       // we try to yield every time we visit 10 regions
    78       if (regions_visited == 10) {
    79         if (_sts.should_yield()) {
    80           _sts.yield("G1 refine");
    81           // we just abandon the iteration
    82           break;
    83         }
    84         regions_visited = 0;
    85       }
    86     }
    88     g1p->check_prediction_validity();
    89   }
    90 }
    92 void ConcurrentG1RefineThread::run_young_rs_sampling() {
    93   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
    94   _vtime_start = os::elapsedVTime();
    95   while(!_should_terminate) {
    96     _sts.join();
    97     sample_young_list_rs_lengths();
    98     _sts.leave();
   100     if (os::supports_vtime()) {
   101       _vtime_accum = (os::elapsedVTime() - _vtime_start);
   102     } else {
   103       _vtime_accum = 0.0;
   104     }
   106     MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   107     if (_should_terminate) {
   108       break;
   109     }
   110     _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefinementServiceIntervalMillis);
   111   }
   112 }
   114 void ConcurrentG1RefineThread::wait_for_completed_buffers() {
   115   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   116   MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   117   while (!_should_terminate && !is_active()) {
   118     _monitor->wait(Mutex::_no_safepoint_check_flag);
   119   }
   120 }
   122 bool ConcurrentG1RefineThread::is_active() {
   123   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   124   return _worker_id > 0 ? _active : dcqs.process_completed_buffers();
   125 }
   127 void ConcurrentG1RefineThread::activate() {
   128   MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   129   if (_worker_id > 0) {
   130     if (G1TraceConcRefinement) {
   131       DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   132       gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d",
   133                              _worker_id, _threshold, (int)dcqs.completed_buffers_num());
   134     }
   135     set_active(true);
   136   } else {
   137     DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   138     dcqs.set_process_completed(true);
   139   }
   140   _monitor->notify();
   141 }
   143 void ConcurrentG1RefineThread::deactivate() {
   144   MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   145   if (_worker_id > 0) {
   146     if (G1TraceConcRefinement) {
   147       DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   148       gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d",
   149                              _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num());
   150     }
   151     set_active(false);
   152   } else {
   153     DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   154     dcqs.set_process_completed(false);
   155   }
   156 }
   158 void ConcurrentG1RefineThread::run() {
   159   initialize_in_thread();
   160   wait_for_universe_init();
   162   if (_worker_id >= cg1r()->worker_thread_num()) {
   163     run_young_rs_sampling();
   164     terminate();
   165     return;
   166   }
   168   _vtime_start = os::elapsedVTime();
   169   while (!_should_terminate) {
   170     DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   172     // Wait for work
   173     wait_for_completed_buffers();
   175     if (_should_terminate) {
   176       break;
   177     }
   179     _sts.join();
   181     do {
   182       int curr_buffer_num = (int)dcqs.completed_buffers_num();
   183       // If the number of the buffers falls down into the yellow zone,
   184       // that means that the transition period after the evacuation pause has ended.
   185       if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) {
   186         dcqs.set_completed_queue_padding(0);
   187       }
   189       if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) {
   190         // If the number of the buffer has fallen below our threshold
   191         // we should deactivate. The predecessor will reactivate this
   192         // thread should the number of the buffers cross the threshold again.
   193         deactivate();
   194         break;
   195       }
   197       // Check if we need to activate the next thread.
   198       if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) {
   199         _next->activate();
   200       }
   201     } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone()));
   203     // We can exit the loop above while being active if there was a yield request.
   204     if (is_active()) {
   205       deactivate();
   206     }
   208     _sts.leave();
   210     if (os::supports_vtime()) {
   211       _vtime_accum = (os::elapsedVTime() - _vtime_start);
   212     } else {
   213       _vtime_accum = 0.0;
   214     }
   215   }
   216   assert(_should_terminate, "just checking");
   217   terminate();
   218 }
   221 void ConcurrentG1RefineThread::yield() {
   222   if (G1TraceConcRefinement) {
   223     gclog_or_tty->print_cr("G1-Refine-yield");
   224   }
   225   _sts.yield("G1 refine");
   226   if (G1TraceConcRefinement) {
   227     gclog_or_tty->print_cr("G1-Refine-yield-end");
   228   }
   229 }
   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   }
   238   {
   239     MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   240     _monitor->notify();
   241   }
   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 }
   254 void ConcurrentG1RefineThread::print() const {
   255   print_on(tty);
   256 }
   258 void ConcurrentG1RefineThread::print_on(outputStream* st) const {
   259   st->print("\"G1 Concurrent Refinement Thread#%d\" ", _worker_id);
   260   Thread::print_on(st);
   261   st->cr();
   262 }

mercurial