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