• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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