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

Tue, 21 Aug 2012 14:10:39 -0700

author
johnc
date
Tue, 21 Aug 2012 14:10:39 -0700
changeset 3998
7383557659bd
parent 3119
4f41766176cf
child 6552
8847586c9037
permissions
-rw-r--r--

7185699: G1: Prediction model discrepancies
Summary: Correct the result value of G1CollectedHeap::pending_card_num(). Change the code that calculates the GC efficiency of a non-young heap region to use historical data from mixed GCs and the actual number of live bytes when predicting how long it would take to collect the region. Changes were also reviewed by Thomas Schatzl.
Reviewed-by: azeemj, brutisso

     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 "precompiled.hpp"
    26 #include "gc_implementation/g1/concurrentG1Refine.hpp"
    27 #include "gc_implementation/g1/concurrentG1RefineThread.hpp"
    28 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
    29 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
    30 #include "memory/resourceArea.hpp"
    31 #include "runtime/handles.inline.hpp"
    32 #include "runtime/mutexLocker.hpp"
    34 ConcurrentG1RefineThread::
    35 ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next,
    36                          int worker_id_offset, int worker_id) :
    37   ConcurrentGCThread(),
    38   _worker_id_offset(worker_id_offset),
    39   _worker_id(worker_id),
    40   _active(false),
    41   _next(next),
    42   _monitor(NULL),
    43   _cg1r(cg1r),
    44   _vtime_accum(0.0)
    45 {
    47   // Each thread has its own monitor. The i-th thread is responsible for signalling
    48   // to thread i+1 if the number of buffers in the queue exceeds a threashold for this
    49   // thread. Monitors are also used to wake up the threads during termination.
    50   // The 0th worker in notified by mutator threads and has a special monitor.
    51   // The last worker is used for young gen rset size sampling.
    52   if (worker_id > 0) {
    53     _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true);
    54   } else {
    55     _monitor = DirtyCardQ_CBL_mon;
    56   }
    57   initialize();
    58   create_and_start();
    59 }
    61 void ConcurrentG1RefineThread::initialize() {
    62   if (_worker_id < cg1r()->worker_thread_num()) {
    63     // Current thread activation threshold
    64     _threshold = MIN2<int>(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(),
    65                            cg1r()->yellow_zone());
    66     // A thread deactivates once the number of buffer reached a deactivation threshold
    67     _deactivation_threshold = MAX2<int>(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone());
    68   } else {
    69     set_active(true);
    70   }
    71 }
    73 void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
    74   G1CollectedHeap* g1h = G1CollectedHeap::heap();
    75   G1CollectorPolicy* g1p = g1h->g1_policy();
    76   if (g1p->adaptive_young_list_length()) {
    77     int regions_visited = 0;
    78     g1h->young_list()->rs_length_sampling_init();
    79     while (g1h->young_list()->rs_length_sampling_more()) {
    80       g1h->young_list()->rs_length_sampling_next();
    81       ++regions_visited;
    83       // we try to yield every time we visit 10 regions
    84       if (regions_visited == 10) {
    85         if (_sts.should_yield()) {
    86           _sts.yield("G1 refine");
    87           // we just abandon the iteration
    88           break;
    89         }
    90         regions_visited = 0;
    91       }
    92     }
    94     g1p->revise_young_list_target_length_if_necessary();
    95   }
    96 }
    98 void ConcurrentG1RefineThread::run_young_rs_sampling() {
    99   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   100   _vtime_start = os::elapsedVTime();
   101   while(!_should_terminate) {
   102     _sts.join();
   103     sample_young_list_rs_lengths();
   104     _sts.leave();
   106     if (os::supports_vtime()) {
   107       _vtime_accum = (os::elapsedVTime() - _vtime_start);
   108     } else {
   109       _vtime_accum = 0.0;
   110     }
   112     MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   113     if (_should_terminate) {
   114       break;
   115     }
   116     _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefinementServiceIntervalMillis);
   117   }
   118 }
   120 void ConcurrentG1RefineThread::wait_for_completed_buffers() {
   121   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   122   MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   123   while (!_should_terminate && !is_active()) {
   124     _monitor->wait(Mutex::_no_safepoint_check_flag);
   125   }
   126 }
   128 bool ConcurrentG1RefineThread::is_active() {
   129   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   130   return _worker_id > 0 ? _active : dcqs.process_completed_buffers();
   131 }
   133 void ConcurrentG1RefineThread::activate() {
   134   MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   135   if (_worker_id > 0) {
   136     if (G1TraceConcRefinement) {
   137       DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   138       gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d",
   139                              _worker_id, _threshold, (int)dcqs.completed_buffers_num());
   140     }
   141     set_active(true);
   142   } else {
   143     DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   144     dcqs.set_process_completed(true);
   145   }
   146   _monitor->notify();
   147 }
   149 void ConcurrentG1RefineThread::deactivate() {
   150   MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   151   if (_worker_id > 0) {
   152     if (G1TraceConcRefinement) {
   153       DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   154       gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d",
   155                              _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num());
   156     }
   157     set_active(false);
   158   } else {
   159     DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   160     dcqs.set_process_completed(false);
   161   }
   162 }
   164 void ConcurrentG1RefineThread::run() {
   165   initialize_in_thread();
   166   wait_for_universe_init();
   168   if (_worker_id >= cg1r()->worker_thread_num()) {
   169     run_young_rs_sampling();
   170     terminate();
   171     return;
   172   }
   174   _vtime_start = os::elapsedVTime();
   175   while (!_should_terminate) {
   176     DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   178     // Wait for work
   179     wait_for_completed_buffers();
   181     if (_should_terminate) {
   182       break;
   183     }
   185     _sts.join();
   187     do {
   188       int curr_buffer_num = (int)dcqs.completed_buffers_num();
   189       // If the number of the buffers falls down into the yellow zone,
   190       // that means that the transition period after the evacuation pause has ended.
   191       if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) {
   192         dcqs.set_completed_queue_padding(0);
   193       }
   195       if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) {
   196         // If the number of the buffer has fallen below our threshold
   197         // we should deactivate. The predecessor will reactivate this
   198         // thread should the number of the buffers cross the threshold again.
   199         deactivate();
   200         break;
   201       }
   203       // Check if we need to activate the next thread.
   204       if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) {
   205         _next->activate();
   206       }
   207     } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone()));
   209     // We can exit the loop above while being active if there was a yield request.
   210     if (is_active()) {
   211       deactivate();
   212     }
   214     _sts.leave();
   216     if (os::supports_vtime()) {
   217       _vtime_accum = (os::elapsedVTime() - _vtime_start);
   218     } else {
   219       _vtime_accum = 0.0;
   220     }
   221   }
   222   assert(_should_terminate, "just checking");
   223   terminate();
   224 }
   227 void ConcurrentG1RefineThread::yield() {
   228   if (G1TraceConcRefinement) {
   229     gclog_or_tty->print_cr("G1-Refine-yield");
   230   }
   231   _sts.yield("G1 refine");
   232   if (G1TraceConcRefinement) {
   233     gclog_or_tty->print_cr("G1-Refine-yield-end");
   234   }
   235 }
   237 void ConcurrentG1RefineThread::stop() {
   238   // it is ok to take late safepoints here, if needed
   239   {
   240     MutexLockerEx mu(Terminator_lock);
   241     _should_terminate = true;
   242   }
   244   {
   245     MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
   246     _monitor->notify();
   247   }
   249   {
   250     MutexLockerEx mu(Terminator_lock);
   251     while (!_has_terminated) {
   252       Terminator_lock->wait();
   253     }
   254   }
   255   if (G1TraceConcRefinement) {
   256     gclog_or_tty->print_cr("G1-Refine-stop");
   257   }
   258 }
   260 void ConcurrentG1RefineThread::print() const {
   261   print_on(tty);
   262 }
   264 void ConcurrentG1RefineThread::print_on(outputStream* st) const {
   265   st->print("\"G1 Concurrent Refinement Thread#%d\" ", _worker_id);
   266   Thread::print_on(st);
   267   st->cr();
   268 }

mercurial