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

Mon, 03 Aug 2009 12:59:30 -0700

author
johnc
date
Mon, 03 Aug 2009 12:59:30 -0700
changeset 1324
15c5903cf9e1
parent 1279
bd02caa94611
child 1371
e1fdf4fd34dc
permissions
-rw-r--r--

6865703: G1: Parallelize hot card cache cleanup
Summary: Have the GC worker threads clear the hot card cache in parallel by having each worker thread claim a chunk of the card cache and process the cards in that chunk. The size of the chunks that each thread will claim is determined at VM initialization from the size of the card cache and the number of worker threads.
Reviewed-by: jmasa, tonyp

     1 /*
     2  * Copyright 2001-2009 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/_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       _sts.join();
   264       _cm->disable_co_trackers();
   265       _sts.leave();
   267       // we now want to allow clearing of the marking bitmap to be
   268       // suspended by a collection pause.
   269       _sts.join();
   270       _cm->clearNextBitmap();
   271       _sts.leave();
   272     }
   273   }
   274   assert(_should_terminate, "just checking");
   276   terminate();
   277 }
   280 void ConcurrentMarkThread::yield() {
   281   _sts.yield("Concurrent Mark");
   282 }
   284 void ConcurrentMarkThread::stop() {
   285   // it is ok to take late safepoints here, if needed
   286   MutexLockerEx mu(Terminator_lock);
   287   _should_terminate = true;
   288   while (!_has_terminated) {
   289     Terminator_lock->wait();
   290   }
   291 }
   293 void ConcurrentMarkThread::print() {
   294   gclog_or_tty->print("\"Concurrent Mark GC Thread\" ");
   295   Thread::print();
   296   gclog_or_tty->cr();
   297 }
   299 void ConcurrentMarkThread::sleepBeforeNextCycle() {
   300   clear_in_progress();
   301   // We join here because we don't want to do the "shouldConcurrentMark()"
   302   // below while the world is otherwise stopped.
   303   MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
   304   while (!started()) {
   305     CGC_lock->wait(Mutex::_no_safepoint_check_flag);
   306   }
   307   set_in_progress();
   308   clear_started();
   309 }
   311 // Note: this method, although exported by the ConcurrentMarkSweepThread,
   312 // which is a non-JavaThread, can only be called by a JavaThread.
   313 // Currently this is done at vm creation time (post-vm-init) by the
   314 // main/Primordial (Java)Thread.
   315 // XXX Consider changing this in the future to allow the CMS thread
   316 // itself to create this thread?
   317 void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) {
   318   assert(_slt == NULL, "SLT already created");
   319   _slt = SurrogateLockerThread::make(THREAD);
   320 }

mercurial