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

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

author
johnc
date
Mon, 02 Aug 2010 12:51:43 -0700
changeset 2060
2d160770d2e5
parent 2011
4e5661ba9d98
child 2195
4e0094bc41fa
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, 2009, 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/_concurrentMarkThread.cpp.incl"
    28 // ======= Concurrent Mark Thread ========
    30 // The CM thread is created when the G1 garbage collector is used
    32 SurrogateLockerThread*
    33      ConcurrentMarkThread::_slt = NULL;
    35 ConcurrentMarkThread::ConcurrentMarkThread(ConcurrentMark* cm) :
    36   ConcurrentGCThread(),
    37   _cm(cm),
    38   _started(false),
    39   _in_progress(false),
    40   _vtime_accum(0.0),
    41   _vtime_mark_accum(0.0),
    42   _vtime_count_accum(0.0)
    43 {
    44   create_and_start();
    45 }
    47 class CMCheckpointRootsInitialClosure: public VoidClosure {
    49   ConcurrentMark* _cm;
    50 public:
    52   CMCheckpointRootsInitialClosure(ConcurrentMark* cm) :
    53     _cm(cm) {}
    55   void do_void(){
    56     _cm->checkpointRootsInitial();
    57   }
    58 };
    60 class CMCheckpointRootsFinalClosure: public VoidClosure {
    62   ConcurrentMark* _cm;
    63 public:
    65   CMCheckpointRootsFinalClosure(ConcurrentMark* cm) :
    66     _cm(cm) {}
    68   void do_void(){
    69     _cm->checkpointRootsFinal(false); // !clear_all_soft_refs
    70   }
    71 };
    73 class CMCleanUp: public VoidClosure {
    74   ConcurrentMark* _cm;
    75 public:
    77   CMCleanUp(ConcurrentMark* cm) :
    78     _cm(cm) {}
    80   void do_void(){
    81     _cm->cleanup();
    82   }
    83 };
    87 void ConcurrentMarkThread::run() {
    88   initialize_in_thread();
    89   _vtime_start = os::elapsedVTime();
    90   wait_for_universe_init();
    92   G1CollectedHeap* g1 = G1CollectedHeap::heap();
    93   G1CollectorPolicy* g1_policy = g1->g1_policy();
    94   G1MMUTracker *mmu_tracker = g1_policy->mmu_tracker();
    95   Thread *current_thread = Thread::current();
    97   while (!_should_terminate) {
    98     // wait until started is set.
    99     sleepBeforeNextCycle();
   100     {
   101       ResourceMark rm;
   102       HandleMark   hm;
   103       double cycle_start = os::elapsedVTime();
   104       double mark_start_sec = os::elapsedTime();
   105       char verbose_str[128];
   107       if (PrintGC) {
   108         gclog_or_tty->date_stamp(PrintGCDateStamps);
   109         gclog_or_tty->stamp(PrintGCTimeStamps);
   110         gclog_or_tty->print_cr("[GC concurrent-mark-start]");
   111       }
   113       if (!g1_policy->in_young_gc_mode()) {
   114         // this ensures the flag is not set if we bail out of the marking
   115         // cycle; normally the flag is cleared immediately after cleanup
   116         g1->set_marking_complete();
   118         if (g1_policy->adaptive_young_list_length()) {
   119           double now = os::elapsedTime();
   120           double init_prediction_ms = g1_policy->predict_init_time_ms();
   121           jlong sleep_time_ms = mmu_tracker->when_ms(now, init_prediction_ms);
   122           os::sleep(current_thread, sleep_time_ms, false);
   123         }
   125         // We don't have to skip here if we've been asked to restart, because
   126         // in the worst case we just enqueue a new VM operation to start a
   127         // marking.  Note that the init operation resets has_aborted()
   128         CMCheckpointRootsInitialClosure init_cl(_cm);
   129         strcpy(verbose_str, "GC initial-mark");
   130         VM_CGC_Operation op(&init_cl, verbose_str);
   131         VMThread::execute(&op);
   132       }
   134       int iter = 0;
   135       do {
   136         iter++;
   137         if (!cm()->has_aborted()) {
   138           _cm->markFromRoots();
   139         }
   141         double mark_end_time = os::elapsedVTime();
   142         double mark_end_sec = os::elapsedTime();
   143         _vtime_mark_accum += (mark_end_time - cycle_start);
   144         if (!cm()->has_aborted()) {
   145           if (g1_policy->adaptive_young_list_length()) {
   146             double now = os::elapsedTime();
   147             double remark_prediction_ms = g1_policy->predict_remark_time_ms();
   148             jlong sleep_time_ms = mmu_tracker->when_ms(now, remark_prediction_ms);
   149             os::sleep(current_thread, sleep_time_ms, false);
   150           }
   152           if (PrintGC) {
   153             gclog_or_tty->date_stamp(PrintGCDateStamps);
   154             gclog_or_tty->stamp(PrintGCTimeStamps);
   155             gclog_or_tty->print_cr("[GC concurrent-mark-end, %1.7lf sec]",
   156                                       mark_end_sec - mark_start_sec);
   157           }
   159           CMCheckpointRootsFinalClosure final_cl(_cm);
   160           sprintf(verbose_str, "GC remark");
   161           VM_CGC_Operation op(&final_cl, verbose_str);
   162           VMThread::execute(&op);
   163         }
   164         if (cm()->restart_for_overflow() &&
   165             G1TraceMarkStackOverflow) {
   166           gclog_or_tty->print_cr("Restarting conc marking because of MS overflow "
   167                                  "in remark (restart #%d).", iter);
   168         }
   170         if (cm()->restart_for_overflow()) {
   171           if (PrintGC) {
   172             gclog_or_tty->date_stamp(PrintGCDateStamps);
   173             gclog_or_tty->stamp(PrintGCTimeStamps);
   174             gclog_or_tty->print_cr("[GC concurrent-mark-restart-for-overflow]");
   175           }
   176         }
   177       } while (cm()->restart_for_overflow());
   178       double counting_start_time = os::elapsedVTime();
   180       // YSR: These look dubious (i.e. redundant) !!! FIX ME
   181       slt()->manipulatePLL(SurrogateLockerThread::acquirePLL);
   182       slt()->manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL);
   184       if (!cm()->has_aborted()) {
   185         double count_start_sec = os::elapsedTime();
   186         if (PrintGC) {
   187           gclog_or_tty->date_stamp(PrintGCDateStamps);
   188           gclog_or_tty->stamp(PrintGCTimeStamps);
   189           gclog_or_tty->print_cr("[GC concurrent-count-start]");
   190         }
   192         _sts.join();
   193         _cm->calcDesiredRegions();
   194         _sts.leave();
   196         if (!cm()->has_aborted()) {
   197           double count_end_sec = os::elapsedTime();
   198           if (PrintGC) {
   199             gclog_or_tty->date_stamp(PrintGCDateStamps);
   200             gclog_or_tty->stamp(PrintGCTimeStamps);
   201             gclog_or_tty->print_cr("[GC concurrent-count-end, %1.7lf]",
   202                                    count_end_sec - count_start_sec);
   203           }
   204         }
   205       }
   206       double end_time = os::elapsedVTime();
   207       _vtime_count_accum += (end_time - counting_start_time);
   208       // Update the total virtual time before doing this, since it will try
   209       // to measure it to get the vtime for this marking.  We purposely
   210       // neglect the presumably-short "completeCleanup" phase here.
   211       _vtime_accum = (end_time - _vtime_start);
   212       if (!cm()->has_aborted()) {
   213         if (g1_policy->adaptive_young_list_length()) {
   214           double now = os::elapsedTime();
   215           double cleanup_prediction_ms = g1_policy->predict_cleanup_time_ms();
   216           jlong sleep_time_ms = mmu_tracker->when_ms(now, cleanup_prediction_ms);
   217           os::sleep(current_thread, sleep_time_ms, false);
   218         }
   220         CMCleanUp cl_cl(_cm);
   221         sprintf(verbose_str, "GC cleanup");
   222         VM_CGC_Operation op(&cl_cl, verbose_str);
   223         VMThread::execute(&op);
   224       } else {
   225         G1CollectedHeap::heap()->set_marking_complete();
   226       }
   228       if (!cm()->has_aborted()) {
   229         double cleanup_start_sec = os::elapsedTime();
   230         if (PrintGC) {
   231           gclog_or_tty->date_stamp(PrintGCDateStamps);
   232           gclog_or_tty->stamp(PrintGCTimeStamps);
   233           gclog_or_tty->print_cr("[GC concurrent-cleanup-start]");
   234         }
   236         // Now do the remainder of the cleanup operation.
   237         _sts.join();
   238         _cm->completeCleanup();
   239         if (!cm()->has_aborted()) {
   240           g1_policy->record_concurrent_mark_cleanup_completed();
   242           double cleanup_end_sec = os::elapsedTime();
   243           if (PrintGC) {
   244             gclog_or_tty->date_stamp(PrintGCDateStamps);
   245             gclog_or_tty->stamp(PrintGCTimeStamps);
   246             gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf]",
   247                                    cleanup_end_sec - cleanup_start_sec);
   248           }
   249         }
   250         _sts.leave();
   251       }
   252       // We're done: no more unclean regions coming.
   253       G1CollectedHeap::heap()->set_unclean_regions_coming(false);
   255       if (cm()->has_aborted()) {
   256         if (PrintGC) {
   257           gclog_or_tty->date_stamp(PrintGCDateStamps);
   258           gclog_or_tty->stamp(PrintGCTimeStamps);
   259           gclog_or_tty->print_cr("[GC concurrent-mark-abort]");
   260         }
   261       }
   263       // we now want to allow clearing of the marking bitmap to be
   264       // suspended by a collection pause.
   265       _sts.join();
   266       _cm->clearNextBitmap();
   267       _sts.leave();
   268     }
   270     // Update the number of full collections that have been
   271     // completed. This will also notify the FullGCCount_lock in case a
   272     // Java thread is waiting for a full GC to happen (e.g., it
   273     // called System.gc() with +ExplicitGCInvokesConcurrent).
   274     g1->increment_full_collections_completed(true /* outer */);
   275   }
   276   assert(_should_terminate, "just checking");
   278   terminate();
   279 }
   282 void ConcurrentMarkThread::yield() {
   283   _sts.yield("Concurrent Mark");
   284 }
   286 void ConcurrentMarkThread::stop() {
   287   // it is ok to take late safepoints here, if needed
   288   MutexLockerEx mu(Terminator_lock);
   289   _should_terminate = true;
   290   while (!_has_terminated) {
   291     Terminator_lock->wait();
   292   }
   293 }
   295 void ConcurrentMarkThread::print() const {
   296   print_on(tty);
   297 }
   299 void ConcurrentMarkThread::print_on(outputStream* st) const {
   300   st->print("\"G1 Main Concurrent Mark GC Thread\" ");
   301   Thread::print_on(st);
   302   st->cr();
   303 }
   305 void ConcurrentMarkThread::sleepBeforeNextCycle() {
   306   clear_in_progress();
   307   // We join here because we don't want to do the "shouldConcurrentMark()"
   308   // below while the world is otherwise stopped.
   309   MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
   310   while (!started()) {
   311     CGC_lock->wait(Mutex::_no_safepoint_check_flag);
   312   }
   313   set_in_progress();
   314   clear_started();
   315 }
   317 // Note: this method, although exported by the ConcurrentMarkSweepThread,
   318 // which is a non-JavaThread, can only be called by a JavaThread.
   319 // Currently this is done at vm creation time (post-vm-init) by the
   320 // main/Primordial (Java)Thread.
   321 // XXX Consider changing this in the future to allow the CMS thread
   322 // itself to create this thread?
   323 void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) {
   324   assert(_slt == NULL, "SLT already created");
   325   _slt = SurrogateLockerThread::make(THREAD);
   326 }

mercurial