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

Thu, 22 Apr 2010 10:02:38 -0700

author
johnc
date
Thu, 22 Apr 2010 10:02:38 -0700
changeset 1829
1316cec51b4d
parent 1717
b81f3572f355
child 1907
c18cbe5936b8
permissions
-rw-r--r--

6819061: G1: eliminate serial Other times that are proportional to the collection set length
6871109: G1: remove the concept of the scan only prefix
Summary: Removed scan only regions and associated code. The young portion of the collection set is now constructed incrementally - when a young region is retired as the current allocation region it is added to the collection set.
Reviewed-by: apetrusenko, iveresov, tonyp

     1 /*
     2  * Copyright 2001-2010 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
    21  * have any 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