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_ShenandoahFinalRoots ||
227            type == VM_Operation::VMOp_ShenandoahInitUpdateRefs ||
228            type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs ||
229            type == VM_Operation::VMOp_ShenandoahFinalVerify ||
230            type == VM_Operation::VMOp_ShenandoahFullGC ||
231            type == VM_Operation::VMOp_ShenandoahDegeneratedGC;
232   }
233 };
234 
235 class ShenandoahWorkerSession : public StackObj {
236 protected:
237   ShenandoahWorkerSession(uint worker_id);
238 public:
239   static inline uint worker_id() {
240     return WorkerThread::worker_id();
241   }
242 };
243 
244 class ShenandoahConcurrentWorkerSession : public ShenandoahWorkerSession {
245 private:
246   EventGCPhaseConcurrent _event;
247 
248 public:
249   ShenandoahConcurrentWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
250   ~ShenandoahConcurrentWorkerSession();
251 };
252 
253 class ShenandoahParallelWorkerSession : public ShenandoahWorkerSession {
254 private:
255   EventGCPhaseParallel _event;
256 
257 public:
258   ShenandoahParallelWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
259   ~ShenandoahParallelWorkerSession();
260 };
261 
262 // Regions cannot be uncommitted when concurrent reset is zeroing out the bitmaps.
263 // This CADR class enforces this by forbidding region uncommits while it is in scope.
264 class ShenandoahNoUncommitMark : public StackObj {
265   ShenandoahHeap* const _heap;
266 public:
267   explicit ShenandoahNoUncommitMark(ShenandoahHeap* heap) : _heap(heap) {
268     _heap->forbid_uncommit();
269   }
270 
271   ~ShenandoahNoUncommitMark() {
272     _heap->allow_uncommit();
273   }
274 };
275 
276 // Casting a double that cannot be represented as a size_t may result in undefined behavior.
277 // This small function checks if the given double is representable in a size_t and returns
278 // that representation if it is. Otherwise, if the double cannot be safely cast to a size_t
279 // it returns zero.
280 inline size_t shenandoah_safe_size_cast(const double d) {
281   static constexpr double size_max_as_double = static_cast<double>(std::numeric_limits<size_t>::max());
282   if (std::isnan(d) || d < 0 || d >= size_max_as_double) {
283     // NaN is unordered, all comparisons will be false.
284     // +Inf is always greater than, -Inf is always less than
285     return 0;
286   }
287   return static_cast<size_t>(d);
288 }
289 
290 // Convert a possibly signed double into a smaller number with appropriate engineering units.
291 struct ShenandoahSignedSize {
292   const double value;
293   const char* unit;
294 
295   static ShenandoahSignedSize get(double v) {
296     if (!std::isfinite(v)) {
297       return { v, "B" };
298     }
299 
300     const double magnitude = fabsd(v);
301 
302     if (magnitude >= 100.0 * G) {
303       return { std::copysign(magnitude / G, v), "G" };
304     }
305 
306     if (magnitude >= 100.0 * M) {
307       return { std::copysign(magnitude / M, v), "M" };
308     }
309 
310     if (magnitude >= 100.0 * K) {
311       return { std::copysign(magnitude / K, v), "K" };
312     }
313 
314     return { std::copysign(magnitude, v), "B" };
315   }
316 };
317 
318 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP