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

ysr@777 1 /*
trims@1907 2 * Copyright (c) 2001, 2009, Oracle and/or its affiliates. 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 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * 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 // we now want to allow clearing of the marking bitmap to be
ysr@777 264 // suspended by a collection pause.
ysr@777 265 _sts.join();
ysr@777 266 _cm->clearNextBitmap();
ysr@777 267 _sts.leave();
ysr@777 268 }
tonyp@2011 269
tonyp@2011 270 // Update the number of full collections that have been
tonyp@2011 271 // completed. This will also notify the FullGCCount_lock in case a
tonyp@2011 272 // Java thread is waiting for a full GC to happen (e.g., it
tonyp@2011 273 // called System.gc() with +ExplicitGCInvokesConcurrent).
tonyp@2011 274 g1->increment_full_collections_completed(true /* outer */);
ysr@777 275 }
ysr@777 276 assert(_should_terminate, "just checking");
ysr@777 277
ysr@777 278 terminate();
ysr@777 279 }
ysr@777 280
ysr@777 281
ysr@777 282 void ConcurrentMarkThread::yield() {
ysr@777 283 _sts.yield("Concurrent Mark");
ysr@777 284 }
ysr@777 285
ysr@777 286 void ConcurrentMarkThread::stop() {
ysr@777 287 // it is ok to take late safepoints here, if needed
ysr@777 288 MutexLockerEx mu(Terminator_lock);
ysr@777 289 _should_terminate = true;
ysr@777 290 while (!_has_terminated) {
ysr@777 291 Terminator_lock->wait();
ysr@777 292 }
ysr@777 293 }
ysr@777 294
tonyp@1454 295 void ConcurrentMarkThread::print() const {
tonyp@1454 296 print_on(tty);
tonyp@1454 297 }
tonyp@1454 298
tonyp@1454 299 void ConcurrentMarkThread::print_on(outputStream* st) const {
tonyp@1454 300 st->print("\"G1 Main Concurrent Mark GC Thread\" ");
tonyp@1454 301 Thread::print_on(st);
tonyp@1454 302 st->cr();
ysr@777 303 }
ysr@777 304
ysr@777 305 void ConcurrentMarkThread::sleepBeforeNextCycle() {
ysr@777 306 clear_in_progress();
ysr@777 307 // We join here because we don't want to do the "shouldConcurrentMark()"
ysr@777 308 // below while the world is otherwise stopped.
ysr@777 309 MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
ysr@777 310 while (!started()) {
ysr@777 311 CGC_lock->wait(Mutex::_no_safepoint_check_flag);
ysr@777 312 }
ysr@777 313 set_in_progress();
ysr@777 314 clear_started();
ysr@777 315 }
ysr@777 316
ysr@777 317 // Note: this method, although exported by the ConcurrentMarkSweepThread,
ysr@777 318 // which is a non-JavaThread, can only be called by a JavaThread.
ysr@777 319 // Currently this is done at vm creation time (post-vm-init) by the
ysr@777 320 // main/Primordial (Java)Thread.
ysr@777 321 // XXX Consider changing this in the future to allow the CMS thread
ysr@777 322 // itself to create this thread?
ysr@777 323 void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) {
ysr@777 324 assert(_slt == NULL, "SLT already created");
ysr@777 325 _slt = SurrogateLockerThread::make(THREAD);
ysr@777 326 }

mercurial