1 /*
2 * Copyright (c) 2015, 2020, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 #include "precompiled.hpp"
25 #include "gc/shared/gcId.hpp"
26 #include "gc/shared/gcLocker.hpp"
27 #include "gc/shared/isGCActiveMark.hpp"
28 #include "gc/z/zBreakpoint.hpp"
29 #include "gc/z/zCollectedHeap.hpp"
30 #include "gc/z/zDriver.hpp"
31 #include "gc/z/zHeap.inline.hpp"
32 #include "gc/z/zMessagePort.inline.hpp"
33 #include "gc/z/zServiceability.hpp"
34 #include "gc/z/zStat.hpp"
35 #include "gc/z/zVerify.hpp"
36 #include "logging/log.hpp"
37 #include "memory/universe.hpp"
38 #include "runtime/vmOperations.hpp"
39 #include "runtime/vmThread.hpp"
40
41 static const ZStatPhaseCycle ZPhaseCycle("Garbage Collection Cycle");
42 static const ZStatPhasePause ZPhasePauseMarkStart("Pause Mark Start");
43 static const ZStatPhaseConcurrent ZPhaseConcurrentMark("Concurrent Mark");
44 static const ZStatPhaseConcurrent ZPhaseConcurrentMarkContinue("Concurrent Mark Continue");
45 static const ZStatPhasePause ZPhasePauseMarkEnd("Pause Mark End");
46 static const ZStatPhaseConcurrent ZPhaseConcurrentProcessNonStrongReferences("Concurrent Process Non-Strong References");
47 static const ZStatPhaseConcurrent ZPhaseConcurrentResetRelocationSet("Concurrent Reset Relocation Set");
48 static const ZStatPhaseConcurrent ZPhaseConcurrentSelectRelocationSet("Concurrent Select Relocation Set");
49 static const ZStatPhasePause ZPhasePauseRelocateStart("Pause Relocate Start");
50 static const ZStatPhaseConcurrent ZPhaseConcurrentRelocated("Concurrent Relocate");
51 static const ZStatCriticalPhase ZCriticalPhaseGCLockerStall("GC Locker Stall", false /* verbose */);
52 static const ZStatSampler ZSamplerJavaThreads("System", "Java Threads", ZStatUnitThreads);
53
54 class VM_ZOperation : public VM_Operation {
55 private:
56 const uint _gc_id;
57 bool _gc_locked;
58 bool _success;
59
60 public:
VM_ZOperation()61 VM_ZOperation() :
62 _gc_id(GCId::current()),
63 _gc_locked(false),
64 _success(false) {}
65
needs_inactive_gc_locker() const66 virtual bool needs_inactive_gc_locker() const {
67 // An inactive GC locker is needed in operations where we change the bad
68 // mask or move objects. Changing the bad mask will invalidate all oops,
69 // which makes it conceptually the same thing as moving all objects.
70 return false;
71 }
72
73 virtual bool do_operation() = 0;
74
doit_prologue()75 virtual bool doit_prologue() {
76 Heap_lock->lock();
77 return true;
78 }
79
doit()80 virtual void doit() {
81 // Abort if GC locker state is incompatible
82 if (needs_inactive_gc_locker() && GCLocker::check_active_before_gc()) {
83 _gc_locked = true;
84 return;
85 }
86
87 // Setup GC id and active marker
88 GCIdMark gc_id_mark(_gc_id);
89 IsGCActiveMark gc_active_mark;
90
91 // Verify before operation
92 ZVerify::before_zoperation();
93
94 // Execute operation
95 _success = do_operation();
96
97 // Update statistics
98 ZStatSample(ZSamplerJavaThreads, Threads::number_of_threads());
99 }
100
doit_epilogue()101 virtual void doit_epilogue() {
102 Heap_lock->unlock();
103 }
104
gc_locked() const105 bool gc_locked() const {
106 return _gc_locked;
107 }
108
success() const109 bool success() const {
110 return _success;
111 }
112 };
113
should_clear_soft_references()114 static bool should_clear_soft_references() {
115 // Clear if one or more allocations have stalled
116 const bool stalled = ZHeap::heap()->is_alloc_stalled();
117 if (stalled) {
118 // Clear
119 return true;
120 }
121
122 // Clear if implied by the GC cause
123 const GCCause::Cause cause = ZCollectedHeap::heap()->gc_cause();
124 if (cause == GCCause::_wb_full_gc ||
125 cause == GCCause::_metadata_GC_clear_soft_refs) {
126 // Clear
127 return true;
128 }
129
130 // Don't clear
131 return false;
132 }
133
should_boost_worker_threads()134 static bool should_boost_worker_threads() {
135 // Boost worker threads if one or more allocations have stalled
136 const bool stalled = ZHeap::heap()->is_alloc_stalled();
137 if (stalled) {
138 // Boost
139 return true;
140 }
141
142 // Boost worker threads if implied by the GC cause
143 const GCCause::Cause cause = ZCollectedHeap::heap()->gc_cause();
144 if (cause == GCCause::_wb_full_gc ||
145 cause == GCCause::_java_lang_system_gc ||
146 cause == GCCause::_metadata_GC_clear_soft_refs) {
147 // Boost
148 return true;
149 }
150
151 // Don't boost
152 return false;
153 }
154
155 class VM_ZMarkStart : public VM_ZOperation {
156 public:
type() const157 virtual VMOp_Type type() const {
158 return VMOp_ZMarkStart;
159 }
160
needs_inactive_gc_locker() const161 virtual bool needs_inactive_gc_locker() const {
162 return true;
163 }
164
do_operation()165 virtual bool do_operation() {
166 ZStatTimer timer(ZPhasePauseMarkStart);
167 ZServiceabilityPauseTracer tracer;
168
169 // Set up soft reference policy
170 const bool clear = should_clear_soft_references();
171 ZHeap::heap()->set_soft_reference_policy(clear);
172
173 // Set up boost mode
174 const bool boost = should_boost_worker_threads();
175 ZHeap::heap()->set_boost_worker_threads(boost);
176
177 ZCollectedHeap::heap()->increment_total_collections(true /* full */);
178
179 ZHeap::heap()->mark_start();
180 return true;
181 }
182 };
183
184 class VM_ZMarkEnd : public VM_ZOperation {
185 public:
type() const186 virtual VMOp_Type type() const {
187 return VMOp_ZMarkEnd;
188 }
189
do_operation()190 virtual bool do_operation() {
191 ZStatTimer timer(ZPhasePauseMarkEnd);
192 ZServiceabilityPauseTracer tracer;
193 return ZHeap::heap()->mark_end();
194 }
195 };
196
197 class VM_ZRelocateStart : public VM_ZOperation {
198 public:
type() const199 virtual VMOp_Type type() const {
200 return VMOp_ZRelocateStart;
201 }
202
needs_inactive_gc_locker() const203 virtual bool needs_inactive_gc_locker() const {
204 return true;
205 }
206
do_operation()207 virtual bool do_operation() {
208 ZStatTimer timer(ZPhasePauseRelocateStart);
209 ZServiceabilityPauseTracer tracer;
210 ZHeap::heap()->relocate_start();
211 return true;
212 }
213 };
214
215 class VM_ZVerify : public VM_Operation {
216 public:
type() const217 virtual VMOp_Type type() const {
218 return VMOp_ZVerify;
219 }
220
doit()221 virtual void doit() {
222 ZVerify::after_weak_processing();
223 }
224 };
225
ZDriver()226 ZDriver::ZDriver() :
227 _gc_cycle_port(),
228 _gc_locker_port() {
229 set_name("ZDriver");
230 create_and_start();
231 }
232
collect(GCCause::Cause cause)233 void ZDriver::collect(GCCause::Cause cause) {
234 switch (cause) {
235 case GCCause::_wb_young_gc:
236 case GCCause::_wb_conc_mark:
237 case GCCause::_wb_full_gc:
238 case GCCause::_dcmd_gc_run:
239 case GCCause::_java_lang_system_gc:
240 case GCCause::_full_gc_alot:
241 case GCCause::_scavenge_alot:
242 case GCCause::_jvmti_force_gc:
243 case GCCause::_metadata_GC_clear_soft_refs:
244 // Start synchronous GC
245 _gc_cycle_port.send_sync(cause);
246 break;
247
248 case GCCause::_z_timer:
249 case GCCause::_z_warmup:
250 case GCCause::_z_allocation_rate:
251 case GCCause::_z_allocation_stall:
252 case GCCause::_z_proactive:
253 case GCCause::_z_high_usage:
254 case GCCause::_metadata_GC_threshold:
255 // Start asynchronous GC
256 _gc_cycle_port.send_async(cause);
257 break;
258
259 case GCCause::_gc_locker:
260 // Restart VM operation previously blocked by the GC locker
261 _gc_locker_port.signal();
262 break;
263
264 case GCCause::_wb_breakpoint:
265 ZBreakpoint::start_gc();
266 _gc_cycle_port.send_async(cause);
267 break;
268
269 default:
270 // Other causes not supported
271 fatal("Unsupported GC cause (%s)", GCCause::to_string(cause));
272 break;
273 }
274 }
275
276 template <typename T>
pause()277 bool ZDriver::pause() {
278 for (;;) {
279 T op;
280 VMThread::execute(&op);
281 if (op.gc_locked()) {
282 // Wait for GC to become unlocked and restart the VM operation
283 ZStatTimer timer(ZCriticalPhaseGCLockerStall);
284 _gc_locker_port.wait();
285 continue;
286 }
287
288 // Notify VM operation completed
289 _gc_locker_port.ack();
290
291 return op.success();
292 }
293 }
294
pause_mark_start()295 void ZDriver::pause_mark_start() {
296 pause<VM_ZMarkStart>();
297 }
298
concurrent_mark()299 void ZDriver::concurrent_mark() {
300 ZStatTimer timer(ZPhaseConcurrentMark);
301 ZBreakpoint::at_after_marking_started();
302 ZHeap::heap()->mark(true /* initial */);
303 ZBreakpoint::at_before_marking_completed();
304 }
305
pause_mark_end()306 bool ZDriver::pause_mark_end() {
307 return pause<VM_ZMarkEnd>();
308 }
309
concurrent_mark_continue()310 void ZDriver::concurrent_mark_continue() {
311 ZStatTimer timer(ZPhaseConcurrentMarkContinue);
312 ZHeap::heap()->mark(false /* initial */);
313 }
314
concurrent_process_non_strong_references()315 void ZDriver::concurrent_process_non_strong_references() {
316 ZStatTimer timer(ZPhaseConcurrentProcessNonStrongReferences);
317 ZHeap::heap()->process_non_strong_references();
318 }
319
concurrent_reset_relocation_set()320 void ZDriver::concurrent_reset_relocation_set() {
321 ZStatTimer timer(ZPhaseConcurrentResetRelocationSet);
322 ZHeap::heap()->reset_relocation_set();
323 }
324
pause_verify()325 void ZDriver::pause_verify() {
326 if (VerifyBeforeGC || VerifyDuringGC || VerifyAfterGC) {
327 // Full verification
328 VM_Verify op;
329 VMThread::execute(&op);
330 } else if (ZVerifyRoots || ZVerifyObjects) {
331 // Limited verification
332 VM_ZVerify op;
333 VMThread::execute(&op);
334 }
335 }
336
concurrent_select_relocation_set()337 void ZDriver::concurrent_select_relocation_set() {
338 ZStatTimer timer(ZPhaseConcurrentSelectRelocationSet);
339 ZHeap::heap()->select_relocation_set();
340 }
341
pause_relocate_start()342 void ZDriver::pause_relocate_start() {
343 pause<VM_ZRelocateStart>();
344 }
345
concurrent_relocate()346 void ZDriver::concurrent_relocate() {
347 ZStatTimer timer(ZPhaseConcurrentRelocated);
348 ZHeap::heap()->relocate();
349 }
350
check_out_of_memory()351 void ZDriver::check_out_of_memory() {
352 ZHeap::heap()->check_out_of_memory();
353 }
354
355 class ZDriverGCScope : public StackObj {
356 private:
357 GCIdMark _gc_id;
358 GCCause::Cause _gc_cause;
359 GCCauseSetter _gc_cause_setter;
360 ZStatTimer _timer;
361 ZServiceabilityCycleTracer _tracer;
362
363 public:
ZDriverGCScope(GCCause::Cause cause)364 ZDriverGCScope(GCCause::Cause cause) :
365 _gc_id(),
366 _gc_cause(cause),
367 _gc_cause_setter(ZCollectedHeap::heap(), cause),
368 _timer(ZPhaseCycle),
369 _tracer() {
370 // Update statistics
371 ZStatCycle::at_start();
372 }
373
~ZDriverGCScope()374 ~ZDriverGCScope() {
375 // Calculate boost factor
376 const double boost_factor = (double)ZHeap::heap()->nconcurrent_worker_threads() /
377 (double)ZHeap::heap()->nconcurrent_no_boost_worker_threads();
378
379 // Update statistics
380 ZStatCycle::at_end(_gc_cause, boost_factor);
381
382 // Update data used by soft reference policy
383 Universe::update_heap_info_at_gc();
384 }
385 };
386
gc(GCCause::Cause cause)387 void ZDriver::gc(GCCause::Cause cause) {
388 ZDriverGCScope scope(cause);
389
390 // Phase 1: Pause Mark Start
391 pause_mark_start();
392
393 // Phase 2: Concurrent Mark
394 concurrent_mark();
395
396 // Phase 3: Pause Mark End
397 while (!pause_mark_end()) {
398 // Phase 3.5: Concurrent Mark Continue
399 concurrent_mark_continue();
400 }
401
402 // Phase 4: Concurrent Process Non-Strong References
403 concurrent_process_non_strong_references();
404
405 // Phase 5: Concurrent Reset Relocation Set
406 concurrent_reset_relocation_set();
407
408 // Phase 6: Pause Verify
409 pause_verify();
410
411 // Phase 7: Concurrent Select Relocation Set
412 concurrent_select_relocation_set();
413
414 // Phase 8: Pause Relocate Start
415 pause_relocate_start();
416
417 // Phase 9: Concurrent Relocate
418 concurrent_relocate();
419 }
420
run_service()421 void ZDriver::run_service() {
422 // Main loop
423 while (!should_terminate()) {
424 // Wait for GC request
425 const GCCause::Cause cause = _gc_cycle_port.receive();
426 if (cause == GCCause::_no_gc) {
427 continue;
428 }
429
430 ZBreakpoint::at_before_gc();
431
432 // Run GC
433 gc(cause);
434
435 // Notify GC completed
436 _gc_cycle_port.ack();
437
438 // Check for out of memory condition
439 check_out_of_memory();
440
441 ZBreakpoint::at_after_gc();
442 }
443 }
444
stop_service()445 void ZDriver::stop_service() {
446 _gc_cycle_port.send_async(GCCause::_no_gc);
447 }
448