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

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

author
johnc
date
Tue, 21 Aug 2012 14:10:39 -0700
changeset 3998
7383557659bd
parent 3823
37552638d24a
child 4386
d275c3dc73e6
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

ysr@777 1 /*
johnc@3463 2 * Copyright (c) 2001, 2012, 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
stefank@2314 25 #include "precompiled.hpp"
stefank@2314 26 #include "gc_implementation/g1/concurrentMarkThread.inline.hpp"
stefank@2314 27 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
stefank@2314 28 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
brutisso@3710 29 #include "gc_implementation/g1/g1Log.hpp"
stefank@2314 30 #include "gc_implementation/g1/g1MMUTracker.hpp"
stefank@2314 31 #include "gc_implementation/g1/vm_operations_g1.hpp"
stefank@2314 32 #include "memory/resourceArea.hpp"
stefank@2314 33 #include "runtime/vmThread.hpp"
ysr@777 34
ysr@777 35 // ======= Concurrent Mark Thread ========
ysr@777 36
ysr@777 37 // The CM thread is created when the G1 garbage collector is used
ysr@777 38
ysr@777 39 SurrogateLockerThread*
ysr@777 40 ConcurrentMarkThread::_slt = NULL;
ysr@777 41
ysr@777 42 ConcurrentMarkThread::ConcurrentMarkThread(ConcurrentMark* cm) :
ysr@777 43 ConcurrentGCThread(),
ysr@777 44 _cm(cm),
ysr@777 45 _started(false),
ysr@777 46 _in_progress(false),
ysr@777 47 _vtime_accum(0.0),
johnc@3463 48 _vtime_mark_accum(0.0) {
ysr@777 49 create_and_start();
ysr@777 50 }
ysr@777 51
ysr@777 52 class CMCheckpointRootsFinalClosure: public VoidClosure {
ysr@777 53
ysr@777 54 ConcurrentMark* _cm;
ysr@777 55 public:
ysr@777 56
ysr@777 57 CMCheckpointRootsFinalClosure(ConcurrentMark* cm) :
ysr@777 58 _cm(cm) {}
ysr@777 59
ysr@777 60 void do_void(){
ysr@777 61 _cm->checkpointRootsFinal(false); // !clear_all_soft_refs
ysr@777 62 }
ysr@777 63 };
ysr@777 64
ysr@777 65 class CMCleanUp: public VoidClosure {
ysr@777 66 ConcurrentMark* _cm;
ysr@777 67 public:
ysr@777 68
ysr@777 69 CMCleanUp(ConcurrentMark* cm) :
ysr@777 70 _cm(cm) {}
ysr@777 71
ysr@777 72 void do_void(){
ysr@777 73 _cm->cleanup();
ysr@777 74 }
ysr@777 75 };
ysr@777 76
ysr@777 77
ysr@777 78
ysr@777 79 void ConcurrentMarkThread::run() {
ysr@777 80 initialize_in_thread();
ysr@777 81 _vtime_start = os::elapsedVTime();
ysr@777 82 wait_for_universe_init();
ysr@777 83
tonyp@2472 84 G1CollectedHeap* g1h = G1CollectedHeap::heap();
tonyp@2472 85 G1CollectorPolicy* g1_policy = g1h->g1_policy();
ysr@777 86 G1MMUTracker *mmu_tracker = g1_policy->mmu_tracker();
ysr@777 87 Thread *current_thread = Thread::current();
ysr@777 88
ysr@777 89 while (!_should_terminate) {
ysr@777 90 // wait until started is set.
ysr@777 91 sleepBeforeNextCycle();
ysr@777 92 {
ysr@777 93 ResourceMark rm;
ysr@777 94 HandleMark hm;
ysr@777 95 double cycle_start = os::elapsedVTime();
ysr@777 96 char verbose_str[128];
ysr@777 97
tonyp@3464 98 // We have to ensure that we finish scanning the root regions
tonyp@3464 99 // before the next GC takes place. To ensure this we have to
tonyp@3464 100 // make sure that we do not join the STS until the root regions
tonyp@3464 101 // have been scanned. If we did then it's possible that a
tonyp@3464 102 // subsequent GC could block us from joining the STS and proceed
tonyp@3464 103 // without the root regions have been scanned which would be a
tonyp@3464 104 // correctness issue.
tonyp@3464 105
tonyp@3464 106 double scan_start = os::elapsedTime();
tonyp@3464 107 if (!cm()->has_aborted()) {
brutisso@3710 108 if (G1Log::fine()) {
tonyp@3464 109 gclog_or_tty->date_stamp(PrintGCDateStamps);
tonyp@3464 110 gclog_or_tty->stamp(PrintGCTimeStamps);
tonyp@3464 111 gclog_or_tty->print_cr("[GC concurrent-root-region-scan-start]");
tonyp@3464 112 }
tonyp@3464 113
tonyp@3464 114 _cm->scanRootRegions();
tonyp@3464 115
tonyp@3464 116 double scan_end = os::elapsedTime();
brutisso@3710 117 if (G1Log::fine()) {
tonyp@3464 118 gclog_or_tty->date_stamp(PrintGCDateStamps);
tonyp@3464 119 gclog_or_tty->stamp(PrintGCTimeStamps);
tonyp@3464 120 gclog_or_tty->print_cr("[GC concurrent-root-region-scan-end, %1.7lf]",
tonyp@3464 121 scan_end - scan_start);
tonyp@3464 122 }
tonyp@3464 123 }
tonyp@3464 124
tonyp@3464 125 double mark_start_sec = os::elapsedTime();
brutisso@3710 126 if (G1Log::fine()) {
ysr@777 127 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 128 gclog_or_tty->stamp(PrintGCTimeStamps);
tonyp@1054 129 gclog_or_tty->print_cr("[GC concurrent-mark-start]");
ysr@777 130 }
ysr@777 131
ysr@777 132 int iter = 0;
ysr@777 133 do {
ysr@777 134 iter++;
ysr@777 135 if (!cm()->has_aborted()) {
ysr@777 136 _cm->markFromRoots();
ysr@777 137 }
ysr@777 138
ysr@777 139 double mark_end_time = os::elapsedVTime();
ysr@777 140 double mark_end_sec = os::elapsedTime();
ysr@777 141 _vtime_mark_accum += (mark_end_time - cycle_start);
ysr@777 142 if (!cm()->has_aborted()) {
ysr@777 143 if (g1_policy->adaptive_young_list_length()) {
ysr@777 144 double now = os::elapsedTime();
ysr@777 145 double remark_prediction_ms = g1_policy->predict_remark_time_ms();
ysr@777 146 jlong sleep_time_ms = mmu_tracker->when_ms(now, remark_prediction_ms);
ysr@777 147 os::sleep(current_thread, sleep_time_ms, false);
ysr@777 148 }
ysr@777 149
brutisso@3710 150 if (G1Log::fine()) {
ysr@777 151 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 152 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 153 gclog_or_tty->print_cr("[GC concurrent-mark-end, %1.7lf sec]",
ysr@777 154 mark_end_sec - mark_start_sec);
ysr@777 155 }
ysr@777 156
ysr@777 157 CMCheckpointRootsFinalClosure final_cl(_cm);
ysr@777 158 sprintf(verbose_str, "GC remark");
johnc@3666 159 VM_CGC_Operation op(&final_cl, verbose_str, true /* needs_pll */);
ysr@777 160 VMThread::execute(&op);
ysr@777 161 }
ysr@777 162 if (cm()->restart_for_overflow() &&
ysr@777 163 G1TraceMarkStackOverflow) {
ysr@777 164 gclog_or_tty->print_cr("Restarting conc marking because of MS overflow "
ysr@777 165 "in remark (restart #%d).", iter);
ysr@777 166 }
ysr@777 167
ysr@777 168 if (cm()->restart_for_overflow()) {
brutisso@3710 169 if (G1Log::fine()) {
ysr@777 170 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 171 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 172 gclog_or_tty->print_cr("[GC concurrent-mark-restart-for-overflow]");
ysr@777 173 }
ysr@777 174 }
ysr@777 175 } while (cm()->restart_for_overflow());
johnc@3218 176
ysr@777 177 double end_time = os::elapsedVTime();
ysr@777 178 // Update the total virtual time before doing this, since it will try
ysr@777 179 // to measure it to get the vtime for this marking. We purposely
ysr@777 180 // neglect the presumably-short "completeCleanup" phase here.
ysr@777 181 _vtime_accum = (end_time - _vtime_start);
johnc@3463 182
ysr@777 183 if (!cm()->has_aborted()) {
ysr@777 184 if (g1_policy->adaptive_young_list_length()) {
ysr@777 185 double now = os::elapsedTime();
ysr@777 186 double cleanup_prediction_ms = g1_policy->predict_cleanup_time_ms();
ysr@777 187 jlong sleep_time_ms = mmu_tracker->when_ms(now, cleanup_prediction_ms);
ysr@777 188 os::sleep(current_thread, sleep_time_ms, false);
ysr@777 189 }
ysr@777 190
ysr@777 191 CMCleanUp cl_cl(_cm);
ysr@777 192 sprintf(verbose_str, "GC cleanup");
johnc@3666 193 VM_CGC_Operation op(&cl_cl, verbose_str, false /* needs_pll */);
ysr@777 194 VMThread::execute(&op);
ysr@777 195 } else {
johnc@3295 196 // We don't want to update the marking status if a GC pause
johnc@3295 197 // is already underway.
johnc@3295 198 _sts.join();
tonyp@2472 199 g1h->set_marking_complete();
johnc@3295 200 _sts.leave();
ysr@777 201 }
ysr@777 202
tonyp@2472 203 // Check if cleanup set the free_regions_coming flag. If it
tonyp@2472 204 // hasn't, we can just skip the next step.
tonyp@2472 205 if (g1h->free_regions_coming()) {
tonyp@2472 206 // The following will finish freeing up any regions that we
tonyp@2472 207 // found to be empty during cleanup. We'll do this part
tonyp@2472 208 // without joining the suspendible set. If an evacuation pause
tonyp@2643 209 // takes place, then we would carry on freeing regions in
tonyp@2472 210 // case they are needed by the pause. If a Full GC takes
tonyp@2643 211 // place, it would wait for us to process the regions
tonyp@2472 212 // reclaimed by cleanup.
tonyp@2472 213
ysr@777 214 double cleanup_start_sec = os::elapsedTime();
brutisso@3710 215 if (G1Log::fine()) {
ysr@777 216 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 217 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 218 gclog_or_tty->print_cr("[GC concurrent-cleanup-start]");
ysr@777 219 }
ysr@777 220
tonyp@3208 221 // Now do the concurrent cleanup operation.
ysr@777 222 _cm->completeCleanup();
tonyp@3208 223
tonyp@2501 224 // Notify anyone who's waiting that there are no more free
tonyp@3208 225 // regions coming. We have to do this before we join the STS
tonyp@3208 226 // (in fact, we should not attempt to join the STS in the
tonyp@3208 227 // interval between finishing the cleanup pause and clearing
tonyp@3208 228 // the free_regions_coming flag) otherwise we might deadlock:
tonyp@3208 229 // a GC worker could be blocked waiting for the notification
tonyp@3208 230 // whereas this thread will be blocked for the pause to finish
tonyp@3208 231 // while it's trying to join the STS, which is conditional on
tonyp@3208 232 // the GC workers finishing.
tonyp@2501 233 g1h->reset_free_regions_coming();
tonyp@2501 234
tonyp@2472 235 double cleanup_end_sec = os::elapsedTime();
brutisso@3710 236 if (G1Log::fine()) {
tonyp@2472 237 gclog_or_tty->date_stamp(PrintGCDateStamps);
tonyp@2472 238 gclog_or_tty->stamp(PrintGCTimeStamps);
tonyp@2472 239 gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf]",
tonyp@2472 240 cleanup_end_sec - cleanup_start_sec);
ysr@777 241 }
ysr@777 242 }
tonyp@2472 243 guarantee(cm()->cleanup_list_is_empty(),
tonyp@2472 244 "at this point there should be no regions on the cleanup list");
ysr@777 245
tonyp@3208 246 // There is a tricky race before recording that the concurrent
tonyp@3208 247 // cleanup has completed and a potential Full GC starting around
tonyp@3208 248 // the same time. We want to make sure that the Full GC calls
tonyp@3208 249 // abort() on concurrent mark after
tonyp@3208 250 // record_concurrent_mark_cleanup_completed(), since abort() is
tonyp@3208 251 // the method that will reset the concurrent mark state. If we
tonyp@3208 252 // end up calling record_concurrent_mark_cleanup_completed()
tonyp@3208 253 // after abort() then we might incorrectly undo some of the work
tonyp@3208 254 // abort() did. Checking the has_aborted() flag after joining
tonyp@3208 255 // the STS allows the correct ordering of the two methods. There
tonyp@3208 256 // are two scenarios:
tonyp@3208 257 //
tonyp@3208 258 // a) If we reach here before the Full GC, the fact that we have
tonyp@3208 259 // joined the STS means that the Full GC cannot start until we
tonyp@3208 260 // leave the STS, so record_concurrent_mark_cleanup_completed()
tonyp@3208 261 // will complete before abort() is called.
tonyp@3208 262 //
tonyp@3208 263 // b) If we reach here during the Full GC, we'll be held up from
tonyp@3208 264 // joining the STS until the Full GC is done, which means that
tonyp@3208 265 // abort() will have completed and has_aborted() will return
tonyp@3208 266 // true to prevent us from calling
tonyp@3208 267 // record_concurrent_mark_cleanup_completed() (and, in fact, it's
tonyp@3208 268 // not needed any more as the concurrent mark state has been
tonyp@3208 269 // already reset).
tonyp@3208 270 _sts.join();
tonyp@3208 271 if (!cm()->has_aborted()) {
tonyp@3208 272 g1_policy->record_concurrent_mark_cleanup_completed();
tonyp@3208 273 }
tonyp@3208 274 _sts.leave();
tonyp@3208 275
ysr@777 276 if (cm()->has_aborted()) {
brutisso@3710 277 if (G1Log::fine()) {
ysr@777 278 gclog_or_tty->date_stamp(PrintGCDateStamps);
ysr@777 279 gclog_or_tty->stamp(PrintGCTimeStamps);
ysr@777 280 gclog_or_tty->print_cr("[GC concurrent-mark-abort]");
ysr@777 281 }
ysr@777 282 }
ysr@777 283
tonyp@3208 284 // We now want to allow clearing of the marking bitmap to be
ysr@777 285 // suspended by a collection pause.
ysr@777 286 _sts.join();
ysr@777 287 _cm->clearNextBitmap();
ysr@777 288 _sts.leave();
ysr@777 289 }
tonyp@2011 290
tonyp@2011 291 // Update the number of full collections that have been
tonyp@2011 292 // completed. This will also notify the FullGCCount_lock in case a
tonyp@2011 293 // Java thread is waiting for a full GC to happen (e.g., it
tonyp@2011 294 // called System.gc() with +ExplicitGCInvokesConcurrent).
tonyp@2372 295 _sts.join();
brutisso@3823 296 g1h->increment_old_marking_cycles_completed(true /* concurrent */);
tonyp@2372 297 _sts.leave();
ysr@777 298 }
ysr@777 299 assert(_should_terminate, "just checking");
ysr@777 300
ysr@777 301 terminate();
ysr@777 302 }
ysr@777 303
ysr@777 304
ysr@777 305 void ConcurrentMarkThread::yield() {
ysr@777 306 _sts.yield("Concurrent Mark");
ysr@777 307 }
ysr@777 308
ysr@777 309 void ConcurrentMarkThread::stop() {
ysr@777 310 // it is ok to take late safepoints here, if needed
ysr@777 311 MutexLockerEx mu(Terminator_lock);
ysr@777 312 _should_terminate = true;
ysr@777 313 while (!_has_terminated) {
ysr@777 314 Terminator_lock->wait();
ysr@777 315 }
ysr@777 316 }
ysr@777 317
tonyp@1454 318 void ConcurrentMarkThread::print() const {
tonyp@1454 319 print_on(tty);
tonyp@1454 320 }
tonyp@1454 321
tonyp@1454 322 void ConcurrentMarkThread::print_on(outputStream* st) const {
tonyp@1454 323 st->print("\"G1 Main Concurrent Mark GC Thread\" ");
tonyp@1454 324 Thread::print_on(st);
tonyp@1454 325 st->cr();
ysr@777 326 }
ysr@777 327
ysr@777 328 void ConcurrentMarkThread::sleepBeforeNextCycle() {
ysr@777 329 // We join here because we don't want to do the "shouldConcurrentMark()"
ysr@777 330 // below while the world is otherwise stopped.
johnc@2195 331 assert(!in_progress(), "should have been cleared");
johnc@2195 332
ysr@777 333 MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
ysr@777 334 while (!started()) {
ysr@777 335 CGC_lock->wait(Mutex::_no_safepoint_check_flag);
ysr@777 336 }
ysr@777 337 set_in_progress();
ysr@777 338 clear_started();
ysr@777 339 }
ysr@777 340
johnc@3218 341 // Note: As is the case with CMS - this method, although exported
johnc@3218 342 // by the ConcurrentMarkThread, which is a non-JavaThread, can only
johnc@3218 343 // be called by a JavaThread. Currently this is done at vm creation
johnc@3218 344 // time (post-vm-init) by the main/Primordial (Java)Thread.
johnc@3218 345 // XXX Consider changing this in the future to allow the CM thread
ysr@777 346 // itself to create this thread?
ysr@777 347 void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) {
johnc@3218 348 assert(UseG1GC, "SLT thread needed only for concurrent GC");
johnc@3218 349 assert(THREAD->is_Java_thread(), "must be a Java thread");
ysr@777 350 assert(_slt == NULL, "SLT already created");
ysr@777 351 _slt = SurrogateLockerThread::make(THREAD);
ysr@777 352 }

mercurial