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 #include "common_components/heap/allocator/allocator.h"
17 #include "common_components/heap/allocator/region_space.h"
18 #include "common_components/heap/collector/heuristic_gc_policy.h"
19 #include "common_components/heap/heap.h"
20 #include "common_components/tests/test_helper.h"
21
22 using namespace common;
23 namespace common::test {
24 class HeuristicGCPolicyTest : public common::test::BaseTestWithScope {
25 protected:
SetUpTestCase()26 static void SetUpTestCase()
27 {
28 BaseRuntime::GetInstance()->Init();
29 }
30
TearDownTestCase()31 static void TearDownTestCase()
32 {
33 BaseRuntime::GetInstance()->Fini();
34 }
35
SetUp()36 void SetUp() override
37 {
38 holder_ = ThreadHolder::CreateAndRegisterNewThreadHolder(nullptr);
39 scope_ = new ThreadHolder::TryBindMutatorScope(holder_);
40 }
41
TearDown()42 void TearDown() override
43 {
44 if (scope_ != nullptr) {
45 delete scope_;
46 scope_ = nullptr;
47 }
48 }
49
50 ThreadHolder *holder_ {nullptr};
51 ThreadHolder::TryBindMutatorScope *scope_ {nullptr};
52 };
53
HWTEST_F_L0(HeuristicGCPolicyTest,ShouldRestrainGCOnStartupOrSensitive_Test1)54 HWTEST_F_L0(HeuristicGCPolicyTest, ShouldRestrainGCOnStartupOrSensitive_Test1)
55 {
56 HeuristicGCPolicy gcPolicy;
57 gcPolicy.Init();
58 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP_FINISH);
59 gcPolicy.TryHeuristicGC();
60 EXPECT_FALSE(gcPolicy.ShouldRestrainGCOnStartupOrSensitive());
61 }
62
HWTEST_F_L0(HeuristicGCPolicyTest,ShouldRestrainGCOnStartupOrSensitive_Test2)63 HWTEST_F_L0(HeuristicGCPolicyTest, ShouldRestrainGCOnStartupOrSensitive_Test2)
64 {
65 HeuristicGCPolicy gcPolicy;
66 gcPolicy.Init();
67 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP);
68 EXPECT_TRUE(gcPolicy.ShouldRestrainGCOnStartupOrSensitive());
69
70 RegionSpace& theAllocator = reinterpret_cast<RegionSpace&>(Heap::GetHeap().GetAllocator());
71 auto allocated = theAllocator.GetAllocatedBytes();
72 auto param = BaseRuntime::GetInstance()->GetHeapParam();
73 auto size = param.heapSize * KB * HeuristicGCPolicy::COLD_STARTUP_PHASE1_GC_THRESHOLD_RATIO;
74 for (int i = 0; allocated < size; i++) {
75 uintptr_t addr = theAllocator.AllocOldRegion();
76 ASSERT_NE(addr, 0);
77 allocated = theAllocator.GetAllocatedBytes();
78 }
79
80 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP_FINISH);
81 EXPECT_FALSE(gcPolicy.ShouldRestrainGCOnStartupOrSensitive());
82
83 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP);
84 EXPECT_FALSE(gcPolicy.ShouldRestrainGCOnStartupOrSensitive());
85
86 theAllocator.GetOldSpace().AssembleRecentFull();
87 auto& fromSpace = theAllocator.GetFromSpace();
88 theAllocator.GetOldSpace().AssembleGarbageCandidates(fromSpace);
89 fromSpace.GetFromRegionList().ClearList();
90 allocated = theAllocator.GetAllocatedBytes();
91 EXPECT_EQ(allocated, 0);
92 }
93
HWTEST_F_L0(HeuristicGCPolicyTest,ShouldRestrainGCOnStartupOrSensitive_Test3)94 HWTEST_F_L0(HeuristicGCPolicyTest, ShouldRestrainGCOnStartupOrSensitive_Test3)
95 {
96 HeuristicGCPolicy gcPolicy;
97 gcPolicy.Init();
98 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP_PARTIALLY_FINISH);
99 EXPECT_TRUE(gcPolicy.ShouldRestrainGCOnStartupOrSensitive());
100
101 RegionSpace& theAllocator = reinterpret_cast<RegionSpace&>(Heap::GetHeap().GetAllocator());
102 auto allocated = theAllocator.GetAllocatedBytes();
103 auto param = BaseRuntime::GetInstance()->GetHeapParam();
104 auto size = param.heapSize * KB * HeuristicGCPolicy::COLD_STARTUP_PHASE2_GC_THRESHOLD_RATIO;
105 for (int i = 0; allocated < size; i++) {
106 uintptr_t addr = theAllocator.AllocOldRegion();
107 ASSERT_NE(addr, 0);
108 allocated = theAllocator.GetAllocatedBytes();
109 }
110
111 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP_FINISH);
112 EXPECT_FALSE(gcPolicy.ShouldRestrainGCOnStartupOrSensitive());
113
114 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP_PARTIALLY_FINISH);
115 EXPECT_FALSE(gcPolicy.ShouldRestrainGCOnStartupOrSensitive());
116
117 theAllocator.GetOldSpace().AssembleRecentFull();
118 auto& fromSpace = theAllocator.GetFromSpace();
119 theAllocator.GetOldSpace().AssembleGarbageCandidates(fromSpace);
120 fromSpace.GetFromRegionList().ClearList();
121 allocated = theAllocator.GetAllocatedBytes();
122 EXPECT_EQ(allocated, 0);
123 }
124
HWTEST_F_L0(HeuristicGCPolicyTest,NotifyNativeAllocation)125 HWTEST_F_L0(HeuristicGCPolicyTest, NotifyNativeAllocation)
126 {
127 HeuristicGCPolicy gcPolicy;
128 size_t initialNotified = gcPolicy.GetNotifiedNativeSize();
129 size_t initialObjects = gcPolicy.GetNativeHeapThreshold();
130
131 gcPolicy.NotifyNativeAllocation(NATIVE_IMMEDIATE_THRESHOLD / 2);
132
133 EXPECT_EQ(gcPolicy.GetNotifiedNativeSize(), initialNotified + NATIVE_IMMEDIATE_THRESHOLD / 2);
134 EXPECT_NE(gcPolicy.GetNativeHeapThreshold(), initialObjects + 1);
135 }
136
HWTEST_F_L0(HeuristicGCPolicyTest,NotifyNativeAllocation_TriggerByBytes)137 HWTEST_F_L0(HeuristicGCPolicyTest, NotifyNativeAllocation_TriggerByBytes)
138 {
139 HeuristicGCPolicy gcPolicy;
140 size_t initialNotified = gcPolicy.GetNotifiedNativeSize();
141 size_t initialObjects = gcPolicy.GetNativeHeapThreshold();
142
143 gcPolicy.NotifyNativeAllocation(NATIVE_IMMEDIATE_THRESHOLD + 1);
144
145 EXPECT_EQ(gcPolicy.GetNotifiedNativeSize(), initialNotified + NATIVE_IMMEDIATE_THRESHOLD + 1);
146 EXPECT_NE(gcPolicy.GetNativeHeapThreshold(), initialObjects + 1);
147 }
148
HWTEST_F_L0(HeuristicGCPolicyTest,TryHeuristicGC)149 HWTEST_F_L0(HeuristicGCPolicyTest, TryHeuristicGC)
150 {
151 HeuristicGCPolicy gcPolicy;
152 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP_FINISH);
153 Heap::GetHeap().GetCollector().GetGCStats().heapThreshold = 0;
154 gcPolicy.TryHeuristicGC();
155 Heap::GetHeap().GetCollector().GetGCStats().shouldRequestYoung = true;
156 gcPolicy.TryHeuristicGC();
157 EXPECT_EQ(Heap::GetHeap().GetAllocator().GetAllocatedBytes(),
158 Heap::GetHeap().GetCollector().GetGCStats().GetThreshold());
159 }
160
HWTEST_F_L0(HeuristicGCPolicyTest,ChangeGCParams)161 HWTEST_F_L0(HeuristicGCPolicyTest, ChangeGCParams)
162 {
163 HeuristicGCPolicy gcPolicy;
164 gcPolicy.RecordAliveSizeAfterLastGC(1);
165 gcPolicy.ChangeGCParams(true);
166 EXPECT_EQ(Heap::GetHeap().GetAllocator().GetAllocatedBytes(), 0);
167 }
168
HWTEST_F_L0(HeuristicGCPolicyTest,CheckAndTriggerHintGC)169 HWTEST_F_L0(HeuristicGCPolicyTest, CheckAndTriggerHintGC)
170 {
171 HeuristicGCPolicy gcPolicy;
172 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP);
173 bool result = gcPolicy.CheckAndTriggerHintGC(MemoryReduceDegree::HIGH);
174 ASSERT_FALSE(result);
175
176 StartupStatusManager::SetStartupStatus(StartupStatus::COLD_STARTUP_FINISH);
177 result = gcPolicy.CheckAndTriggerHintGC(MemoryReduceDegree::HIGH);
178 ASSERT_FALSE(result);
179
180 gcPolicy.RecordAliveSizeAfterLastGC(1);
181 result = gcPolicy.CheckAndTriggerHintGC(MemoryReduceDegree::HIGH);
182 ASSERT_FALSE(result);
183
184 result = gcPolicy.CheckAndTriggerHintGC(MemoryReduceDegree::LOW);
185 ASSERT_FALSE(result);
186 }
187
HWTEST_F_L0(HeuristicGCPolicyTest,NotifyNativeAllocation_TriggerByBytes1)188 HWTEST_F_L0(HeuristicGCPolicyTest, NotifyNativeAllocation_TriggerByBytes1)
189 {
190 HeuristicGCPolicy gcPolicy;
191 size_t initialNotified = gcPolicy.GetNotifiedNativeSize();
192 size_t initialObjects = gcPolicy.GetNativeHeapThreshold();
193
194 gcPolicy.SetNativeHeapThreshold(1);
195 gcPolicy.NotifyNativeAllocation(NATIVE_IMMEDIATE_THRESHOLD + 1);
196
197 EXPECT_EQ(gcPolicy.GetNotifiedNativeSize(), initialNotified + NATIVE_IMMEDIATE_THRESHOLD + 1);
198 EXPECT_NE(gcPolicy.GetNativeHeapThreshold(), initialObjects + 1);
199 }
200 } // namespace common::test