Mercurial > hg > truffle
annotate src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp @ 2030:fb712ff22571
7000559: G1: assertion failure !outer || (full_collections_started == _full_collections_completed + 1)
Summary: The concurrent marking thread can complete its operation and increment the full GC counter during a Full GC. This causes the nesting of increments to the start and end of Full GCs that we are expecting to be wrong. the fix is for the marking thread to join the suspendible thread set before incrementing the counter so that it's blocked until the Full GC (or any other safepoint) is finished. The change also includes some minor code cleanup (I renamed a parameter).
Reviewed-by: brutisso, ysr
author | tonyp |
---|---|
date | Tue, 14 Dec 2010 16:19:44 -0500 |
parents | f95d63e2154a |
children | 0fa27f37d4d4 |
rev | line source |
---|---|
342 | 1 /* |
1972 | 2 * Copyright (c) 2001, 2010, 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 | |
98 G1CollectedHeap* g1 = G1CollectedHeap::heap(); | |
99 G1CollectorPolicy* g1_policy = g1->g1_policy(); | |
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 | |
122 g1->set_marking_complete(); | |
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 { | |
231 G1CollectedHeap::heap()->set_marking_complete(); | |
232 } | |
233 | |
234 if (!cm()->has_aborted()) { | |
235 double cleanup_start_sec = os::elapsedTime(); | |
236 if (PrintGC) { | |
237 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
238 gclog_or_tty->stamp(PrintGCTimeStamps); | |
239 gclog_or_tty->print_cr("[GC concurrent-cleanup-start]"); | |
240 } | |
241 | |
242 // Now do the remainder of the cleanup operation. | |
243 _sts.join(); | |
244 _cm->completeCleanup(); | |
245 if (!cm()->has_aborted()) { | |
246 g1_policy->record_concurrent_mark_cleanup_completed(); | |
247 | |
248 double cleanup_end_sec = os::elapsedTime(); | |
249 if (PrintGC) { | |
250 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
251 gclog_or_tty->stamp(PrintGCTimeStamps); | |
252 gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf]", | |
253 cleanup_end_sec - cleanup_start_sec); | |
254 } | |
255 } | |
256 _sts.leave(); | |
257 } | |
258 // We're done: no more unclean regions coming. | |
259 G1CollectedHeap::heap()->set_unclean_regions_coming(false); | |
260 | |
261 if (cm()->has_aborted()) { | |
262 if (PrintGC) { | |
263 gclog_or_tty->date_stamp(PrintGCDateStamps); | |
264 gclog_or_tty->stamp(PrintGCTimeStamps); | |
265 gclog_or_tty->print_cr("[GC concurrent-mark-abort]"); | |
266 } | |
267 } | |
268 | |
269 // we now want to allow clearing of the marking bitmap to be | |
270 // suspended by a collection pause. | |
271 _sts.join(); | |
272 _cm->clearNextBitmap(); | |
273 _sts.leave(); | |
274 } | |
1656
4e5661ba9d98
6944166: G1: explicit GCs are not always handled correctly
tonyp
parents:
1552
diff
changeset
|
275 |
4e5661ba9d98
6944166: G1: explicit GCs are not always handled correctly
tonyp
parents:
1552
diff
changeset
|
276 // Update the number of full collections that have been |
4e5661ba9d98
6944166: G1: explicit GCs are not always handled correctly
tonyp
parents:
1552
diff
changeset
|
277 // 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
|
278 // 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
|
279 // called System.gc() with +ExplicitGCInvokesConcurrent). |
2030
fb712ff22571
7000559: G1: assertion failure !outer || (full_collections_started == _full_collections_completed + 1)
tonyp
parents:
1972
diff
changeset
|
280 _sts.join(); |
fb712ff22571
7000559: G1: assertion failure !outer || (full_collections_started == _full_collections_completed + 1)
tonyp
parents:
1972
diff
changeset
|
281 g1->increment_full_collections_completed(true /* concurrent */); |
fb712ff22571
7000559: G1: assertion failure !outer || (full_collections_started == _full_collections_completed + 1)
tonyp
parents:
1972
diff
changeset
|
282 _sts.leave(); |
342 | 283 } |
284 assert(_should_terminate, "just checking"); | |
285 | |
286 terminate(); | |
287 } | |
288 | |
289 | |
290 void ConcurrentMarkThread::yield() { | |
291 _sts.yield("Concurrent Mark"); | |
292 } | |
293 | |
294 void ConcurrentMarkThread::stop() { | |
295 // it is ok to take late safepoints here, if needed | |
296 MutexLockerEx mu(Terminator_lock); | |
297 _should_terminate = true; | |
298 while (!_has_terminated) { | |
299 Terminator_lock->wait(); | |
300 } | |
301 } | |
302 | |
1019 | 303 void ConcurrentMarkThread::print() const { |
304 print_on(tty); | |
305 } | |
306 | |
307 void ConcurrentMarkThread::print_on(outputStream* st) const { | |
308 st->print("\"G1 Main Concurrent Mark GC Thread\" "); | |
309 Thread::print_on(st); | |
310 st->cr(); | |
342 | 311 } |
312 | |
313 void ConcurrentMarkThread::sleepBeforeNextCycle() { | |
314 // We join here because we don't want to do the "shouldConcurrentMark()" | |
315 // below while the world is otherwise stopped. | |
1840
4e0094bc41fa
6983311: G1: LoopTest hangs when run with -XX:+ExplicitInvokesConcurrent
johnc
parents:
1656
diff
changeset
|
316 assert(!in_progress(), "should have been cleared"); |
4e0094bc41fa
6983311: G1: LoopTest hangs when run with -XX:+ExplicitInvokesConcurrent
johnc
parents:
1656
diff
changeset
|
317 |
342 | 318 MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); |
319 while (!started()) { | |
320 CGC_lock->wait(Mutex::_no_safepoint_check_flag); | |
321 } | |
322 set_in_progress(); | |
323 clear_started(); | |
324 } | |
325 | |
326 // Note: this method, although exported by the ConcurrentMarkSweepThread, | |
327 // which is a non-JavaThread, can only be called by a JavaThread. | |
328 // Currently this is done at vm creation time (post-vm-init) by the | |
329 // main/Primordial (Java)Thread. | |
330 // XXX Consider changing this in the future to allow the CMS thread | |
331 // itself to create this thread? | |
332 void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) { | |
333 assert(_slt == NULL, "SLT already created"); | |
334 _slt = SurrogateLockerThread::make(THREAD); | |
335 } |