Mon, 03 Aug 2009 12:59:30 -0700
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 }