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