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