14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_MEM_GC_TRIGGER_H 164514f5e3Sopenharmony_ci#define ECMASCRIPT_MEM_GC_TRIGGER_H 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include <atomic> 194514f5e3Sopenharmony_ci#include <ctime> 204514f5e3Sopenharmony_ci#include <chrono> 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_ci#include "libpandabase/macros.h" 234514f5e3Sopenharmony_ci#include "ecmascript/common.h" 244514f5e3Sopenharmony_ci#include "ecmascript/mem/mem_common.h" 254514f5e3Sopenharmony_ci#include "ecmascript/base/gc_ring_buffer.h" 264514f5e3Sopenharmony_ci#include "ecmascript/mem/heap.h" 274514f5e3Sopenharmony_ci#include "ecmascript/napi/include/jsnapi_expo.h" 284514f5e3Sopenharmony_ci 294514f5e3Sopenharmony_cinamespace panda::ecmascript { 304514f5e3Sopenharmony_ciclass Heap; 314514f5e3Sopenharmony_ciclass SharedHeap; 324514f5e3Sopenharmony_ciclass ConcurrentMarker; 334514f5e3Sopenharmony_ciclass MemController; 344514f5e3Sopenharmony_ciclass SharedMemController; 354514f5e3Sopenharmony_ciclass EcmaVM; 364514f5e3Sopenharmony_ci 374514f5e3Sopenharmony_ciclass IdleGCTrigger { 384514f5e3Sopenharmony_ciusing TRIGGER_IDLE_GC_TYPE = panda::JSNApi::TRIGGER_IDLE_GC_TYPE; 394514f5e3Sopenharmony_ciusing Clock = std::chrono::high_resolution_clock; 404514f5e3Sopenharmony_cipublic: 414514f5e3Sopenharmony_ci explicit IdleGCTrigger(Heap *heap, SharedHeap *sHeap, JSThread *thread, bool logEnable = false) 424514f5e3Sopenharmony_ci : heap_(heap), 434514f5e3Sopenharmony_ci sHeap_(sHeap), 444514f5e3Sopenharmony_ci thread_(thread), 454514f5e3Sopenharmony_ci optionalLogEnabled_(logEnable) {}; 464514f5e3Sopenharmony_ci virtual ~IdleGCTrigger() = default; 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_ci bool IsIdleState() const 494514f5e3Sopenharmony_ci { 504514f5e3Sopenharmony_ci return idleState_.load(); 514514f5e3Sopenharmony_ci } 524514f5e3Sopenharmony_ci 534514f5e3Sopenharmony_ci const char *GetGCTypeName(TRIGGER_IDLE_GC_TYPE gcType) const 544514f5e3Sopenharmony_ci { 554514f5e3Sopenharmony_ci switch (gcType) { 564514f5e3Sopenharmony_ci case TRIGGER_IDLE_GC_TYPE::FULL_GC: 574514f5e3Sopenharmony_ci return "full gc"; 584514f5e3Sopenharmony_ci case TRIGGER_IDLE_GC_TYPE::SHARED_CONCURRENT_MARK: 594514f5e3Sopenharmony_ci return "shared concurrent mark"; 604514f5e3Sopenharmony_ci case TRIGGER_IDLE_GC_TYPE::SHARED_FULL_GC: 614514f5e3Sopenharmony_ci return "shared full gc"; 624514f5e3Sopenharmony_ci case TRIGGER_IDLE_GC_TYPE::LOCAL_CONCURRENT_MARK: 634514f5e3Sopenharmony_ci return "local concurrent mark"; 644514f5e3Sopenharmony_ci case TRIGGER_IDLE_GC_TYPE::LOCAL_REMARK: 654514f5e3Sopenharmony_ci return "local remark"; 664514f5e3Sopenharmony_ci default: 674514f5e3Sopenharmony_ci return "UnknownType"; 684514f5e3Sopenharmony_ci } 694514f5e3Sopenharmony_ci } 704514f5e3Sopenharmony_ci 714514f5e3Sopenharmony_ci bool IsPossiblePostGCTask(TRIGGER_IDLE_GC_TYPE gcType) const 724514f5e3Sopenharmony_ci { 734514f5e3Sopenharmony_ci uint8_t bit = static_cast<uint8_t>(gcType); 744514f5e3Sopenharmony_ci return (bit & gcTaskPostedState_) != bit; 754514f5e3Sopenharmony_ci } 764514f5e3Sopenharmony_ci 774514f5e3Sopenharmony_ci void SetPostGCTask(TRIGGER_IDLE_GC_TYPE gcType) 784514f5e3Sopenharmony_ci { 794514f5e3Sopenharmony_ci uint8_t bit = static_cast<uint8_t>(gcType); 804514f5e3Sopenharmony_ci gcTaskPostedState_ = (gcTaskPostedState_ | bit); 814514f5e3Sopenharmony_ci } 824514f5e3Sopenharmony_ci 834514f5e3Sopenharmony_ci void ClearPostGCTask(TRIGGER_IDLE_GC_TYPE gcType) 844514f5e3Sopenharmony_ci { 854514f5e3Sopenharmony_ci uint8_t bit = static_cast<uint8_t>(gcType); 864514f5e3Sopenharmony_ci gcTaskPostedState_ = (gcTaskPostedState_ & ~bit); 874514f5e3Sopenharmony_ci } 884514f5e3Sopenharmony_ci 894514f5e3Sopenharmony_ci void SetTriggerGCTaskCallback(const TriggerGCTaskCallback& callback) 904514f5e3Sopenharmony_ci { 914514f5e3Sopenharmony_ci triggerGCTaskCallback_ = callback; 924514f5e3Sopenharmony_ci } 934514f5e3Sopenharmony_ci 944514f5e3Sopenharmony_ci void NotifyVsyncIdleStart(); 954514f5e3Sopenharmony_ci void NotifyLooperIdleStart(int64_t timestamp, int idleTime); 964514f5e3Sopenharmony_ci void NotifyLooperIdleEnd(int64_t timestamp); 974514f5e3Sopenharmony_ci void TryTriggerHandleMarkFinished(); 984514f5e3Sopenharmony_ci void TryTriggerLocalConcurrentMark(); 994514f5e3Sopenharmony_ci bool TryTriggerIdleLocalOldGC(); 1004514f5e3Sopenharmony_ci bool TryTriggerIdleSharedOldGC(); 1014514f5e3Sopenharmony_ci bool ReachIdleLocalOldGCThresholds(); 1024514f5e3Sopenharmony_ci bool ReachIdleSharedGCThresholds(); 1034514f5e3Sopenharmony_ci void TryPostHandleMarkFinished(); 1044514f5e3Sopenharmony_ci void TryTriggerIdleGC(TRIGGER_IDLE_GC_TYPE gcType); 1054514f5e3Sopenharmony_ci bool CheckIdleYoungGC() const; 1064514f5e3Sopenharmony_ci template<class T> 1074514f5e3Sopenharmony_ci bool CheckIdleOrHintOldGC(const T *baseHeap) const 1084514f5e3Sopenharmony_ci { 1094514f5e3Sopenharmony_ci size_t heapAliveSizeAfterGC = baseHeap->GetHeapAliveSizeAfterGC(); 1104514f5e3Sopenharmony_ci if (heapAliveSizeAfterGC == 0) { 1114514f5e3Sopenharmony_ci return false; 1124514f5e3Sopenharmony_ci } 1134514f5e3Sopenharmony_ci size_t expectHeapSize = std::max(static_cast<size_t>(heapAliveSizeAfterGC * IDLE_SPACE_SIZE_MIN_INC_RATIO), 1144514f5e3Sopenharmony_ci heapAliveSizeAfterGC + IDLE_SPACE_SIZE_MIN_INC_STEP); 1154514f5e3Sopenharmony_ci LOG_ECMA_IF(optionalLogEnabled_, DEBUG) << "IdleGCTrigger: check old GC heapAliveSizeAfterGC:" 1164514f5e3Sopenharmony_ci << heapAliveSizeAfterGC << ";expectHeapSize" << expectHeapSize 1174514f5e3Sopenharmony_ci << "heapObjectSize" << baseHeap->GetHeapObjectSize(); 1184514f5e3Sopenharmony_ci return baseHeap->GetHeapObjectSize() >= expectHeapSize; 1194514f5e3Sopenharmony_ci } 1204514f5e3Sopenharmony_ci 1214514f5e3Sopenharmony_ci template<class T> 1224514f5e3Sopenharmony_ci bool CheckIdleOrHintFullGC(const T *baseHeap) const 1234514f5e3Sopenharmony_ci { 1244514f5e3Sopenharmony_ci size_t heapAliveSizeAfterGC = baseHeap->GetHeapAliveSizeAfterGC(); 1254514f5e3Sopenharmony_ci size_t expectHeapSize = std::max(static_cast<size_t>(heapAliveSizeAfterGC * IDLE_SPACE_SIZE_MIN_INC_RATIO), 1264514f5e3Sopenharmony_ci heapAliveSizeAfterGC + IDLE_SPACE_SIZE_MIN_INC_STEP_FULL); 1274514f5e3Sopenharmony_ci LOG_GC(DEBUG) << "IdleGCTrigger: check full GC heapAliveSizeAfterGC:" << heapAliveSizeAfterGC 1284514f5e3Sopenharmony_ci << ";expectHeapSize:" << expectHeapSize << ";heapObjectSize:" << baseHeap->GetHeapObjectSize(); 1294514f5e3Sopenharmony_ci if (baseHeap->GetHeapObjectSize() >= expectHeapSize) { 1304514f5e3Sopenharmony_ci return true; 1314514f5e3Sopenharmony_ci } 1324514f5e3Sopenharmony_ci size_t fragmentSizeAfterGC = baseHeap->GetFragmentSizeAfterGC(); 1334514f5e3Sopenharmony_ci size_t heapBasicLoss = baseHeap->GetHeapBasicLoss(); 1344514f5e3Sopenharmony_ci if (fragmentSizeAfterGC <= heapBasicLoss) { 1354514f5e3Sopenharmony_ci return false; 1364514f5e3Sopenharmony_ci } 1374514f5e3Sopenharmony_ci size_t fragmentSize = fragmentSizeAfterGC - heapBasicLoss; 1384514f5e3Sopenharmony_ci size_t expectFragmentSize = std::max(static_cast<size_t>((baseHeap->GetCommittedSize() - heapBasicLoss) * 1394514f5e3Sopenharmony_ci IDLE_FRAGMENT_SIZE_RATIO), IDLE_MIN_EXPECT_RECLAIM_SIZE); 1404514f5e3Sopenharmony_ci LOG_GC(DEBUG) << "IdleGCTrigger: check full GC fragmentSizeAfterGC:" << fragmentSizeAfterGC 1414514f5e3Sopenharmony_ci << ";heapBasicLoss:" << heapBasicLoss << ";expectFragmentSize" << expectFragmentSize; 1424514f5e3Sopenharmony_ci return fragmentSize >= expectFragmentSize; 1434514f5e3Sopenharmony_ci } 1444514f5e3Sopenharmony_ci 1454514f5e3Sopenharmony_ci template<class T> 1464514f5e3Sopenharmony_ci bool HintGCInLowDegree(const T *baseHeap) const 1474514f5e3Sopenharmony_ci { 1484514f5e3Sopenharmony_ci return CheckIdleOrHintOldGC<T>(baseHeap); 1494514f5e3Sopenharmony_ci } 1504514f5e3Sopenharmony_ci 1514514f5e3Sopenharmony_ci template<class T> 1524514f5e3Sopenharmony_ci bool HintGCInMiddleDegree(const T *baseHeap) const 1534514f5e3Sopenharmony_ci { 1544514f5e3Sopenharmony_ci return CheckIdleOrHintOldGC<T>(baseHeap); 1554514f5e3Sopenharmony_ci } 1564514f5e3Sopenharmony_ci 1574514f5e3Sopenharmony_ci template<class T> 1584514f5e3Sopenharmony_ci bool HintGCInHighDegree(const T *baseHeap) const 1594514f5e3Sopenharmony_ci { 1604514f5e3Sopenharmony_ci return CheckIdleOrHintFullGC<T>(baseHeap); 1614514f5e3Sopenharmony_ci } 1624514f5e3Sopenharmony_ci 1634514f5e3Sopenharmony_ciprivate: 1644514f5e3Sopenharmony_ci void PostIdleGCTask(TRIGGER_IDLE_GC_TYPE gcType); 1654514f5e3Sopenharmony_ci 1664514f5e3Sopenharmony_ci Heap *heap_ {nullptr}; 1674514f5e3Sopenharmony_ci SharedHeap *sHeap_ {nullptr}; 1684514f5e3Sopenharmony_ci JSThread *thread_ {nullptr}; 1694514f5e3Sopenharmony_ci bool optionalLogEnabled_ {false}; 1704514f5e3Sopenharmony_ci 1714514f5e3Sopenharmony_ci std::atomic<bool> idleState_ {false}; 1724514f5e3Sopenharmony_ci uint8_t gcTaskPostedState_ {0}; 1734514f5e3Sopenharmony_ci TriggerGCTaskCallback triggerGCTaskCallback_ {nullptr}; 1744514f5e3Sopenharmony_ci}; 1754514f5e3Sopenharmony_ci 1764514f5e3Sopenharmony_ci} 1774514f5e3Sopenharmony_ci 1784514f5e3Sopenharmony_ci#endif // ECMASCRIPT_MEM_GC_TRIGGER_H