1 /*
  2  * Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP
 26 #define SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP
 27 
 28 #include "gc/shared/gcCause.hpp"
 29 #include "gc/shared/gcTraceTime.inline.hpp"
 30 #include "gc/shared/gcVMOperations.hpp"
 31 #include "gc/shared/isGCActiveMark.hpp"
 32 #include "gc/shared/suspendibleThreadSet.hpp"
 33 #include "gc/shenandoah/shenandoahPhaseTimings.hpp"
 34 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
 35 #include "jfr/jfrEvents.hpp"
 36 #include "memory/allocation.hpp"
 37 #include "runtime/safepoint.hpp"
 38 #include "runtime/vmThread.hpp"
 39 #include "runtime/vmOperations.hpp"
 40 #include "services/memoryService.hpp"
 41 
 42 class GCTimer;
 43 
 44 class ShenandoahGCSession : public StackObj {
 45 private:
 46   ShenandoahHeap* const _heap;
 47   GCTimer*  const _timer;
 48   GCTracer* const _tracer;
 49 
 50   TraceMemoryManagerStats _trace_cycle;
 51 public:
 52   ShenandoahGCSession(GCCause::Cause cause);
 53   ~ShenandoahGCSession();
 54 };
 55 
 56 /*
 57  * ShenandoahGCPhaseTiming tracks Shenandoah specific timing information
 58  * of a GC phase
 59  */
 60 class ShenandoahTimingsTracker : public StackObj {
 61 private:
 62   static ShenandoahPhaseTimings::Phase  _current_phase;
 63 
 64   ShenandoahPhaseTimings* const         _timings;
 65   const ShenandoahPhaseTimings::Phase   _phase;
 66   ShenandoahPhaseTimings::Phase         _parent_phase;
 67   double _start;
 68 
 69 public:
 70   ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase);
 71   ~ShenandoahTimingsTracker();
 72 
 73   static ShenandoahPhaseTimings::Phase current_phase() { return _current_phase; }
 74 
 75   static bool is_current_phase_valid();
 76 };
 77 
 78 /*
 79  * ShenandoahPausePhase tracks a STW pause and emits Shenandoah timing and
 80  * a corresponding JFR event
 81  */
 82 class ShenandoahPausePhase : public ShenandoahTimingsTracker {
 83 private:
 84   GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
 85   ConcurrentGCTimer* const _timer;
 86 
 87 public:
 88   ShenandoahPausePhase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
 89   ~ShenandoahPausePhase();
 90 };
 91 
 92 /*
 93  * ShenandoahConcurrentPhase tracks a concurrent GC phase and emits Shenandoah timing and
 94  * a corresponding JFR event
 95  */
 96 class ShenandoahConcurrentPhase : public ShenandoahTimingsTracker {
 97 private:
 98   GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
 99   ConcurrentGCTimer* const _timer;
100 
101 public:
102   ShenandoahConcurrentPhase(const char* title, ShenandoahPhaseTimings::Phase phase, bool log_heap_usage = false);
103   ~ShenandoahConcurrentPhase();
104 };
105 
106 /*
107  * ShenandoahGCPhase tracks Shenandoah specific timing information
108  * and emits a corresponding JFR event of a GC phase
109  */
110 class ShenandoahGCPhase : public ShenandoahTimingsTracker {
111 private:
112   ConcurrentGCTimer* const _timer;
113 
114 public:
115   ShenandoahGCPhase(ShenandoahPhaseTimings::Phase phase);
116   ~ShenandoahGCPhase();
117 };
118 
119 class ShenandoahGCWorkerPhase : public StackObj {
120 private:
121   ShenandoahPhaseTimings* const       _timings;
122   const ShenandoahPhaseTimings::Phase _phase;
123 public:
124   ShenandoahGCWorkerPhase(ShenandoahPhaseTimings::Phase phase);
125   ~ShenandoahGCWorkerPhase();
126 };
127 
128 // Aggregates all the things that should happen before/after the pause.
129 class ShenandoahGCPauseMark : public StackObj {
130 private:
131   ShenandoahHeap* const _heap;
132   const GCIdMark                _gc_id_mark;
133   const SvcGCMarker             _svc_gc_mark;
134   const IsGCActiveMark          _is_gc_active_mark;
135   TraceMemoryManagerStats       _trace_pause;
136 
137 public:
138   ShenandoahGCPauseMark(uint gc_id, SvcGCMarker::reason_type type);
139 };
140 
141 class ShenandoahSafepoint : public AllStatic {
142 public:
143   // Check if Shenandoah GC safepoint is in progress. This is nominally
144   // equivalent to calling SafepointSynchronize::is_at_safepoint(), but
145   // it also checks the Shenandoah specifics, when it can.
146   static inline bool is_at_shenandoah_safepoint() {
147     if (!SafepointSynchronize::is_at_safepoint()) return false;
148 
149     Thread* const thr = Thread::current();
150     // Shenandoah GC specific safepoints are scheduled by control thread.
151     // So if we are enter here from control thread, then we are definitely not
152     // at Shenandoah safepoint, but at something else.
153     if (thr == ShenandoahHeap::heap()->control_thread()) return false;
154 
155     // This is not VM thread, cannot see what VM thread is doing,
156     // so pretend this is a proper Shenandoah safepoint
157     if (!thr->is_VM_thread()) return true;
158 
159     // Otherwise check we are at proper operation type
160     VM_Operation* vm_op = VMThread::vm_operation();
161     if (vm_op == NULL) return false;
162 
163     VM_Operation::VMOp_Type type = vm_op->type();
164     return type == VM_Operation::VMOp_ShenandoahInitMark ||
165            type == VM_Operation::VMOp_ShenandoahFinalMarkStartEvac ||
166            type == VM_Operation::VMOp_ShenandoahInitUpdateRefs ||
167            type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs ||
168            type == VM_Operation::VMOp_ShenandoahFinalRoots ||
169            type == VM_Operation::VMOp_ShenandoahFullGC ||
170            type == VM_Operation::VMOp_ShenandoahDegeneratedGC;
171   }
172 };
173 
174 class ShenandoahWorkerSession : public StackObj {
175 protected:
176   uint _worker_id;
177 
178   ShenandoahWorkerSession(uint worker_id);
179   ~ShenandoahWorkerSession();
180 public:
181   static inline uint worker_id() {
182     Thread* thr = Thread::current();
183     uint id = ShenandoahThreadLocalData::worker_id(thr);
184     assert(id != ShenandoahThreadLocalData::INVALID_WORKER_ID, "Worker session has not been created");
185     return id;
186   }
187 };
188 
189 class ShenandoahConcurrentWorkerSession : public ShenandoahWorkerSession {
190 private:
191   EventGCPhaseConcurrent _event;
192 
193 public:
194   ShenandoahConcurrentWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
195   ~ShenandoahConcurrentWorkerSession();
196 };
197 
198 class ShenandoahParallelWorkerSession : public ShenandoahWorkerSession {
199 private:
200   EventGCPhaseParallel _event;
201 
202 public:
203   ShenandoahParallelWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
204   ~ShenandoahParallelWorkerSession();
205 };
206 
207 class ShenandoahSuspendibleThreadSetJoiner {
208 private:
209   SuspendibleThreadSetJoiner _joiner;
210 public:
211   ShenandoahSuspendibleThreadSetJoiner(bool active = true) : _joiner(active) {
212     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be joined before evac scope");
213   }
214   ~ShenandoahSuspendibleThreadSetJoiner() {
215     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be left after evac scope");
216   }
217 };
218 
219 class ShenandoahSuspendibleThreadSetLeaver {
220 private:
221   SuspendibleThreadSetLeaver _leaver;
222 public:
223   ShenandoahSuspendibleThreadSetLeaver(bool active = true) : _leaver(active) {
224     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be left after evac scope");
225   }
226   ~ShenandoahSuspendibleThreadSetLeaver() {
227     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be joined before evac scope");
228   }
229 };
230 
231 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP