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/vmThread.hpp"
 41 #include "runtime/vmOperations.hpp"
 42 #include "services/memoryService.hpp"
 43 
 44 class GCTimer;
 45 class ShenandoahGeneration;
 46 
 47 #define SHENANDOAH_RETURN_EVENT_MESSAGE(generation_type, prefix, postfix) \
 48   switch (generation_type) {                                              \
 49     case NON_GEN:                                                         \
 50       return prefix " (NON-GENERATIONAL)" postfix;                        \
 51     case GLOBAL:                                                          \
 52       return prefix " (GLOBAL)" postfix;                                  \
 53     case YOUNG:                                                           \
 54       return prefix " (YOUNG)" postfix;                                   \
 55     case OLD:                                                             \
 56       return prefix " (OLD)" postfix;                                     \
 57     default:                                                              \
 58       ShouldNotReachHere();                                               \
 59       return prefix " (UNKNOWN)" postfix;                                 \
 60   }                                                                       \
 61 
 62 class ShenandoahGCSession : public StackObj {
 63 private:
 64   ShenandoahHeap* const _heap;
 65   ShenandoahGeneration* const _generation;
 66   GCTimer*  const _timer;
 67   GCTracer* const _tracer;
 68 
 69   TraceMemoryManagerStats _trace_cycle;
 70 public:
 71   ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation);
 72   ~ShenandoahGCSession();
 73 };
 74 
 75 /*
 76  * ShenandoahGCPhaseTiming tracks Shenandoah specific timing information
 77  * of a GC phase
 78  */
 79 class ShenandoahTimingsTracker : public StackObj {
 80 private:
 81   static ShenandoahPhaseTimings::Phase  _current_phase;
 82 
 83   ShenandoahPhaseTimings* const         _timings;
 84   const ShenandoahPhaseTimings::Phase   _phase;
 85   const bool                            _should_aggregate;
 86   ShenandoahPhaseTimings::Phase         _parent_phase;
 87   double _start;
 88 
 89 public:
 90   ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase, bool should_aggregate = false);
 91   ~ShenandoahTimingsTracker();
 92 
 93   static ShenandoahPhaseTimings::Phase current_phase() { return _current_phase; }
 94 
 95   static bool is_current_phase_valid();
 96 };
 97 
 98 /*
 99  * ShenandoahPausePhase tracks a STW pause and emits Shenandoah timing and
100  * a corresponding JFR event
101  */
102 class ShenandoahPausePhase : public ShenandoahTimingsTracker {
103 private:
104   GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
105   ConcurrentGCTimer* const _timer;
106 
107 public:
108   ShenandoahPausePhase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
109   ~ShenandoahPausePhase();
110 };
111 
112 /*
113  * ShenandoahConcurrentPhase tracks a concurrent GC phase and emits Shenandoah timing and
114  * a corresponding JFR event
115  */
116 class ShenandoahConcurrentPhase : public ShenandoahTimingsTracker {
117 private:
118   GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
119   ConcurrentGCTimer* const _timer;
120 
121 public:
122   ShenandoahConcurrentPhase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
123   ~ShenandoahConcurrentPhase();
124 };
125 
126 /*
127  * ShenandoahGCPhase tracks Shenandoah specific timing information
128  * and emits a corresponding JFR event of a GC phase
129  */
130 class ShenandoahGCPhase : public ShenandoahTimingsTracker {
131 private:
132   ConcurrentGCTimer* const _timer;
133 
134 public:
135   ShenandoahGCPhase(ShenandoahPhaseTimings::Phase phase);
136   ~ShenandoahGCPhase();
137 };
138 
139 class ShenandoahGCWorkerPhase : public StackObj {
140 private:
141   ShenandoahPhaseTimings* const       _timings;
142   const ShenandoahPhaseTimings::Phase _phase;
143 public:
144   ShenandoahGCWorkerPhase(ShenandoahPhaseTimings::Phase phase);
145   ~ShenandoahGCWorkerPhase();
146 };
147 
148 // Aggregates all the things that should happen before/after the pause.
149 class ShenandoahGCPauseMark : public StackObj {
150 private:
151   ShenandoahHeap* const _heap;
152   const GCIdMark                _gc_id_mark;
153   const SvcGCMarker             _svc_gc_mark;
154   const IsSTWGCActiveMark       _is_gc_active_mark;
155   TraceMemoryManagerStats       _trace_pause;
156 
157 public:
158   ShenandoahGCPauseMark(uint gc_id, const char* notification_action, SvcGCMarker::reason_type type);
159 };
160 
161 class ShenandoahSafepoint : public AllStatic {
162 public:
163   // Check if Shenandoah GC safepoint is in progress. This is nominally
164   // equivalent to calling SafepointSynchronize::is_at_safepoint(), but
165   // it also checks the Shenandoah specifics, when it can.
166   static inline bool is_at_shenandoah_safepoint() {
167     if (!SafepointSynchronize::is_at_safepoint()) return false;
168 
169     Thread* const thr = Thread::current();
170     // Shenandoah GC specific safepoints are scheduled by control thread.
171     // So if we are enter here from control thread, then we are definitely not
172     // at Shenandoah safepoint, but at something else.
173     if (thr == ShenandoahHeap::heap()->control_thread()) return false;
174 
175     // This is not VM thread, cannot see what VM thread is doing,
176     // so pretend this is a proper Shenandoah safepoint
177     if (!thr->is_VM_thread()) return true;
178 
179     // Otherwise check we are at proper operation type
180     VM_Operation* vm_op = VMThread::vm_operation();
181     if (vm_op == nullptr) return false;
182 
183     VM_Operation::VMOp_Type type = vm_op->type();
184     return type == VM_Operation::VMOp_ShenandoahInitMark ||
185            type == VM_Operation::VMOp_ShenandoahFinalMarkStartEvac ||
186            type == VM_Operation::VMOp_ShenandoahInitUpdateRefs ||
187            type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs ||
188            type == VM_Operation::VMOp_ShenandoahFinalRoots ||
189            type == VM_Operation::VMOp_ShenandoahFullGC ||
190            type == VM_Operation::VMOp_ShenandoahDegeneratedGC;
191   }
192 };
193 
194 class ShenandoahWorkerSession : public StackObj {
195 protected:
196   ShenandoahWorkerSession(uint worker_id);
197 public:
198   static inline uint worker_id() {
199     return WorkerThread::worker_id();
200   }
201 };
202 
203 class ShenandoahConcurrentWorkerSession : public ShenandoahWorkerSession {
204 private:
205   EventGCPhaseConcurrent _event;
206 
207 public:
208   ShenandoahConcurrentWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
209   ~ShenandoahConcurrentWorkerSession();
210 };
211 
212 class ShenandoahParallelWorkerSession : public ShenandoahWorkerSession {
213 private:
214   EventGCPhaseParallel _event;
215 
216 public:
217   ShenandoahParallelWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
218   ~ShenandoahParallelWorkerSession();
219 };
220 
221 class ShenandoahSuspendibleThreadSetJoiner {
222 private:
223   SuspendibleThreadSetJoiner _joiner;
224 public:
225   ShenandoahSuspendibleThreadSetJoiner(bool active = true) : _joiner(active) {
226     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be joined before evac scope");
227   }
228   ~ShenandoahSuspendibleThreadSetJoiner() {
229     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be left after evac scope");
230   }
231 };
232 
233 class ShenandoahSuspendibleThreadSetLeaver {
234 private:
235   SuspendibleThreadSetLeaver _leaver;
236 public:
237   ShenandoahSuspendibleThreadSetLeaver(bool active = true) : _leaver(active) {
238     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be left after evac scope");
239   }
240   ~ShenandoahSuspendibleThreadSetLeaver() {
241     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be joined before evac scope");
242   }
243 };
244 
245 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP