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

ysr@777 1 /*
xdono@1279 2 * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
ysr@777 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ysr@777 4 *
ysr@777 5 * This code is free software; you can redistribute it and/or modify it
ysr@777 6 * under the terms of the GNU General Public License version 2 only, as
ysr@777 7 * published by the Free Software Foundation.
ysr@777 8 *
ysr@777 9 * This code is distributed in the hope that it will be useful, but WITHOUT
ysr@777 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ysr@777 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ysr@777 12 * version 2 for more details (a copy is included in the LICENSE file that
ysr@777 13 * accompanied this code).
ysr@777 14 *
ysr@777 15 * You should have received a copy of the GNU General Public License version
ysr@777 16 * 2 along with this work; if not, write to the Free Software Foundation,
ysr@777 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ysr@777 18 *
ysr@777 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
ysr@777 20 * CA 95054 USA or visit www.sun.com if you need additional information or
ysr@777 21 * have any questions.
ysr@777 22 *
ysr@777 23 */
ysr@777 24
ysr@777 25 #include "incls/_precompiled.incl"
ysr@777 26 #include "incls/_concurrentMarkThread.cpp.incl"
ysr@777 27
ysr@777 28 // ======= Concurrent Mark Thread ========
ysr@777 29
ysr@777 30 // The CM thread is created when the G1 garbage collector is used
ysr@777 31
ysr@777 32 SurrogateLockerThread*
ysr@777 33 ConcurrentMarkThread::_slt = NULL;
ysr@777 34
ysr@777 35 ConcurrentMarkThread::ConcurrentMarkThread(ConcurrentMark* cm) :
ysr@777 36 ConcurrentGCThread(),
ysr@777 37 _cm(cm),
ysr@777 38 _started(false),
ysr@777 39 _in_progress(false),
ysr@777 40 _vtime_accum(0.0),
ysr@777 41 _vtime_mark_accum(0.0),
ysr@777 42 _vtime_count_accum(0.0)
ysr@777 43 {
ysr@777 44 create_and_start();
ysr@777 45 }
ysr@777 46
ysr@777 47 class CMCheckpointRootsInitialClosure: public VoidClosure {
ysr@777 48
ysr@777 49 ConcurrentMark* _cm;
ysr@777 50 public:
ysr@777 51
ysr@777 52 CMCheckpointRootsInitialClosure(ConcurrentMark* cm) :
ysr@777 53 _cm(cm) {}
ysr@777 54
ysr@777 55 void do_void(){
ysr@777 56 _cm->checkpointRootsInitial();
ysr@777 57 }
ysr@777 58 };
ysr@777 59
ysr@777 60 class CMCheckpointRootsFinalClosure: public VoidClosure {
ysr@777 61
ysr@777 62 ConcurrentMark* _cm;
ysr@777 63 public:
ysr@777 64
ysr@777 65 CMCheckpointRootsFinalClosure(ConcurrentMark* cm) :
ysr@777 66 _cm(cm) {}
ysr@777 67
ysr@777 68 void do_void(){
ysr@777 69 _cm->checkpointRootsFinal(false); // !clear_all_soft_refs
ysr@777 70 }
ysr@777 71 };
ysr@777 72
ysr@777 73 class CMCleanUp: public VoidClosure {
ysr@777 74 ConcurrentMark* _cm;
ysr@777 75 public:
ysr@777 76
ysr@777 77 CMCleanUp(ConcurrentMark* cm) :
ysr@777 78 _cm(cm) {}
ysr@777 79
ysr@777 80 void do_void(){
ysr@777 81 _cm->cleanup();
ysr@777 82 }
ysr@777 83 };
ysr@777 84
ysr@777 85
ysr@777 86
ysr@777 87 void ConcurrentMarkThread::run() {
ysr@777 88 initialize_in_thread();
ysr@777 89 _vtime_start = os::elapsedVTime();
ysr@777 90 wait_for_universe_init();
ysr@777 91
ysr@777 92 G1CollectedHeap* g1 = G1CollectedHeap::heap();
ysr@777 93 G1CollectorPolicy* g1_policy = g1->g1_policy();
ysr@777 94 G1MMUTracker *mmu_tracker = g1_policy->mmu_tracker();
ysr@777 95 Thread *current_thread = Thread::current();
ysr@777 96
ysr@777 97 while (!_should_terminate) {
ysr@777 98 // wait until started is set.
ysr@777 99 sleepBeforeNextCycle();
ysr@777 100 {
ysr@777 101 ResourceMark rm;
ysr@777 102 HandleMark hm;
ysr@777 103 double cycle_start = os::elapsedVTime();
ysr@777 104 double mark_start_sec = os::elapsedTime();
ysr@777 105 char verbose_str[128];
ysr@777 106
ysr@777 107 if (PrintGC) {
ysr@777 108 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 109 gclog_or_tty->stamp(PrintGCTimeStamps);
tonyp@1054 110 gclog_or_tty->print_cr("[GC concurrent-mark-start]");
ysr@777 111 }
ysr@777 112
ysr@777 113 if (!g1_policy->in_young_gc_mode()) {
ysr@777 114 // this ensures the flag is not set if we bail out of the marking
ysr@777 115 // cycle; normally the flag is cleared immediately after cleanup
ysr@777 116 g1->set_marking_complete();
ysr@777 117
ysr@777 118 if (g1_policy->adaptive_young_list_length()) {
ysr@777 119 double now = os::elapsedTime();
ysr@777 120 double init_prediction_ms = g1_policy->predict_init_time_ms();
ysr@777 121 jlong sleep_time_ms = mmu_tracker->when_ms(now, init_prediction_ms);
ysr@777 122 os::sleep(current_thread, sleep_time_ms, false);
ysr@777 123 }
ysr@777 124
ysr@777 125 // We don't have to skip here if we've been asked to restart, because
ysr@777 126 // in the worst case we just enqueue a new VM operation to start a
ysr@777 127 // marking. Note that the init operation resets has_aborted()
ysr@777 128 CMCheckpointRootsInitialClosure init_cl(_cm);
ysr@777 129 strcpy(verbose_str, "GC initial-mark");
ysr@777 130 VM_CGC_Operation op(&init_cl, verbose_str);
ysr@777 131 VMThread::execute(&op);
ysr@777 132 }
ysr@777 133
ysr@777 134 int iter = 0;
ysr@777 135 do {
ysr@777 136 iter++;
ysr@777 137 if (!cm()->has_aborted()) {
ysr@777 138 _cm->markFromRoots();
ysr@777 139 }
ysr@777 140
ysr@777 141 double mark_end_time = os::elapsedVTime();
ysr@777 142 double mark_end_sec = os::elapsedTime();
ysr@777 143 _vtime_mark_accum += (mark_end_time - cycle_start);
ysr@777 144 if (!cm()->has_aborted()) {
ysr@777 145 if (g1_policy->adaptive_young_list_length()) {
ysr@777 146 double now = os::elapsedTime();
ysr@777 147 double remark_prediction_ms = g1_policy->predict_remark_time_ms();
ysr@777 148 jlong sleep_time_ms = mmu_tracker->when_ms(now, remark_prediction_ms);
ysr@777 149 os::sleep(current_thread, sleep_time_ms, false);
ysr@777 150 }
ysr@777 151
ysr@777 152 if (PrintGC) {
ysr@777 153 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 154 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 155 gclog_or_tty->print_cr("[GC concurrent-mark-end, %1.7lf sec]",
ysr@777 156 mark_end_sec - mark_start_sec);
ysr@777 157 }
ysr@777 158
ysr@777 159 CMCheckpointRootsFinalClosure final_cl(_cm);
ysr@777 160 sprintf(verbose_str, "GC remark");
ysr@777 161 VM_CGC_Operation op(&final_cl, verbose_str);
ysr@777 162 VMThread::execute(&op);
ysr@777 163 }
ysr@777 164 if (cm()->restart_for_overflow() &&
ysr@777 165 G1TraceMarkStackOverflow) {
ysr@777 166 gclog_or_tty->print_cr("Restarting conc marking because of MS overflow "
ysr@777 167 "in remark (restart #%d).", iter);
ysr@777 168 }
ysr@777 169
ysr@777 170 if (cm()->restart_for_overflow()) {
ysr@777 171 if (PrintGC) {
ysr@777 172 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 173 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 174 gclog_or_tty->print_cr("[GC concurrent-mark-restart-for-overflow]");
ysr@777 175 }
ysr@777 176 }
ysr@777 177 } while (cm()->restart_for_overflow());
ysr@777 178 double counting_start_time = os::elapsedVTime();
ysr@777 179
ysr@777 180 // YSR: These look dubious (i.e. redundant) !!! FIX ME
ysr@777 181 slt()->manipulatePLL(SurrogateLockerThread::acquirePLL);
ysr@777 182 slt()->manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL);
ysr@777 183
ysr@777 184 if (!cm()->has_aborted()) {
ysr@777 185 double count_start_sec = os::elapsedTime();
ysr@777 186 if (PrintGC) {
ysr@777 187 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 188 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 189 gclog_or_tty->print_cr("[GC concurrent-count-start]");
ysr@777 190 }
ysr@777 191
ysr@777 192 _sts.join();
ysr@777 193 _cm->calcDesiredRegions();
ysr@777 194 _sts.leave();
ysr@777 195
ysr@777 196 if (!cm()->has_aborted()) {
ysr@777 197 double count_end_sec = os::elapsedTime();
ysr@777 198 if (PrintGC) {
ysr@777 199 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 200 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 201 gclog_or_tty->print_cr("[GC concurrent-count-end, %1.7lf]",
ysr@777 202 count_end_sec - count_start_sec);
ysr@777 203 }
ysr@777 204 }
ysr@777 205 }
ysr@777 206 double end_time = os::elapsedVTime();
ysr@777 207 _vtime_count_accum += (end_time - counting_start_time);
ysr@777 208 // Update the total virtual time before doing this, since it will try
ysr@777 209 // to measure it to get the vtime for this marking. We purposely
ysr@777 210 // neglect the presumably-short "completeCleanup" phase here.
ysr@777 211 _vtime_accum = (end_time - _vtime_start);
ysr@777 212 if (!cm()->has_aborted()) {
ysr@777 213 if (g1_policy->adaptive_young_list_length()) {
ysr@777 214 double now = os::elapsedTime();
ysr@777 215 double cleanup_prediction_ms = g1_policy->predict_cleanup_time_ms();
ysr@777 216 jlong sleep_time_ms = mmu_tracker->when_ms(now, cleanup_prediction_ms);
ysr@777 217 os::sleep(current_thread, sleep_time_ms, false);
ysr@777 218 }
ysr@777 219
ysr@777 220 CMCleanUp cl_cl(_cm);
ysr@777 221 sprintf(verbose_str, "GC cleanup");
ysr@777 222 VM_CGC_Operation op(&cl_cl, verbose_str);
ysr@777 223 VMThread::execute(&op);
ysr@777 224 } else {
ysr@777 225 G1CollectedHeap::heap()->set_marking_complete();
ysr@777 226 }
ysr@777 227
ysr@777 228 if (!cm()->has_aborted()) {
ysr@777 229 double cleanup_start_sec = os::elapsedTime();
ysr@777 230 if (PrintGC) {
ysr@777 231 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 232 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 233 gclog_or_tty->print_cr("[GC concurrent-cleanup-start]");
ysr@777 234 }
ysr@777 235
ysr@777 236 // Now do the remainder of the cleanup operation.
ysr@777 237 _sts.join();
ysr@777 238 _cm->completeCleanup();
ysr@777 239 if (!cm()->has_aborted()) {
ysr@777 240 g1_policy->record_concurrent_mark_cleanup_completed();
ysr@777 241
ysr@777 242 double cleanup_end_sec = os::elapsedTime();
ysr@777 243 if (PrintGC) {
ysr@777 244 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 245 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 246 gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf]",
ysr@777 247 cleanup_end_sec - cleanup_start_sec);
ysr@777 248 }
ysr@777 249 }
ysr@777 250 _sts.leave();
ysr@777 251 }
ysr@777 252 // We're done: no more unclean regions coming.
ysr@777 253 G1CollectedHeap::heap()->set_unclean_regions_coming(false);
ysr@777 254
ysr@777 255 if (cm()->has_aborted()) {
ysr@777 256 if (PrintGC) {
ysr@777 257 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 258 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 259 gclog_or_tty->print_cr("[GC concurrent-mark-abort]");
ysr@777 260 }
ysr@777 261 }
ysr@777 262
ysr@777 263 _sts.join();
ysr@777 264 _cm->disable_co_trackers();
ysr@777 265 _sts.leave();
ysr@777 266
ysr@777 267 // we now want to allow clearing of the marking bitmap to be
ysr@777 268 // suspended by a collection pause.
ysr@777 269 _sts.join();
ysr@777 270 _cm->clearNextBitmap();
ysr@777 271 _sts.leave();
ysr@777 272 }
ysr@777 273 }
ysr@777 274 assert(_should_terminate, "just checking");
ysr@777 275
ysr@777 276 terminate();
ysr@777 277 }
ysr@777 278
ysr@777 279
ysr@777 280 void ConcurrentMarkThread::yield() {
ysr@777 281 _sts.yield("Concurrent Mark");
ysr@777 282 }
ysr@777 283
ysr@777 284 void ConcurrentMarkThread::stop() {
ysr@777 285 // it is ok to take late safepoints here, if needed
ysr@777 286 MutexLockerEx mu(Terminator_lock);
ysr@777 287 _should_terminate = true;
ysr@777 288 while (!_has_terminated) {
ysr@777 289 Terminator_lock->wait();
ysr@777 290 }
ysr@777 291 }
ysr@777 292
ysr@777 293 void ConcurrentMarkThread::print() {
ysr@777 294 gclog_or_tty->print("\"Concurrent Mark GC Thread\" ");
ysr@777 295 Thread::print();
ysr@777 296 gclog_or_tty->cr();
ysr@777 297 }
ysr@777 298
ysr@777 299 void ConcurrentMarkThread::sleepBeforeNextCycle() {
ysr@777 300 clear_in_progress();
ysr@777 301 // We join here because we don't want to do the "shouldConcurrentMark()"
ysr@777 302 // below while the world is otherwise stopped.
ysr@777 303 MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
ysr@777 304 while (!started()) {
ysr@777 305 CGC_lock->wait(Mutex::_no_safepoint_check_flag);
ysr@777 306 }
ysr@777 307 set_in_progress();
ysr@777 308 clear_started();
ysr@777 309 }
ysr@777 310
ysr@777 311 // Note: this method, although exported by the ConcurrentMarkSweepThread,
ysr@777 312 // which is a non-JavaThread, can only be called by a JavaThread.
ysr@777 313 // Currently this is done at vm creation time (post-vm-init) by the
ysr@777 314 // main/Primordial (Java)Thread.
ysr@777 315 // XXX Consider changing this in the future to allow the CMS thread
ysr@777 316 // itself to create this thread?
ysr@777 317 void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) {
ysr@777 318 assert(_slt == NULL, "SLT already created");
ysr@777 319 _slt = SurrogateLockerThread::make(THREAD);
ysr@777 320 }

mercurial