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 class ShenandoahPausePhase : public StackObj {
  58 private:
  59   GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
  60   ConcurrentGCTimer* const _timer;
  61 
  62 public:
  63   ShenandoahPausePhase(const char* title, bool log_heap_usage = false);
  64   ~ShenandoahPausePhase();
  65 };
  66 
  67 class ShenandoahConcurrentPhase : public StackObj {
  68 private:
  69   GCTraceTimeWrapper<LogLevel::Info, LOG_TAGS(gc)> _tracer;
  70   ConcurrentGCTimer* const _timer;
  71 
  72 public:
  73   ShenandoahConcurrentPhase(const char* title, bool log_heap_usage = false);
  74   ~ShenandoahConcurrentPhase();
  75 };
  76 
  77 class ShenandoahGCPhase : public StackObj {
  78 private:
  79   static ShenandoahPhaseTimings::Phase  _current_phase;
  80 
  81   ShenandoahPhaseTimings* const         _timings;
  82   const ShenandoahPhaseTimings::Phase   _phase;
  83   ShenandoahPhaseTimings::Phase         _parent_phase;
  84   double _start;
  85 
  86 public:
  87   ShenandoahGCPhase(ShenandoahPhaseTimings::Phase phase);
  88   ~ShenandoahGCPhase();
  89 
  90   static ShenandoahPhaseTimings::Phase current_phase() { return _current_phase; }
  91 
  92   static bool is_current_phase_valid();
  93 };
  94 
  95 class ShenandoahGCSubPhase: public ShenandoahGCPhase {
  96 private:
  97   ConcurrentGCTimer* const _timer;
  98 
  99 public:
 100   ShenandoahGCSubPhase(ShenandoahPhaseTimings::Phase phase);
 101   ~ShenandoahGCSubPhase();
 102 };
 103 
 104 class ShenandoahGCWorkerPhase : public StackObj {
 105 private:
 106   ShenandoahPhaseTimings* const       _timings;
 107   const ShenandoahPhaseTimings::Phase _phase;
 108 public:
 109   ShenandoahGCWorkerPhase(ShenandoahPhaseTimings::Phase phase);
 110   ~ShenandoahGCWorkerPhase();
 111 };
 112 
 113 // Aggregates all the things that should happen before/after the pause.
 114 class ShenandoahGCPauseMark : public StackObj {
 115 private:
 116   ShenandoahHeap* const _heap;
 117   const GCIdMark                _gc_id_mark;
 118   const SvcGCMarker             _svc_gc_mark;
 119   const IsGCActiveMark          _is_gc_active_mark;
 120   TraceMemoryManagerStats       _trace_pause;
 121 
 122 public:
 123   ShenandoahGCPauseMark(uint gc_id, SvcGCMarker::reason_type type);
 124 };
 125 
 126 class ShenandoahSafepoint : public AllStatic {
 127 public:
 128   // check if Shenandoah GC safepoint is in progress
 129   static inline bool is_at_shenandoah_safepoint() {
 130     if (!SafepointSynchronize::is_at_safepoint()) return false;
 131 
 132     VM_Operation* vm_op = VMThread::vm_operation();
 133     if (vm_op == NULL) return false;
 134 
 135     VM_Operation::VMOp_Type type = vm_op->type();
 136     return type == VM_Operation::VMOp_ShenandoahInitMark ||
 137            type == VM_Operation::VMOp_ShenandoahFinalMarkStartEvac ||
 138            type == VM_Operation::VMOp_ShenandoahInitUpdateRefs ||
 139            type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs ||
 140            type == VM_Operation::VMOp_ShenandoahFullGC ||
 141            type == VM_Operation::VMOp_ShenandoahDegeneratedGC;
 142   }
 143 };
 144 
 145 class ShenandoahWorkerSession : public StackObj {
 146 protected:
 147   uint _worker_id;
 148 
 149   ShenandoahWorkerSession(uint worker_id);
 150   ~ShenandoahWorkerSession();
 151 public:
 152   static inline uint worker_id() {
 153     Thread* thr = Thread::current();
 154     uint id = ShenandoahThreadLocalData::worker_id(thr);
 155     assert(id != ShenandoahThreadLocalData::INVALID_WORKER_ID, "Worker session has not been created");
 156     return id;
 157   }
 158 };
 159 
 160 class ShenandoahConcurrentWorkerSession : public ShenandoahWorkerSession {
 161 private:
 162   EventGCPhaseConcurrent _event;
 163 
 164 public:
 165   ShenandoahConcurrentWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
 166   ~ShenandoahConcurrentWorkerSession();
 167 };
 168 
 169 class ShenandoahParallelWorkerSession : public ShenandoahWorkerSession {
 170 private:
 171   EventGCPhaseParallel _event;
 172 
 173 public:
 174   ShenandoahParallelWorkerSession(uint worker_id) : ShenandoahWorkerSession(worker_id) { }
 175   ~ShenandoahParallelWorkerSession();
 176 };
 177 
 178 class ShenandoahSuspendibleThreadSetJoiner {
 179 private:
 180   SuspendibleThreadSetJoiner _joiner;
 181 public:
 182   ShenandoahSuspendibleThreadSetJoiner(bool active = true) : _joiner(active) {
 183     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be joined before evac scope");
 184   }
 185   ~ShenandoahSuspendibleThreadSetJoiner() {
 186     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be left after evac scope");
 187   }
 188 };
 189 
 190 class ShenandoahSuspendibleThreadSetLeaver {
 191 private:
 192   SuspendibleThreadSetLeaver _leaver;
 193 public:
 194   ShenandoahSuspendibleThreadSetLeaver(bool active = true) : _leaver(active) {
 195     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be left after evac scope");
 196   }
 197   ~ShenandoahSuspendibleThreadSetLeaver() {
 198     assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "STS should be joined before evac scope");
 199   }
 200 };
 201 
 202 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP