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/shared/weakProcessorPhaseTimes.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 IsGCActiveMark          _is_gc_active_mark;
 136   TraceMemoryManagerStats       _trace_pause;
 137 
 138 public:
 139   ShenandoahGCPauseMark(uint gc_id, SvcGCMarker::reason_type type);
 140 };
 141 
 142 class ShenandoahSafepoint : public AllStatic {
 143 public:
 144   // check if Shenandoah GC safepoint is in progress
 145   static inline bool is_at_shenandoah_safepoint() {
 146     if (!SafepointSynchronize::is_at_safepoint()) return false;
 147 
 148     VM_Operation* vm_op = VMThread::vm_operation();
 149     if (vm_op == NULL) return false;
 150 
 151     VM_Operation::VMOp_Type type = vm_op->type();
 152     return type == VM_Operation::VMOp_ShenandoahInitMark ||
 153            type == VM_Operation::VMOp_ShenandoahFinalMarkStartEvac ||
 154            type == VM_Operation::VMOp_ShenandoahInitUpdateRefs ||
 155            type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs ||
 156            type == VM_Operation::VMOp_ShenandoahFullGC ||
 157            type == VM_Operation::VMOp_ShenandoahDegeneratedGC;
 158   }
 159 };
 160 
 161 class ShenandoahWorkerSession : public StackObj {
 162 protected:
 163   uint _worker_id;
 164 
 165   ShenandoahWorkerSession(uint worker_id);
 166   ~ShenandoahWorkerSession();
 167 public:
 168   static inline uint worker_id() {
 169     Thread* thr = Thread::current();
 170     uint id = ShenandoahThreadLocalData::worker_id(thr);
 171     assert(id != ShenandoahThreadLocalData::INVALID_WORKER_ID, "Worker session has not been created");
 172     return id;
 173   }
 174 };
 175 
 176 class ShenandoahConcurrentWorkerSession : public ShenandoahWorkerSession {
 177 private:
 178   EventGCPhaseConcurrent _event;
 179 
 180 public:
 181   ShenandoahConcurrentWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
 182   ~ShenandoahConcurrentWorkerSession();
 183 };
 184 
 185 class ShenandoahParallelWorkerSession : public ShenandoahWorkerSession {
 186 private:
 187   EventGCPhaseParallel _event;
 188 
 189 public:
 190   ShenandoahParallelWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
 191   ~ShenandoahParallelWorkerSession();
 192 };
 193 
 194 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP