Mercurial > hg > graal-jvmci-8
annotate src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp @ 3772:6747fd0512e0
7004681: G1: Extend marking verification to Full GCs
Summary: Perform a heap verification after the first phase of G1's full GC using objects' mark words to determine liveness. The third parameter of the heap verification routines, which was used in G1 to determine which marking bitmap to use in liveness calculations, has been changed from a boolean to an enum with values defined for using the mark word, and the 'prev' and 'next' bitmaps.
Reviewed-by: tonyp, ysr
author | johnc |
---|---|
date | Tue, 14 Jun 2011 11:01:10 -0700 |
parents | 1216415d8e35 |
children | ff53346271fe |
rev | line source |
---|---|
342 | 1 /* |
2152 | 2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. |
342 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1019
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1019
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1019
diff
changeset
|
21 * questions. |
342 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "gc_implementation/g1/concurrentMarkThread.inline.hpp" | |
27 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" | |
28 #include "gc_implementation/g1/g1CollectorPolicy.hpp" | |
29 #include "gc_implementation/g1/g1MMUTracker.hpp" | |
30 #include "gc_implementation/g1/vm_operations_g1.hpp" | |
31 #include "memory/resourceArea.hpp" | |
32 #include "runtime/vmThread.hpp" | |
342 | 33 |
34 // ======= Concurrent Mark Thread ======== | |
35 | |
36 // The CM thread is created when the G1 garbage collector is used | |
37 | |
38 SurrogateLockerThread* | |
39 ConcurrentMarkThread::_slt = NULL; | |
40 | |
41 ConcurrentMarkThread::ConcurrentMarkThread(ConcurrentMark* cm) : | |
42 ConcurrentGCThread(), | |
43 _cm(cm), | |
44 _started(false), | |
45 _in_progress(false), | |
46 _vtime_accum(0.0), | |
47 _vtime_mark_accum(0.0), | |
48 _vtime_count_accum(0.0) | |
49 { | |
50 create_and_start(); | |
51 } | |
52 | |
53 class CMCheckpointRootsInitialClosure: public VoidClosure { | |
54 | |
55 ConcurrentMark* _cm; | |
56 public: | |
57 | |
58 CMCheckpointRootsInitialClosure(ConcurrentMark* cm) : | |
59 _cm(cm) {} | |
60 | |
61 void do_void(){ | |
62 _cm->checkpointRootsInitial(); | |
63 } | |
64 }; | |
65 | |
66 class CMCheckpointRootsFinalClosure: public VoidClosure { | |
67 | |
68 ConcurrentMark* _cm; | |
69 public: | |
70 | |
71 CMCheckpointRootsFinalClosure(ConcurrentMark* cm) : | |
72 _cm(cm) {} | |
73 | |
74 void do_void(){ | |
75 _cm->checkpointRootsFinal(false); // !clear_all_soft_refs | |
76 } | |
77 }; | |
78 | |
79 class CMCleanUp: public VoidClosure { | |
80 ConcurrentMark* _cm; | |
81 public: | |
82 | |
83 CMCleanUp(ConcurrentMark* cm) : | |
84 _cm(cm) {} | |
85 | |
86 void do_void(){ | |
87 _cm->cleanup(); | |
88 } | |
89 }; | |
90 | |
91 | |
92 | |
93 void ConcurrentMarkThread::run() { | |
94 initialize_in_thread(); | |
95 _vtime_start = os::elapsedVTime(); | |
96 wait_for_universe_init(); | |
97 | |
2152 | 98 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
99 G1CollectorPolicy* g1_policy = g1h->g1_policy(); | |
342 | 100 G1MMUTracker *mmu_tracker = g1_policy->mmu_tracker(); |
101 Thread *current_thread = Thread::current(); | |
102 | |
103 while (!_should_terminate) { | |
104 // wait until started is set. | |
105 sleepBeforeNextCycle(); | |
106 { | |
107 ResourceMark rm; | |
108 HandleMark hm; | |
109 double cycle_start = os::elapsedVTime(); | |
110 double mark_start_sec = os::elapsedTime(); | |
111 char verbose_str[128]; | |
112 | |
113 if (PrintGC) { | |
114 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
115 gclog_or_tty->stamp(PrintGCTimeStamps); | |
619
7ea5ca260b28
6814467: G1: small fixes related to concurrent marking verboseness
tonyp
parents:
342
diff
changeset
|
116 gclog_or_tty->print_cr("[GC concurrent-mark-start]"); |
342 | 117 } |
118 | |
119 if (!g1_policy->in_young_gc_mode()) { | |
120 // this ensures the flag is not set if we bail out of the marking | |
121 // cycle; normally the flag is cleared immediately after cleanup | |
2152 | 122 g1h->set_marking_complete(); |
342 | 123 |
124 if (g1_policy->adaptive_young_list_length()) { | |
125 double now = os::elapsedTime(); | |
126 double init_prediction_ms = g1_policy->predict_init_time_ms(); | |
127 jlong sleep_time_ms = mmu_tracker->when_ms(now, init_prediction_ms); | |
128 os::sleep(current_thread, sleep_time_ms, false); | |
129 } | |
130 | |
131 // We don't have to skip here if we've been asked to restart, because | |
132 // in the worst case we just enqueue a new VM operation to start a | |
133 // marking. Note that the init operation resets has_aborted() | |
134 CMCheckpointRootsInitialClosure init_cl(_cm); | |
135 strcpy(verbose_str, "GC initial-mark"); | |
136 VM_CGC_Operation op(&init_cl, verbose_str); | |
137 VMThread::execute(&op); | |
138 } | |
139 | |
140 int iter = 0; | |
141 do { | |
142 iter++; | |
143 if (!cm()->has_aborted()) { | |
144 _cm->markFromRoots(); | |
145 } | |
146 | |
147 double mark_end_time = os::elapsedVTime(); | |
148 double mark_end_sec = os::elapsedTime(); | |
149 _vtime_mark_accum += (mark_end_time - cycle_start); | |
150 if (!cm()->has_aborted()) { | |
151 if (g1_policy->adaptive_young_list_length()) { | |
152 double now = os::elapsedTime(); | |
153 double remark_prediction_ms = g1_policy->predict_remark_time_ms(); | |
154 jlong sleep_time_ms = mmu_tracker->when_ms(now, remark_prediction_ms); | |
155 os::sleep(current_thread, sleep_time_ms, false); | |
156 } | |
157 | |
158 if (PrintGC) { | |
159 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
160 gclog_or_tty->stamp(PrintGCTimeStamps); | |
161 gclog_or_tty->print_cr("[GC concurrent-mark-end, %1.7lf sec]", | |
162 mark_end_sec - mark_start_sec); | |
163 } | |
164 | |
165 CMCheckpointRootsFinalClosure final_cl(_cm); | |
166 sprintf(verbose_str, "GC remark"); | |
167 VM_CGC_Operation op(&final_cl, verbose_str); | |
168 VMThread::execute(&op); | |
169 } | |
170 if (cm()->restart_for_overflow() && | |
171 G1TraceMarkStackOverflow) { | |
172 gclog_or_tty->print_cr("Restarting conc marking because of MS overflow " | |
173 "in remark (restart #%d).", iter); | |
174 } | |
175 | |
176 if (cm()->restart_for_overflow()) { | |
177 if (PrintGC) { | |
178 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
179 gclog_or_tty->stamp(PrintGCTimeStamps); | |
180 gclog_or_tty->print_cr("[GC concurrent-mark-restart-for-overflow]"); | |
181 } | |
182 } | |
183 } while (cm()->restart_for_overflow()); | |
184 double counting_start_time = os::elapsedVTime(); | |
185 | |
186 // YSR: These look dubious (i.e. redundant) !!! FIX ME | |
187 slt()->manipulatePLL(SurrogateLockerThread::acquirePLL); | |
188 slt()->manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL); | |
189 | |
190 if (!cm()->has_aborted()) { | |
191 double count_start_sec = os::elapsedTime(); | |
192 if (PrintGC) { | |
193 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
194 gclog_or_tty->stamp(PrintGCTimeStamps); | |
195 gclog_or_tty->print_cr("[GC concurrent-count-start]"); | |
196 } | |
197 | |
198 _sts.join(); | |
199 _cm->calcDesiredRegions(); | |
200 _sts.leave(); | |
201 | |
202 if (!cm()->has_aborted()) { | |
203 double count_end_sec = os::elapsedTime(); | |
204 if (PrintGC) { | |
205 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
206 gclog_or_tty->stamp(PrintGCTimeStamps); | |
207 gclog_or_tty->print_cr("[GC concurrent-count-end, %1.7lf]", | |
208 count_end_sec - count_start_sec); | |
209 } | |
210 } | |
211 } | |
212 double end_time = os::elapsedVTime(); | |
213 _vtime_count_accum += (end_time - counting_start_time); | |
214 // Update the total virtual time before doing this, since it will try | |
215 // to measure it to get the vtime for this marking. We purposely | |
216 // neglect the presumably-short "completeCleanup" phase here. | |
217 _vtime_accum = (end_time - _vtime_start); | |
218 if (!cm()->has_aborted()) { | |
219 if (g1_policy->adaptive_young_list_length()) { | |
220 double now = os::elapsedTime(); | |
221 double cleanup_prediction_ms = g1_policy->predict_cleanup_time_ms(); | |
222 jlong sleep_time_ms = mmu_tracker->when_ms(now, cleanup_prediction_ms); | |
223 os::sleep(current_thread, sleep_time_ms, false); | |
224 } | |
225 | |
226 CMCleanUp cl_cl(_cm); | |
227 sprintf(verbose_str, "GC cleanup"); | |
228 VM_CGC_Operation op(&cl_cl, verbose_str); | |
229 VMThread::execute(&op); | |
230 } else { | |
2152 | 231 g1h->set_marking_complete(); |
342 | 232 } |
233 | |
2152 | 234 // Check if cleanup set the free_regions_coming flag. If it |
235 // hasn't, we can just skip the next step. | |
236 if (g1h->free_regions_coming()) { | |
237 // The following will finish freeing up any regions that we | |
238 // found to be empty during cleanup. We'll do this part | |
239 // without joining the suspendible set. If an evacuation pause | |
2361 | 240 // takes place, then we would carry on freeing regions in |
2152 | 241 // case they are needed by the pause. If a Full GC takes |
2361 | 242 // place, it would wait for us to process the regions |
2152 | 243 // reclaimed by cleanup. |
244 | |
342 | 245 double cleanup_start_sec = os::elapsedTime(); |
246 if (PrintGC) { | |
247 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
248 gclog_or_tty->stamp(PrintGCTimeStamps); | |
249 gclog_or_tty->print_cr("[GC concurrent-cleanup-start]"); | |
250 } | |
251 | |
252 // Now do the remainder of the cleanup operation. | |
253 _cm->completeCleanup(); | |
2185 | 254 // Notify anyone who's waiting that there are no more free |
255 // regions coming. We have to do this before we join the STS, | |
256 // otherwise we might deadlock: a GC worker could be blocked | |
257 // waiting for the notification whereas this thread will be | |
258 // blocked for the pause to finish while it's trying to join | |
259 // the STS, which is conditional on the GC workers finishing. | |
260 g1h->reset_free_regions_coming(); | |
261 | |
2172
a672e43650cc
7013718: G1: small fixes for two assert/guarantee failures
tonyp
parents:
2152
diff
changeset
|
262 _sts.join(); |
2152 | 263 g1_policy->record_concurrent_mark_cleanup_completed(); |
2172
a672e43650cc
7013718: G1: small fixes for two assert/guarantee failures
tonyp
parents:
2152
diff
changeset
|
264 _sts.leave(); |
342 | 265 |
2152 | 266 double cleanup_end_sec = os::elapsedTime(); |
267 if (PrintGC) { | |
268 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
269 gclog_or_tty->stamp(PrintGCTimeStamps); | |
270 gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf]", | |
271 cleanup_end_sec - cleanup_start_sec); | |
342 | 272 } |
273 } | |
2152 | 274 guarantee(cm()->cleanup_list_is_empty(), |
275 "at this point there should be no regions on the cleanup list"); | |
342 | 276 |
277 if (cm()->has_aborted()) { | |
278 if (PrintGC) { | |
279 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
280 gclog_or_tty->stamp(PrintGCTimeStamps); | |
281 gclog_or_tty->print_cr("[GC concurrent-mark-abort]"); | |
282 } | |
283 } | |
284 | |
285 // we now want to allow clearing of the marking bitmap to be | |
286 // suspended by a collection pause. | |
287 _sts.join(); | |
288 _cm->clearNextBitmap(); | |
289 _sts.leave(); | |
290 } | |
1656
4e5661ba9d98
6944166: G1: explicit GCs are not always handled correctly
tonyp
parents:
1552
diff
changeset
|
291 |
4e5661ba9d98
6944166: G1: explicit GCs are not always handled correctly
tonyp
parents:
1552
diff
changeset
|
292 // Update the number of full collections that have been |
4e5661ba9d98
6944166: G1: explicit GCs are not always handled correctly
tonyp
parents:
1552
diff
changeset
|
293 // completed. This will also notify the FullGCCount_lock in case a |
4e5661ba9d98
6944166: G1: explicit GCs are not always handled correctly
tonyp
parents:
1552
diff
changeset
|
294 // Java thread is waiting for a full GC to happen (e.g., it |
4e5661ba9d98
6944166: G1: explicit GCs are not always handled correctly
tonyp
parents:
1552
diff
changeset
|
295 // called System.gc() with +ExplicitGCInvokesConcurrent). |
2030
fb712ff22571
7000559: G1: assertion failure !outer || (full_collections_started == _full_collections_completed + 1)
tonyp
parents:
1972
diff
changeset
|
296 _sts.join(); |
2152 | 297 g1h->increment_full_collections_completed(true /* concurrent */); |
2030
fb712ff22571
7000559: G1: assertion failure !outer || (full_collections_started == _full_collections_completed + 1)
tonyp
parents:
1972
diff
changeset
|
298 _sts.leave(); |
342 | 299 } |
300 assert(_should_terminate, "just checking"); | |
301 | |
302 terminate(); | |
303 } | |
304 | |
305 | |
306 void ConcurrentMarkThread::yield() { | |
307 _sts.yield("Concurrent Mark"); | |
308 } | |
309 | |
310 void ConcurrentMarkThread::stop() { | |
311 // it is ok to take late safepoints here, if needed | |
312 MutexLockerEx mu(Terminator_lock); | |
313 _should_terminate = true; | |
314 while (!_has_terminated) { | |
315 Terminator_lock->wait(); | |
316 } | |
317 } | |
318 | |
1019 | 319 void ConcurrentMarkThread::print() const { |
320 print_on(tty); | |
321 } | |
322 | |
323 void ConcurrentMarkThread::print_on(outputStream* st) const { | |
324 st->print("\"G1 Main Concurrent Mark GC Thread\" "); | |
325 Thread::print_on(st); | |
326 st->cr(); | |
342 | 327 } |
328 | |
329 void ConcurrentMarkThread::sleepBeforeNextCycle() { | |
330 // We join here because we don't want to do the "shouldConcurrentMark()" | |
331 // below while the world is otherwise stopped. | |
1840
4e0094bc41fa
6983311: G1: LoopTest hangs when run with -XX:+ExplicitInvokesConcurrent
johnc
parents:
1656
diff
changeset
|
332 assert(!in_progress(), "should have been cleared"); |
4e0094bc41fa
6983311: G1: LoopTest hangs when run with -XX:+ExplicitInvokesConcurrent
johnc
parents:
1656
diff
changeset
|
333 |
342 | 334 MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); |
335 while (!started()) { | |
336 CGC_lock->wait(Mutex::_no_safepoint_check_flag); | |
337 } | |
338 set_in_progress(); | |
339 clear_started(); | |
340 } | |
341 | |
342 // Note: this method, although exported by the ConcurrentMarkSweepThread, | |
343 // which is a non-JavaThread, can only be called by a JavaThread. | |
344 // Currently this is done at vm creation time (post-vm-init) by the | |
345 // main/Primordial (Java)Thread. | |
346 // XXX Consider changing this in the future to allow the CMS thread | |
347 // itself to create this thread? | |
348 void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) { | |
349 assert(_slt == NULL, "SLT already created"); | |
350 _slt = SurrogateLockerThread::make(THREAD); | |
351 } |