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/workerThread.hpp"
34 #include "gc/shenandoah/shenandoahGenerationType.hpp"
35 #include "gc/shenandoah/shenandoahHeap.hpp"
36 #include "gc/shenandoah/shenandoahPhaseTimings.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 #include "utilities/globalDefinitions.hpp"
44
45 #include <cmath>
46 #include <limits>
47
48 class GCTimer;
49 class ShenandoahGeneration;
50
51 #define SHENANDOAH_EVENT_MESSAGE(loc, generation_type, prefix, postfix) \
52 const char* loc; \
53 switch (generation_type) { \
54 case NON_GEN: \
55 loc = prefix postfix; \
56 break; \
57 case GLOBAL: \
58 loc = prefix " (Global)" postfix; \
59 break; \
60 case YOUNG: \
61 loc = prefix " (Young)" postfix; \
62 break; \
63 case OLD: \
64 loc = prefix " (Old)" postfix; \
65 break; \
66 default: \
67 ShouldNotReachHere(); \
68 loc = prefix " (Unknown)" postfix; \
69 } \
70
71 class ShenandoahGCSession : public StackObj {
72 private:
73 ShenandoahHeap* const _heap;
74 ShenandoahGeneration* const _generation;
75 GCTimer* const _timer;
76 GCTracer* const _tracer;
77
78 TraceMemoryManagerStats _trace_cycle;
79
80 static const char* cycle_end_message(ShenandoahGenerationType type);
81 public:
82 ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation,
83 bool is_degenerated = false, bool is_out_of_cycle = false);
84 ~ShenandoahGCSession();
85 };
86
87 /*
88 * ShenandoahGCPhaseTiming tracks Shenandoah specific timing information
89 * of a GC phase
90 */
91 class ShenandoahTimingsTracker : public StackObj {
92 private:
93 static ShenandoahPhaseTimings::Phase _current_phase;
94
95 ShenandoahPhaseTimings* const _timings;
96 const ShenandoahPhaseTimings::Phase _phase;
97 const bool _should_aggregate;
98 ShenandoahPhaseTimings::Phase _parent_phase;
99 double _start;
100
101 public:
102 ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase, bool should_aggregate = false);
103 ~ShenandoahTimingsTracker();
104
105 static ShenandoahPhaseTimings::Phase current_phase() { return _current_phase; }
106
107 static bool is_current_phase_valid();
108 };
109
110 /*
111 * ShenandoahPauseSubphase tracks a STW pause and emits Shenandoah timing and
112 * a corresponding JFR event
113 */
114 class ShenandoahPauseSubphase : public ShenandoahTimingsTracker {
115 private:
116 GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
117 ConcurrentGCTimer* const _timer;
118
119 public:
120 ShenandoahPauseSubphase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
121 ~ShenandoahPauseSubphase();
122 };
123
124 /*
125 * ShenandoahConcurrentSubphase tracks a concurrent GC phase and emits Shenandoah timing and
126 * a corresponding JFR event
127 */
128 class ShenandoahConcurrentSubphase : public ShenandoahTimingsTracker {
129 private:
130 GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc, phases)> _tracer;
131 ConcurrentGCTimer* const _timer;
132
133 public:
134 ShenandoahConcurrentSubphase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
135 ~ShenandoahConcurrentSubphase();
136 };
137
138 /*
139 * ShenandoahPausePhase tracks a pause GC phase and emits Shenandoah timing and
140 * a corresponding JFR event
141 */
142 class ShenandoahPausePhase : public ShenandoahTimingsTracker {
143 private:
144 GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
145 ConcurrentGCTimer* const _timer;
146
147 public:
148 ShenandoahPausePhase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
149 ~ShenandoahPausePhase();
150 };
151
152 /*
153 * ShenandoahConcurrentPhase tracks a concurrent GC phase and emits Shenandoah timing and
154 * a corresponding JFR event
155 */
156 class ShenandoahConcurrentPhase : public ShenandoahTimingsTracker {
157 private:
158 GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
159 ConcurrentGCTimer* const _timer;
160
161 public:
162 ShenandoahConcurrentPhase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
163 ~ShenandoahConcurrentPhase();
164 };
165
166 /*
167 * ShenandoahGCPhase tracks Shenandoah specific timing information
168 * and emits a corresponding JFR event of a GC phase
169 */
170 class ShenandoahGCPhase : public ShenandoahTimingsTracker {
171 private:
172 ConcurrentGCTimer* const _timer;
173
174 public:
175 ShenandoahGCPhase(ShenandoahPhaseTimings::Phase phase);
176 ~ShenandoahGCPhase();
177 };
178
179 class ShenandoahGCWorkerPhase : public StackObj {
180 private:
181 ShenandoahPhaseTimings* const _timings;
182 const ShenandoahPhaseTimings::Phase _phase;
183 public:
184 ShenandoahGCWorkerPhase(ShenandoahPhaseTimings::Phase phase);
185 ~ShenandoahGCWorkerPhase();
186 };
187
188 // Aggregates all the things that should happen before/after the pause.
189 class ShenandoahGCPauseMark : public StackObj {
190 private:
191 ShenandoahHeap* const _heap;
192 const GCIdMark _gc_id_mark;
193 const SvcGCMarker _svc_gc_mark;
194 const IsSTWGCActiveMark _is_gc_active_mark;
195 TraceMemoryManagerStats _trace_pause;
196
197 public:
198 ShenandoahGCPauseMark(uint gc_id, const char* notification_action, SvcGCMarker::reason_type type);
199 };
200
201 class ShenandoahSafepoint : public AllStatic {
202 public:
203 // Check if Shenandoah GC safepoint is in progress. This is nominally
204 // equivalent to calling SafepointSynchronize::is_at_safepoint(), but
205 // it also checks the Shenandoah specifics, when it can.
206 static inline bool is_at_shenandoah_safepoint() {
207 if (!SafepointSynchronize::is_at_safepoint()) return false;
208
209 Thread* const thr = Thread::current();
210 // Shenandoah GC specific safepoints are scheduled by control thread.
211 // So if we are enter here from control thread, then we are definitely not
212 // at Shenandoah safepoint, but at something else.
213 if (thr == ShenandoahHeap::heap()->control_thread()) return false;
214
215 // This is not VM thread, cannot see what VM thread is doing,
216 // so pretend this is a proper Shenandoah safepoint
217 if (!thr->is_VM_thread()) return true;
218
219 // Otherwise check we are at proper operation type
220 VM_Operation* vm_op = VMThread::vm_operation();
221 if (vm_op == nullptr) return false;
222
223 VM_Operation::VMOp_Type type = vm_op->type();
224 return type == VM_Operation::VMOp_ShenandoahInitMark ||
225 type == VM_Operation::VMOp_ShenandoahFinalMarkStartEvac ||
226 type == VM_Operation::VMOp_ShenandoahInitUpdateRefs ||
227 type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs ||
228 type == VM_Operation::VMOp_ShenandoahFinalVerify ||
229 type == VM_Operation::VMOp_ShenandoahFullGC ||
230 type == VM_Operation::VMOp_ShenandoahDegeneratedGC;
231 }
232 };
233
234 class ShenandoahWorkerSession : public StackObj {
235 protected:
236 ShenandoahWorkerSession(uint worker_id);
237 public:
238 static inline uint worker_id() {
239 return WorkerThread::worker_id();
240 }
241 };
242
243 class ShenandoahConcurrentWorkerSession : public ShenandoahWorkerSession {
244 private:
245 EventGCPhaseConcurrent _event;
246
247 public:
248 ShenandoahConcurrentWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
249 ~ShenandoahConcurrentWorkerSession();
250 };
251
252 class ShenandoahParallelWorkerSession : public ShenandoahWorkerSession {
253 private:
254 EventGCPhaseParallel _event;
255
256 public:
257 ShenandoahParallelWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
258 ~ShenandoahParallelWorkerSession();
259 };
260
261 // Regions cannot be uncommitted when concurrent reset is zeroing out the bitmaps.
262 // This CADR class enforces this by forbidding region uncommits while it is in scope.
263 class ShenandoahNoUncommitMark : public StackObj {
264 ShenandoahHeap* const _heap;
265 public:
266 explicit ShenandoahNoUncommitMark(ShenandoahHeap* heap) : _heap(heap) {
267 _heap->forbid_uncommit();
268 }
269
270 ~ShenandoahNoUncommitMark() {
271 _heap->allow_uncommit();
272 }
273 };
274
275 // Casting a double that cannot be represented as a size_t may result in undefined behavior.
276 // This small function checks if the given double is representable in a size_t and returns
277 // that representation if it is. Otherwise, if the double cannot be safely cast to a size_t
278 // it returns zero.
279 inline size_t shenandoah_safe_size_cast(const double d) {
280 static constexpr double size_max_as_double = static_cast<double>(std::numeric_limits<size_t>::max());
281 if (std::isnan(d) || d < 0 || d >= size_max_as_double) {
282 // NaN is unordered, all comparisons will be false.
283 // +Inf is always greater than, -Inf is always less than
284 return 0;
285 }
286 return static_cast<size_t>(d);
287 }
288
289 // Convert a possibly signed double into a smaller number with appropriate engineering units.
290 struct ShenandoahSignedSize {
291 const double value;
292 const char* unit;
293
294 static ShenandoahSignedSize get(double v) {
295 if (!std::isfinite(v)) {
296 return { v, "B" };
297 }
298
299 const double magnitude = fabsd(v);
300
301 if (magnitude >= 100.0 * G) {
302 return { std::copysign(magnitude / G, v), "G" };
303 }
304
305 if (magnitude >= 100.0 * M) {
306 return { std::copysign(magnitude / M, v), "M" };
307 }
308
309 if (magnitude >= 100.0 * K) {
310 return { std::copysign(magnitude / K, v), "K" };
311 }
312
313 return { std::copysign(magnitude, v), "B" };
314 }
315 };
316
317 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP