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