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: 41 explicit IdleGCTrigger(Heap *heap, SharedHeap *sHeap, JSThread *thread, bool logEnable = false) heap_(heap)42 : heap_(heap), 43 sHeap_(sHeap), 44 thread_(thread), 45 optionalLogEnabled_(logEnable) {}; 46 virtual ~IdleGCTrigger() = default; 47 IsIdleState()48 bool IsIdleState() const 49 { 50 return idleState_.load(); 51 } 52 GetGCTypeName(TRIGGER_IDLE_GC_TYPE gcType)53 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_CONCURRENT_PARTIAL_MARK: 61 return "shared concurrent partial mark"; 62 case TRIGGER_IDLE_GC_TYPE::SHARED_FULL_GC: 63 return "shared full gc"; 64 case TRIGGER_IDLE_GC_TYPE::LOCAL_CONCURRENT_YOUNG_MARK: 65 return "local concurrent young mark"; 66 case TRIGGER_IDLE_GC_TYPE::LOCAL_CONCURRENT_FULL_MARK: 67 return "local concurrent full mark"; 68 case TRIGGER_IDLE_GC_TYPE::LOCAL_REMARK: 69 return "local remark"; 70 default: 71 return "UnknownType"; 72 } 73 } 74 IsPossiblePostGCTask(TRIGGER_IDLE_GC_TYPE gcType)75 bool IsPossiblePostGCTask(TRIGGER_IDLE_GC_TYPE gcType) const 76 { 77 uint8_t bit = static_cast<uint8_t>(gcType); 78 return (bit & gcTaskPostedState_) != bit; 79 } 80 SetPostGCTask(TRIGGER_IDLE_GC_TYPE gcType)81 void SetPostGCTask(TRIGGER_IDLE_GC_TYPE gcType) 82 { 83 uint8_t bit = static_cast<uint8_t>(gcType); 84 gcTaskPostedState_ = (gcTaskPostedState_ | bit); 85 } 86 ClearPostGCTask(TRIGGER_IDLE_GC_TYPE gcType)87 void ClearPostGCTask(TRIGGER_IDLE_GC_TYPE gcType) 88 { 89 uint8_t bit = static_cast<uint8_t>(gcType); 90 gcTaskPostedState_ = (gcTaskPostedState_ & ~bit); 91 } 92 SetTriggerGCTaskCallback(const TriggerGCTaskCallback & callback)93 void SetTriggerGCTaskCallback(const TriggerGCTaskCallback& callback) 94 { 95 triggerGCTaskCallback_ = callback; 96 } 97 98 void NotifyVsyncIdleStart(); 99 bool NotifyLooperIdleStart(int64_t timestamp, int idleTime); 100 void NotifyLooperIdleEnd(int64_t timestamp); 101 void TryTriggerHandleMarkFinished(); 102 void TryTriggerLocalConcurrentMark(MarkType type); 103 bool TryTriggerIdleYoungGC(); 104 bool TryTriggerIdleLocalOldGC(); 105 bool TryTriggerIdleSharedOldGC(); 106 bool ReachIdleLocalOldGCThresholds(); 107 bool ReachIdleSharedPartialGCThresholds(); 108 bool ReachIdleSharedGCThresholds(); 109 void TryPostHandleMarkFinished(); 110 void TryTriggerIdleGC(TRIGGER_IDLE_GC_TYPE gcType); 111 bool CheckIdleYoungGC(bool isLongIdle = false) const; 112 bool CheckIdleLocalOldGC(const Heap *heap) const; 113 bool CheckLocalBindingNativeTriggerOldGC() const; 114 template<class T> CheckIdleOrHintOldGC(const T * baseHeap)115 bool CheckIdleOrHintOldGC(const T *baseHeap) const 116 { 117 size_t heapAliveSizeAfterGC = baseHeap->GetHeapAliveSizeAfterGC(); 118 if (heapAliveSizeAfterGC == 0) { 119 return false; 120 } 121 size_t expectHeapSize = std::max(static_cast<size_t>(heapAliveSizeAfterGC * IDLE_SPACE_SIZE_MIN_INC_RATIO), 122 heapAliveSizeAfterGC + IDLE_SPACE_SIZE_MIN_INC_STEP); 123 LOG_ECMA_IF(optionalLogEnabled_, DEBUG) << "IdleGCTrigger: check old GC heapAliveSizeAfterGC:" 124 << heapAliveSizeAfterGC << ";expectHeapSize" << expectHeapSize 125 << "heapObjectSize" << baseHeap->GetHeapObjectSize(); 126 return baseHeap->GetHeapObjectSize() >= expectHeapSize; 127 } 128 129 template<class T> CheckIdleOrHintFullGC(const T * baseHeap)130 bool CheckIdleOrHintFullGC(const T *baseHeap) const 131 { 132 size_t heapAliveSizeAfterGC = baseHeap->GetHeapAliveSizeAfterGC(); 133 size_t expectHeapSize = std::max(static_cast<size_t>(heapAliveSizeAfterGC * IDLE_SPACE_SIZE_MIN_INC_RATIO), 134 heapAliveSizeAfterGC + IDLE_SPACE_SIZE_MIN_INC_STEP_FULL); 135 LOG_GC(DEBUG) << "IdleGCTrigger: check full GC heapAliveSizeAfterGC:" << heapAliveSizeAfterGC 136 << ";expectHeapSize:" << expectHeapSize << ";heapObjectSize:" << baseHeap->GetHeapObjectSize(); 137 if (baseHeap->GetHeapObjectSize() >= expectHeapSize) { 138 return true; 139 } 140 size_t fragmentSizeAfterGC = baseHeap->GetFragmentSizeAfterGC(); 141 size_t heapBasicLoss = baseHeap->GetHeapBasicLoss(); 142 if (fragmentSizeAfterGC <= heapBasicLoss) { 143 return false; 144 } 145 size_t fragmentSize = fragmentSizeAfterGC - heapBasicLoss; 146 size_t expectFragmentSize = std::max(static_cast<size_t>((baseHeap->GetCommittedSize() - heapBasicLoss) * 147 IDLE_FRAGMENT_SIZE_RATIO), IDLE_MIN_EXPECT_RECLAIM_SIZE); 148 LOG_GC(DEBUG) << "IdleGCTrigger: check full GC fragmentSizeAfterGC:" << fragmentSizeAfterGC 149 << ";heapBasicLoss:" << heapBasicLoss << ";expectFragmentSize" << expectFragmentSize; 150 return fragmentSize >= expectFragmentSize; 151 } 152 153 template<class T> HintGCInLowDegree(const T * baseHeap)154 bool HintGCInLowDegree(const T *baseHeap) const 155 { 156 return CheckIdleOrHintOldGC<T>(baseHeap); 157 } 158 159 template<class T> HintGCInMiddleDegree(const T * baseHeap)160 bool HintGCInMiddleDegree(const T *baseHeap) const 161 { 162 return CheckIdleOrHintOldGC<T>(baseHeap); 163 } 164 165 template<class T> HintGCInHighDegree(const T * baseHeap)166 bool HintGCInHighDegree(const T *baseHeap) const 167 { 168 return CheckIdleOrHintFullGC<T>(baseHeap); 169 } 170 171 private: 172 bool PostIdleGCTask(TRIGGER_IDLE_GC_TYPE gcType); 173 174 Heap *heap_ {nullptr}; 175 SharedHeap *sHeap_ {nullptr}; 176 JSThread *thread_ {nullptr}; 177 bool optionalLogEnabled_ {false}; 178 179 std::atomic<bool> idleState_ {false}; 180 uint8_t gcTaskPostedState_ {0}; 181 TriggerGCTaskCallback triggerGCTaskCallback_ {nullptr}; 182 }; 183 184 } 185 186 #endif // ECMASCRIPT_MEM_GC_TRIGGER_H