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 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