1 /* 2 * Copyright (c) 2025 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 COMMON_COMPONENTS_HEAP_HEURISTIC_GC_POLICY_H 17 #define COMMON_COMPONENTS_HEAP_HEURISTIC_GC_POLICY_H 18 19 #include "common_components/base/globals.h" 20 #include "common_interfaces/base_runtime.h" 21 #include "common_components/taskpool/taskpool.h" 22 #include "common_components/log/log.h" 23 24 namespace common { 25 enum class StartupStatus: uint8_t { 26 BEFORE_STARTUP, 27 COLD_STARTUP, 28 COLD_STARTUP_PARTIALLY_FINISH, 29 COLD_STARTUP_FINISH, 30 }; 31 32 enum AppSensitiveStatus : uint8_t { 33 NORMAL_SCENE, 34 ENTER_HIGH_SENSITIVE, 35 EXIT_HIGH_SENSITIVE, 36 }; 37 38 class StartupStatusManager { 39 public: 40 static std::atomic<StartupStatus> startupStatus_; 41 static constexpr size_t STARTUP_DURATION_MS = 2000; 42 static constexpr size_t STARTUP_FINISH_DURATION_MS = 8000; 43 44 static void OnAppStartup(); 45 SetStartupStatus(StartupStatus status)46 static void SetStartupStatus(StartupStatus status) 47 { 48 startupStatus_ = status; 49 } 50 GetStartupStatus()51 static StartupStatus GetStartupStatus() 52 { 53 return startupStatus_.load(std::memory_order_relaxed); 54 } 55 56 private: 57 class StartupFinishTask : public common::Task { 58 public: StartupFinishTask(uint32_t id)59 StartupFinishTask(uint32_t id) : Task(id) {} Run(uint32_t threadIndex)60 bool Run([[maybe_unused]] uint32_t threadIndex) override 61 { 62 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP_FINISH); 63 return true; 64 } 65 }; 66 67 class StartupTask : public common::Task { 68 public: StartupTask(uint32_t id,Taskpool * pool,size_t delay)69 StartupTask(uint32_t id, Taskpool *pool, size_t delay) 70 : Task(id), threadPool_(pool), delay_(delay) {} Run(uint32_t threadIndex)71 bool Run([[maybe_unused]] uint32_t threadIndex) override 72 { 73 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP_PARTIALLY_FINISH); 74 size_t startupFinishDelay = STARTUP_FINISH_DURATION_MS - delay_; 75 threadPool_->PostDelayedTask(std::make_unique<StartupFinishTask>(0), startupFinishDelay); 76 return true; 77 } 78 79 private: 80 Taskpool *threadPool_ {nullptr}; 81 size_t delay_ {0}; 82 }; 83 }; 84 85 static constexpr size_t NATIVE_MULTIPLIER = 2; 86 // Use interval to avoid gc request too frequent. 87 static constexpr size_t NOTIFY_NATIVE_INTERVAL = 32; 88 #if defined(PANDA_TARGET_32) 89 static constexpr size_t NATIVE_INIT_THRESHOLD = 100 * MB; 90 static constexpr size_t MAX_GLOBAL_NATIVE_LIMIT = 512 * MB; 91 static constexpr size_t MAX_NATIVE_STEP = 64 * MB; 92 static constexpr size_t MAX_NATIVE_SIZE_INC = 256 * MB; 93 static constexpr size_t NATIVE_IMMEDIATE_THRESHOLD = 300 * KB; 94 #else 95 static constexpr size_t NATIVE_INIT_THRESHOLD = 200 * MB; 96 static constexpr size_t MAX_GLOBAL_NATIVE_LIMIT = 2 * GB; 97 static constexpr size_t MAX_NATIVE_STEP = 200 * MB; 98 static constexpr size_t MAX_NATIVE_SIZE_INC = 1 * GB; 99 static constexpr size_t NATIVE_IMMEDIATE_THRESHOLD = 2 * MB; 100 #endif 101 static constexpr size_t URGENCY_NATIVE_LIMIT = MAX_NATIVE_SIZE_INC + MAX_NATIVE_STEP * 2; // 2 is double. 102 103 class HeuristicGCPolicy { 104 public: 105 static constexpr double COLD_STARTUP_PHASE1_GC_THRESHOLD_RATIO = 0.3; 106 static constexpr double COLD_STARTUP_PHASE2_GC_THRESHOLD_RATIO = 0.125; 107 void Init(); 108 109 bool ShouldRestrainGCOnStartupOrSensitive(); 110 111 void TryHeuristicGC(); 112 113 void TryIdleGC(); 114 115 bool ShouldRestrainGCInSensitive(size_t currentSize); 116 NotifyHighSensitive(bool isStart)117 void NotifyHighSensitive(bool isStart) 118 { 119 OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "SmartGC: set high sensitive status: ", 120 std::to_string(isStart).c_str()); 121 isStart ? SetSensitiveStatus(AppSensitiveStatus::ENTER_HIGH_SENSITIVE) 122 : SetSensitiveStatus(AppSensitiveStatus::EXIT_HIGH_SENSITIVE); 123 LOG_COMMON(INFO) << "SmartGC: set high sensitive status: " << isStart; 124 } 125 InSensitiveStatus()126 bool InSensitiveStatus() const 127 { 128 return GetSensitiveStatus() == AppSensitiveStatus::ENTER_HIGH_SENSITIVE; 129 } 130 OnStartupEvent()131 bool OnStartupEvent() const 132 { 133 return StartupStatusManager::GetStartupStatus() == StartupStatus::COLD_STARTUP; 134 } 135 136 StartupStatus GetStartupStatus() const; 137 SetSensitiveStatus(AppSensitiveStatus status)138 void SetSensitiveStatus(AppSensitiveStatus status) 139 { 140 sensitiveStatus_.store(status, std::memory_order_release); 141 } 142 GetSensitiveStatus()143 AppSensitiveStatus GetSensitiveStatus() const 144 { 145 return sensitiveStatus_.load(std::memory_order_acquire); 146 } 147 CASSensitiveStatus(AppSensitiveStatus expect,AppSensitiveStatus status)148 bool CASSensitiveStatus(AppSensitiveStatus expect, AppSensitiveStatus status) 149 { 150 return sensitiveStatus_.compare_exchange_strong(expect, status, std::memory_order_seq_cst); 151 } 152 SetRecordHeapObjectSizeBeforeSensitive(size_t objSize)153 void SetRecordHeapObjectSizeBeforeSensitive(size_t objSize) 154 { 155 recordSizeBeforeSensitive_.store(objSize, std::memory_order_release); 156 } 157 GetRecordHeapObjectSizeBeforeSensitive()158 size_t GetRecordHeapObjectSizeBeforeSensitive() const 159 { 160 return recordSizeBeforeSensitive_.load(std::memory_order_acquire); 161 } 162 163 void NotifyNativeAllocation(size_t bytes); 164 165 void NotifyNativeFree(size_t bytes); 166 167 void NotifyNativeReset(size_t oldBytes, size_t newBytes); 168 169 size_t GetNotifiedNativeSize() const; 170 171 void SetNativeHeapThreshold(size_t newThreshold); 172 173 size_t GetNativeHeapThreshold() const; 174 175 void RecordAliveSizeAfterLastGC(size_t aliveBytes); 176 177 void ChangeGCParams(bool isBackground); 178 179 bool CheckAndTriggerHintGC(MemoryReduceDegree degree); 180 #if defined(PANDA_TARGET_32) 181 static constexpr size_t INC_OBJ_SIZE_IN_SENSITIVE = 40 * MB; 182 #else 183 static constexpr size_t INC_OBJ_SIZE_IN_SENSITIVE = 80 * MB; 184 #endif 185 static constexpr size_t BACKGROUND_LIMIT = 2 * MB; 186 static constexpr size_t MIN_BACKGROUND_GC_SIZE = 30 * MB; 187 188 static constexpr double IDLE_MIN_INC_RATIO = 1.1f; 189 static constexpr size_t LOW_DEGREE_STEP_IN_IDLE = 5 * MB; 190 static constexpr size_t HIGH_DEGREE_STEP_IN_IDLE = 1 * MB; 191 192 static constexpr double IDLE_SPACE_SIZE_MIN_INC_RATIO = 1.1f; 193 static constexpr size_t IDLE_SPACE_SIZE_MIN_INC_STEP_FULL = 1 * MB; 194 195 private: 196 void CheckGCForNative(); 197 198 uint64_t heapSize_ {0}; 199 size_t aliveSizeAfterGC_ {0}; 200 201 std::atomic<size_t> notifiedNativeSize_ = 0; 202 std::atomic<size_t> nativeHeapThreshold_ = NATIVE_INIT_THRESHOLD; 203 std::atomic<size_t> nativeHeapObjects_ = 0; 204 205 std::atomic<AppSensitiveStatus> sensitiveStatus_ {AppSensitiveStatus::NORMAL_SCENE}; 206 std::atomic<size_t> recordSizeBeforeSensitive_ {0}; 207 }; 208 } // namespace common 209 210 #endif // COMMON_COMPONENTS_HEAP_HEURISTIC_GC_POLICY_H 211