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