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 */