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