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 16 #ifndef FOUNDATION_ACE_NAPI_NATIVE_ENGINE_IMPL_ARK_ARK_NATIVE_IDLE_MONITOR_H 17 #define FOUNDATION_ACE_NAPI_NATIVE_ENGINE_IMPL_ARK_ARK_NATIVE_IDLE_MONITOR_H 18 19 #include <atomic> 20 #include <ctime> 21 #include <chrono> 22 #include <array> 23 #include <algorithm> 24 #include <memory> 25 26 #if defined(ENABLE_EVENT_HANDLER) 27 #include "event_handler.h" 28 #endif 29 #include "uv.h" 30 #include "ecmascript/napi/include/dfx_jsnapi.h" 31 #include "ecmascript/napi/include/jsnapi.h" 32 33 namespace panda::ecmascript { 34 class Heap; 35 class SharedHeap; 36 class ConcurrentMarker; 37 class MemController; 38 class SharedMemController; 39 40 class ArkIdleMonitor { 41 using Clock = std::chrono::high_resolution_clock; 42 using TRIGGER_IDLE_GC_TYPE = panda::JSNApi::TRIGGER_IDLE_GC_TYPE; 43 public: ArkIdleMonitor(EcmaVM * vm)44 explicit ArkIdleMonitor(EcmaVM* vm) : vm_(vm) {}; 45 ~ArkIdleMonitor(); 46 IsIdleState()47 bool IsIdleState() const 48 { 49 return idleState_.load(std::memory_order_relaxed); 50 } 51 SetIdleState(bool idleState)52 void SetIdleState(bool idleState) 53 { 54 idleState_.store(idleState, std::memory_order_relaxed); 55 } 56 57 void NotifyChangeBackgroundState(bool inBackground); 58 IsInBackground()59 bool IsInBackground() const 60 { 61 return inBackground_.load(std::memory_order_relaxed); 62 } 63 AddIdleNotifyCount()64 void AddIdleNotifyCount() 65 { 66 idleNotifyCount_.fetch_add(1, std::memory_order_relaxed); 67 } 68 GetIdleNotifyCount()69 int64_t GetIdleNotifyCount() const 70 { 71 return idleNotifyCount_.load(std::memory_order_relaxed); 72 } 73 ResetIdleNotifyCount()74 void ResetIdleNotifyCount() 75 { 76 return idleNotifyCount_.store(0, std::memory_order_relaxed); 77 } 78 GetNotifyTimestamp()79 int64_t GetNotifyTimestamp() const 80 { 81 return notifyTimestamp_.load(std::memory_order_relaxed); 82 } 83 SetNotifyTimestamp(int64_t timestamp)84 void SetNotifyTimestamp(int64_t timestamp) 85 { 86 notifyTimestamp_.store(timestamp, std::memory_order_relaxed); 87 } 88 GetTotalIdleDuration()89 int64_t GetTotalIdleDuration() const 90 { 91 return totalIdleDuration_.load(std::memory_order_relaxed); 92 } 93 ResetTotalIdleDuration()94 void ResetTotalIdleDuration() 95 { 96 totalIdleDuration_.store(0, std::memory_order_relaxed); 97 } 98 AddIdleDuration(int64_t duration)99 void AddIdleDuration(int64_t duration) 100 { 101 totalIdleDuration_.fetch_add(duration, std::memory_order_relaxed); 102 } 103 104 template<typename T, int N> 105 class RingBuffer { 106 public: 107 RingBuffer() = default; 108 ~RingBuffer() = default; 109 Push(const T & value)110 void Push(const T &value) 111 { 112 if (count_ == N) { 113 elements_[start_++] = value; 114 if (start_ == N) { 115 start_ = 0; 116 } 117 } else { 118 ASSERT(start_ == 0); 119 elements_[count_++] = value; 120 } 121 } 122 Count()123 int Count() const 124 { 125 return count_; 126 } 127 128 template<typename Callback> Sum(Callback callback,const T & initial)129 T Sum(Callback callback, const T &initial) const 130 { 131 T result = initial; 132 for (int i = 0; i < count_; i++) { 133 result = callback(result, elements_[i]); 134 } 135 return result; 136 } 137 Reset()138 void Reset() 139 { 140 start_ = count_ = 0; 141 } 142 143 private: 144 std::array<T, N> elements_; 145 int start_ {0}; 146 int count_ {0}; 147 }; 148 149 bool ShouldTryTriggerGC(int64_t timestamp); 150 void NotifyLooperIdleStart(int64_t timestamp, int idleTime); 151 void NotifyLooperIdleEnd(int64_t timestamp); 152 bool CheckLowNotifyState() const; 153 bool CheckLowRunningDurationState() const; 154 void IntervalMonitor(); 155 void ClearIdleStats(); 156 void PostMonitorTask(uint64_t delayMs = IDLE_MONITORING_INTERVAL); 157 void TryTriggerGC(TriggerGCType gcType); 158 void NotifyTryCompressGC(); 159 void SetStartTimerCallback(); 160 161 private: 162 double GetCpuUsage() const; 163 164 EcmaVM* vm_; 165 166 static constexpr int IDLE_CHECK_LENGTH = 15; 167 static constexpr int IDLE_INBACKGROUND_CHECK_LENGTH = 4; 168 static constexpr int IDLE_CHECK_INTERVAL_LENGTH = 5; 169 static constexpr int MIN_TRIGGER_FULLGC_INTERVAL = 90; 170 static constexpr int LOW_IDLE_NOTIFY_THRESHOLD = 10; 171 static constexpr uint64_t IDLE_MONITORING_INTERVAL = 1 * 1000; // ms 172 static constexpr uint64_t SLEEP_MONITORING_INTERVAL = 90 * 1000; // ms 173 static constexpr int64_t MIN_TRIGGER_GC_IDLE_INTERVAL = 30; // ms 174 static constexpr double IDLE_RATIO = 0.985f; 175 static constexpr double IDLE_CPU_USAGE = 0.5f; 176 static constexpr int DOUBLE_INTERVAL_CHECK = 2; 177 178 std::atomic<bool> idleState_ {false}; 179 std::atomic<bool> inBackground_ {true}; 180 std::atomic<int64_t> idleNotifyCount_ {0}; 181 std::atomic<int64_t> notifyTimestamp_ {0}; 182 std::atomic<int64_t> totalIdleDuration_ {0}; 183 int currentTimerHandler_ {-1}; 184 int waitForStopTimerHandler_ {-1}; 185 int64_t startRecordTimestamp_ {0}; 186 int64_t needCheckFullGCTimestamp_ {0}; 187 int64_t numberOfLowIdleNotifyCycles_ {0}; 188 int64_t numberOfHighIdleTimeRatio_ {0}; 189 RingBuffer<int64_t, IDLE_CHECK_INTERVAL_LENGTH> recordedIdleNotifyInterval_; 190 #if defined(ENABLE_EVENT_HANDLER) 191 std::shared_ptr<OHOS::AppExecFwk::EventHandler> mainThreadHandler_ {}; 192 #endif 193 }; 194 195 } 196 197 #endif /* FOUNDATION_ACE_NAPI_NATIVE_ENGINE_IMPL_ARK_ARK_NATIVE_IDLE_MONITOR_H */