1 /*
2 * Copyright (c) 2017, 2021, Red Hat, Inc. All rights reserved.
3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP
27 #define SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP
28
29 #include "gc/shared/gcCause.hpp"
30 #include "gc/shared/gcTraceTime.inline.hpp"
31 #include "gc/shared/gcVMOperations.hpp"
32 #include "gc/shared/isGCActiveMark.hpp"
33 #include "gc/shared/suspendibleThreadSet.hpp"
34 #include "gc/shared/workerThread.hpp"
35 #include "gc/shenandoah/shenandoahPhaseTimings.hpp"
36 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
37 #include "jfr/jfrEvents.hpp"
38 #include "memory/allocation.hpp"
39 #include "runtime/safepoint.hpp"
40 #include "runtime/vmOperations.hpp"
41 #include "runtime/vmThread.hpp"
42 #include "services/memoryService.hpp"
43
44 #include <cmath>
45 #include <limits>
46
47 class GCTimer;
48 class ShenandoahGeneration;
49
50 #define SHENANDOAH_RETURN_EVENT_MESSAGE(generation_type, prefix, postfix) \
51 switch (generation_type) { \
52 case NON_GEN: \
53 return prefix postfix; \
54 case GLOBAL: \
55 return prefix " (Global)" postfix; \
56 case YOUNG: \
57 return prefix " (Young)" postfix; \
58 case OLD: \
59 return prefix " (Old)" postfix; \
60 default: \
61 ShouldNotReachHere(); \
62 return prefix " (Unknown)" postfix; \
63 } \
64
65 class ShenandoahGCSession : public StackObj {
66 private:
67 ShenandoahHeap* const _heap;
68 ShenandoahGeneration* const _generation;
69 GCTimer* const _timer;
70 GCTracer* const _tracer;
71
72 TraceMemoryManagerStats _trace_cycle;
73
74 static const char* cycle_end_message(ShenandoahGenerationType type);
75 public:
76 ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation,
77 bool is_degenerated = false, bool is_out_of_cycle = false);
78 ~ShenandoahGCSession();
79 };
80
81 /*
82 * ShenandoahGCPhaseTiming tracks Shenandoah specific timing information
83 * of a GC phase
84 */
85 class ShenandoahTimingsTracker : public StackObj {
86 private:
87 static ShenandoahPhaseTimings::Phase _current_phase;
88
89 ShenandoahPhaseTimings* const _timings;
90 const ShenandoahPhaseTimings::Phase _phase;
91 const bool _should_aggregate;
92 ShenandoahPhaseTimings::Phase _parent_phase;
93 double _start;
94
95 public:
96 ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase, bool should_aggregate = false);
97 ~ShenandoahTimingsTracker();
98
99 static ShenandoahPhaseTimings::Phase current_phase() {
100 assert(is_current_phase_valid(), "Current phase is not valid");
101 return _current_phase;
102 }
103
104 static bool is_current_phase_valid();
105 };
106
107 /*
108 * ShenandoahPausePhase tracks a STW pause and emits Shenandoah timing and
109 * a corresponding JFR event
110 */
111 class ShenandoahPausePhase : public ShenandoahTimingsTracker {
112 private:
113 GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
114 ConcurrentGCTimer* const _timer;
115
116 public:
117 ShenandoahPausePhase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
118 ~ShenandoahPausePhase();
119 };
120
121 /*
122 * ShenandoahConcurrentPhase tracks a concurrent GC phase and emits Shenandoah timing and
123 * a corresponding JFR event
124 */
125 class ShenandoahConcurrentPhase : public ShenandoahTimingsTracker {
126 private:
127 GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
128 ConcurrentGCTimer* const _timer;
129
130 public:
131 ShenandoahConcurrentPhase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
132 ~ShenandoahConcurrentPhase();
133 };
134
135 /*
136 * ShenandoahGCPhase tracks Shenandoah specific timing information
137 * and emits a corresponding JFR event of a GC phase
138 */
139 class ShenandoahGCPhase : public ShenandoahTimingsTracker {
140 private:
141 ConcurrentGCTimer* const _timer;
142
143 public:
144 ShenandoahGCPhase(ShenandoahPhaseTimings::Phase phase);
145 ~ShenandoahGCPhase();
146 };
147
148 class ShenandoahGCWorkerPhase : public StackObj {
149 private:
150 ShenandoahPhaseTimings* const _timings;
151 const ShenandoahPhaseTimings::Phase _phase;
152 public:
153 ShenandoahGCWorkerPhase(ShenandoahPhaseTimings::Phase phase);
154 ~ShenandoahGCWorkerPhase();
155 };
156
157 // Aggregates all the things that should happen before/after the pause.
158 class ShenandoahGCPauseMark : public StackObj {
159 private:
160 ShenandoahHeap* const _heap;
161 const GCIdMark _gc_id_mark;
162 const SvcGCMarker _svc_gc_mark;
163 const IsSTWGCActiveMark _is_gc_active_mark;
164 TraceMemoryManagerStats _trace_pause;
165
166 public:
167 ShenandoahGCPauseMark(uint gc_id, const char* notification_action, SvcGCMarker::reason_type type);
168 };
169
170 class ShenandoahSafepoint : public AllStatic {
171 public:
172 // Check if Shenandoah GC safepoint is in progress. This is nominally
173 // equivalent to calling SafepointSynchronize::is_at_safepoint(), but
174 // it also checks the Shenandoah specifics, when it can.
175 static inline bool is_at_shenandoah_safepoint() {
176 if (!SafepointSynchronize::is_at_safepoint()) return false;
177
178 Thread* const thr = Thread::current();
179 // Shenandoah GC specific safepoints are scheduled by control thread.
180 // So if we are enter here from control thread, then we are definitely not
181 // at Shenandoah safepoint, but at something else.
182 if (thr == ShenandoahHeap::heap()->control_thread()) return false;
183
184 // This is not VM thread, cannot see what VM thread is doing,
185 // so pretend this is a proper Shenandoah safepoint
186 if (!thr->is_VM_thread()) return true;
187
188 // Otherwise check we are at proper operation type
189 VM_Operation* vm_op = VMThread::vm_operation();
190 if (vm_op == nullptr) return false;
191
192 VM_Operation::VMOp_Type type = vm_op->type();
193 return type == VM_Operation::VMOp_ShenandoahInitMark ||
194 type == VM_Operation::VMOp_ShenandoahFinalMarkStartEvac ||
195 type == VM_Operation::VMOp_ShenandoahInitUpdateRefs ||
196 type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs ||
197 type == VM_Operation::VMOp_ShenandoahFinalRoots ||
198 type == VM_Operation::VMOp_ShenandoahFullGC ||
199 type == VM_Operation::VMOp_ShenandoahDegeneratedGC;
200 }
201 };
202
203 class ShenandoahWorkerSession : public StackObj {
204 protected:
205 ShenandoahWorkerSession(uint worker_id);
206 public:
207 static inline uint worker_id() {
208 return WorkerThread::worker_id();
209 }
210 };
211
212 class ShenandoahConcurrentWorkerSession : public ShenandoahWorkerSession {
213 private:
214 EventGCPhaseConcurrent _event;
215
216 public:
217 ShenandoahConcurrentWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
218 ~ShenandoahConcurrentWorkerSession();
219 };
220
221 class ShenandoahParallelWorkerSession : public ShenandoahWorkerSession {
222 private:
223 EventGCPhaseParallel _event;
224
225 public:
226 ShenandoahParallelWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
227 ~ShenandoahParallelWorkerSession();
228 };
229
230 // Regions cannot be uncommitted when concurrent reset is zeroing out the bitmaps.
231 // This CADR class enforces this by forbidding region uncommits while it is in scope.
232 class ShenandoahNoUncommitMark : public StackObj {
233 ShenandoahHeap* const _heap;
234 public:
235 explicit ShenandoahNoUncommitMark(ShenandoahHeap* heap) : _heap(heap) {
236 _heap->forbid_uncommit();
237 }
238
239 ~ShenandoahNoUncommitMark() {
240 _heap->allow_uncommit();
241 }
242 };
243
244 // Casting a double that cannot be represented as a size_t may result in undefined behavior.
245 // This small function checks if the given double is representable in a size_t and returns
246 // that representation if it is. Otherwise, if the double cannot be safely cast to a size_t
247 // it returns zero.
248 inline size_t shenandoah_safe_size_cast(const double d) {
249 static constexpr double size_max_as_double = static_cast<double>(std::numeric_limits<size_t>::max());
250 if (std::isnan(d) || d < 0 || d >= size_max_as_double) {
251 // NaN is unordered, all comparisons will be false.
252 // +Inf is always greater than, -Inf is always less than
253 return 0;
254 }
255 return static_cast<size_t>(d);
256 }
257
258
259
260 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP