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