1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #ifndef ECMASCRIPT_MEM_GC_TRIGGER_H 16 #define ECMASCRIPT_MEM_GC_TRIGGER_H 17 18 #include <atomic> 19 #include <ctime> 20 #include <chrono> 21 22 #include "libpandabase/macros.h" 23 #include "ecmascript/common.h" 24 #include "ecmascript/mem/mem_common.h" 25 #include "ecmascript/base/gc_ring_buffer.h" 26 #include "ecmascript/mem/heap.h" 27 #include "ecmascript/napi/include/jsnapi_expo.h" 28 29 namespace panda::ecmascript { 30 class Heap; 31 class SharedHeap; 32 class ConcurrentMarker; 33 class MemController; 34 class SharedMemController; 35 class EcmaVM; 36 37 class IdleGCTrigger { 38 using TRIGGER_IDLE_GC_TYPE = panda::JSNApi::TRIGGER_IDLE_GC_TYPE; 39 using Clock = std::chrono::high_resolution_clock; 40 public: IdleGCTrigger(Heap *heap, SharedHeap *sHeap, JSThread *thread, bool logEnable = false)41 explicit IdleGCTrigger(Heap *heap, SharedHeap *sHeap, JSThread *thread, bool logEnable = false) 42 : heap_(heap), 43 sHeap_(sHeap), 44 thread_(thread), 45 optionalLogEnabled_(logEnable) {}; 46 virtual ~IdleGCTrigger() = default; 47 IsIdleState() const48 bool IsIdleState() const 49 { 50 return idleState_.load(); 51 } 52 GetGCTypeName(TRIGGER_IDLE_GC_TYPE gcType) const53 const char *GetGCTypeName(TRIGGER_IDLE_GC_TYPE gcType) const 54 { 55 switch (gcType) { 56 case TRIGGER_IDLE_GC_TYPE::FULL_GC: 57 return "full gc"; 58 case TRIGGER_IDLE_GC_TYPE::SHARED_CONCURRENT_MARK: 59 return "shared concurrent mark"; 60 case TRIGGER_IDLE_GC_TYPE::SHARED_FULL_GC: 61 return "shared full gc"; 62 case TRIGGER_IDLE_GC_TYPE::LOCAL_CONCURRENT_MARK: 63 return "local concurrent mark"; 64 case TRIGGER_IDLE_GC_TYPE::LOCAL_REMARK: 65 return "local remark"; 66 default: 67 return "UnknownType"; 68 } 69 } 70 IsPossiblePostGCTask(TRIGGER_IDLE_GC_TYPE gcType) const71 bool IsPossiblePostGCTask(TRIGGER_IDLE_GC_TYPE gcType) const 72 { 73 uint8_t bit = static_cast<uint8_t>(gcType); 74 return (bit & gcTaskPostedState_) != bit; 75 } 76 SetPostGCTask(TRIGGER_IDLE_GC_TYPE gcType)77 void SetPostGCTask(TRIGGER_IDLE_GC_TYPE gcType) 78 { 79 uint8_t bit = static_cast<uint8_t>(gcType); 80 gcTaskPostedState_ = (gcTaskPostedState_ | bit); 81 } 82 ClearPostGCTask(TRIGGER_IDLE_GC_TYPE gcType)83 void ClearPostGCTask(TRIGGER_IDLE_GC_TYPE gcType) 84 { 85 uint8_t bit = static_cast<uint8_t>(gcType); 86 gcTaskPostedState_ = (gcTaskPostedState_ & ~bit); 87 } 88 SetTriggerGCTaskCallback(const TriggerGCTaskCallback& callback)89 void SetTriggerGCTaskCallback(const TriggerGCTaskCallback& callback) 90 { 91 triggerGCTaskCallback_ = callback; 92 } 93 94 void NotifyVsyncIdleStart(); 95 void NotifyLooperIdleStart(int64_t timestamp, int idleTime); 96 void NotifyLooperIdleEnd(int64_t timestamp); 97 void TryTriggerHandleMarkFinished(); 98 void TryTriggerLocalConcurrentMark(); 99 bool TryTriggerIdleLocalOldGC(); 100 bool TryTriggerIdleSharedOldGC(); 101 bool ReachIdleLocalOldGCThresholds(); 102 bool ReachIdleSharedGCThresholds(); 103 void TryPostHandleMarkFinished(); 104 void TryTriggerIdleGC(TRIGGER_IDLE_GC_TYPE gcType); 105 bool CheckIdleYoungGC() const; 106 template<class T> CheckIdleOrHintOldGC(const T *baseHeap) const107 bool CheckIdleOrHintOldGC(const T *baseHeap) const 108 { 109 size_t heapAliveSizeAfterGC = baseHeap->GetHeapAliveSizeAfterGC(); 110 if (heapAliveSizeAfterGC == 0) { 111 return false; 112 } 113 size_t expectHeapSize = std::max(static_cast<size_t>(heapAliveSizeAfterGC * IDLE_SPACE_SIZE_MIN_INC_RATIO), 114 heapAliveSizeAfterGC + IDLE_SPACE_SIZE_MIN_INC_STEP); 115 LOG_ECMA_IF(optionalLogEnabled_, DEBUG) << "IdleGCTrigger: check old GC heapAliveSizeAfterGC:" 116 << heapAliveSizeAfterGC << ";expectHeapSize" << expectHeapSize 117 << "heapObjectSize" << baseHeap->GetHeapObjectSize(); 118 return baseHeap->GetHeapObjectSize() >= expectHeapSize; 119 } 120 121 template<class T> CheckIdleOrHintFullGC(const T *baseHeap) const122 bool CheckIdleOrHintFullGC(const T *baseHeap) const 123 { 124 size_t heapAliveSizeAfterGC = baseHeap->GetHeapAliveSizeAfterGC(); 125 size_t expectHeapSize = std::max(static_cast<size_t>(heapAliveSizeAfterGC * IDLE_SPACE_SIZE_MIN_INC_RATIO), 126 heapAliveSizeAfterGC + IDLE_SPACE_SIZE_MIN_INC_STEP_FULL); 127 LOG_GC(DEBUG) << "IdleGCTrigger: check full GC heapAliveSizeAfterGC:" << heapAliveSizeAfterGC 128 << ";expectHeapSize:" << expectHeapSize << ";heapObjectSize:" << baseHeap->GetHeapObjectSize(); 129 if (baseHeap->GetHeapObjectSize() >= expectHeapSize) { 130 return true; 131 } 132 size_t fragmentSizeAfterGC = baseHeap->GetFragmentSizeAfterGC(); 133 size_t heapBasicLoss = baseHeap->GetHeapBasicLoss(); 134 if (fragmentSizeAfterGC <= heapBasicLoss) { 135 return false; 136 } 137 size_t fragmentSize = fragmentSizeAfterGC - heapBasicLoss; 138 size_t expectFragmentSize = std::max(static_cast<size_t>((baseHeap->GetCommittedSize() - heapBasicLoss) * 139 IDLE_FRAGMENT_SIZE_RATIO), IDLE_MIN_EXPECT_RECLAIM_SIZE); 140 LOG_GC(DEBUG) << "IdleGCTrigger: check full GC fragmentSizeAfterGC:" << fragmentSizeAfterGC 141 << ";heapBasicLoss:" << heapBasicLoss << ";expectFragmentSize" << expectFragmentSize; 142 return fragmentSize >= expectFragmentSize; 143 } 144 145 template<class T> HintGCInLowDegree(const T *baseHeap) const146 bool HintGCInLowDegree(const T *baseHeap) const 147 { 148 return CheckIdleOrHintOldGC<T>(baseHeap); 149 } 150 151 template<class T> HintGCInMiddleDegree(const T *baseHeap) const152 bool HintGCInMiddleDegree(const T *baseHeap) const 153 { 154 return CheckIdleOrHintOldGC<T>(baseHeap); 155 } 156 157 template<class T> HintGCInHighDegree(const T *baseHeap) const158 bool HintGCInHighDegree(const T *baseHeap) const 159 { 160 return CheckIdleOrHintFullGC<T>(baseHeap); 161 } 162 163 private: 164 void PostIdleGCTask(TRIGGER_IDLE_GC_TYPE gcType); 165 166 Heap *heap_ {nullptr}; 167 SharedHeap *sHeap_ {nullptr}; 168 JSThread *thread_ {nullptr}; 169 bool optionalLogEnabled_ {false}; 170 171 std::atomic<bool> idleState_ {false}; 172 uint8_t gcTaskPostedState_ {0}; 173 TriggerGCTaskCallback triggerGCTaskCallback_ {nullptr}; 174 }; 175 176 } 177 178 #endif // ECMASCRIPT_MEM_GC_TRIGGER_H