1 /**
2 * Copyright (c) 2021-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 #include <gtest/gtest.h>
17
18 #include "libpandabase/utils/logger.h"
19 #include "libpandabase/mem/mem_config.h"
20 #include "libpandabase/mem/pool_manager.h"
21 #include "runtime/mem/heap_space.h"
22
23 namespace ark::mem::test {
24
25 class HeapSpaceTest : public testing::Test {
26 public:
27 explicit HeapSpaceTest() = default;
28
29 NO_COPY_SEMANTIC(HeapSpaceTest);
30 NO_MOVE_SEMANTIC(HeapSpaceTest);
31
32 ~HeapSpaceTest() override = default;
33
34 protected:
35 static constexpr size_t DEFAULT_TEST_HEAP_SIZE = 64_MB;
36 static constexpr size_t DEFAULT_TEST_YOUNG_SIZE = 4_MB;
37 static constexpr size_t DEFAULT_MIN_PERCENTAGE = 30U;
38 static constexpr size_t DEFAULT_MAX_PERCENTAGE = 70U;
39
GetCurrentMaxSize() const40 size_t GetCurrentMaxSize() const
41 {
42 return heapSpace_->GetCurrentSize();
43 }
44
GetCurrentYoungMaxSize() const45 size_t GetCurrentYoungMaxSize() const
46 {
47 return genSpaces_->GetCurrentYoungSize();
48 }
49
GetCurrentTenuredMaxSize() const50 size_t GetCurrentTenuredMaxSize() const
51 {
52 return genSpaces_->GetCurrentSize();
53 }
54
55 struct HeapSpaceHolder {
56 NO_COPY_SEMANTIC(HeapSpaceHolder);
57 NO_MOVE_SEMANTIC(HeapSpaceHolder);
58
HeapSpaceHolderark::mem::test::HeapSpaceTest::HeapSpaceHolder59 explicit HeapSpaceHolder(size_t initialHeapSize = DEFAULT_TEST_HEAP_SIZE,
60 size_t maxHeapSize = DEFAULT_TEST_HEAP_SIZE,
61 uint32_t minPercentage = DEFAULT_MIN_PERCENTAGE,
62 uint32_t maxPercentage = DEFAULT_MAX_PERCENTAGE)
63 {
64 MemConfig::Initialize(maxHeapSize, 0_MB, 0_MB, 0_MB, 0_MB, 0_MB, initialHeapSize);
65 PoolManager::Initialize();
66 HeapSpaceTest::heapSpace_ = new HeapSpace();
67 HeapSpaceTest::heapSpace_->Initialize(MemConfig::GetInitialHeapSizeLimit(), MemConfig::GetHeapSizeLimit(),
68 minPercentage, maxPercentage);
69 }
70
~HeapSpaceHolderark::mem::test::HeapSpaceTest::HeapSpaceHolder71 ~HeapSpaceHolder() noexcept
72 {
73 delete HeapSpaceTest::heapSpace_;
74 HeapSpaceTest::heapSpace_ = nullptr;
75 PoolManager::Finalize();
76 MemConfig::Finalize();
77 }
78 };
79
80 struct GenerationalSpacesHolder {
81 NO_COPY_SEMANTIC(GenerationalSpacesHolder);
82 NO_MOVE_SEMANTIC(GenerationalSpacesHolder);
83
GenerationalSpacesHolderark::mem::test::HeapSpaceTest::GenerationalSpacesHolder84 explicit GenerationalSpacesHolder(size_t initYoungSize = DEFAULT_TEST_YOUNG_SIZE,
85 size_t youngSize = DEFAULT_TEST_YOUNG_SIZE,
86 size_t initialHeapSize = DEFAULT_TEST_HEAP_SIZE,
87 size_t maxHeapSize = DEFAULT_TEST_HEAP_SIZE, uint32_t minPercentage = 0U,
88 uint32_t maxPercentage = PERCENT_100_U32)
89 {
90 MemConfig::Initialize(maxHeapSize, 0_MB, 0_MB, 0_MB, 0_MB, 0_MB, initialHeapSize);
91 PoolManager::Initialize();
92 HeapSpaceTest::genSpaces_ = new GenerationalSpaces();
93 HeapSpaceTest::genSpaces_->Initialize(initYoungSize, true, youngSize, true,
94 MemConfig::GetInitialHeapSizeLimit(), MemConfig::GetHeapSizeLimit(),
95 minPercentage, maxPercentage);
96 }
97
~GenerationalSpacesHolderark::mem::test::HeapSpaceTest::GenerationalSpacesHolder98 ~GenerationalSpacesHolder() noexcept
99 {
100 delete HeapSpaceTest::genSpaces_;
101 HeapSpaceTest::genSpaces_ = nullptr;
102 PoolManager::Finalize();
103 MemConfig::Finalize();
104 }
105 };
106
107 static HeapSpace *heapSpace_;
108 static GenerationalSpaces *genSpaces_;
109 };
110
111 HeapSpace *HeapSpaceTest::heapSpace_ = nullptr;
112 GenerationalSpaces *HeapSpaceTest::genSpaces_ = nullptr;
113
TEST_F(HeapSpaceTest,AllocFreeAndCheckSizesTest)114 TEST_F(HeapSpaceTest, AllocFreeAndCheckSizesTest)
115 {
116 HeapSpaceHolder hsh;
117
118 auto pool1 =
119 heapSpace_->TryAllocPool(4_MB, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR, nullptr);
120 ASSERT_NE(pool1, NULLPOOL);
121 auto pool2 =
122 heapSpace_->TryAllocPool(6_MB, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR, nullptr);
123 ASSERT_NE(pool2, NULLPOOL);
124
125 ASSERT_EQ(heapSpace_->GetHeapSize(), 10_MB);
126
127 heapSpace_->FreePool(pool1.GetMem(), pool1.GetSize());
128 ASSERT_EQ(heapSpace_->GetHeapSize(), 6_MB);
129 auto *arena1 =
130 heapSpace_->TryAllocArena(6_MB, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR, nullptr);
131 ASSERT_NE(arena1, nullptr);
132 ASSERT_EQ(heapSpace_->GetHeapSize(), 12_MB);
133 heapSpace_->FreePool(pool2.GetMem(), pool2.GetSize());
134 ASSERT_EQ(heapSpace_->GetHeapSize(), 6_MB);
135 heapSpace_->FreeArena(arena1);
136 ASSERT_EQ(heapSpace_->GetHeapSize(), 0_MB);
137 }
138
TEST_F(HeapSpaceTest,EmulateAllocBeforeAndAfterSTWGCTest)139 TEST_F(HeapSpaceTest, EmulateAllocBeforeAndAfterSTWGCTest)
140 {
141 static constexpr size_t INIT_HEAP_SIZE = 4_MB;
142 static constexpr size_t FIRST_POOL_SIZE = INIT_HEAP_SIZE / 2U;
143 static constexpr size_t SECOND_POOL_SIZE = INIT_HEAP_SIZE * 3U / 4U;
144 HeapSpaceHolder hsh(INIT_HEAP_SIZE, 2U * INIT_HEAP_SIZE, 0U, PERCENT_100_U32);
145
146 ASSERT_EQ(GetCurrentMaxSize(), INIT_HEAP_SIZE) << "Current heap limit must be equal initial heap size";
147 auto pool1 = heapSpace_->TryAllocPool(FIRST_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
148 AllocatorType::FREELIST_ALLOCATOR, nullptr);
149 ASSERT_NE(pool1, NULLPOOL);
150 // -- Emulate simple GC
151 heapSpace_->ComputeNewSize();
152 ASSERT_EQ(GetCurrentMaxSize(), INIT_HEAP_SIZE);
153 // --
154 auto pool2 = heapSpace_->TryAllocPool(SECOND_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
155 AllocatorType::FREELIST_ALLOCATOR, nullptr);
156 ASSERT_EQ(pool2, NULLPOOL) << "We now can't allocate pool";
157 // -- Emulate simple GC
158 heapSpace_->ComputeNewSize();
159 ASSERT_EQ(GetCurrentMaxSize(), FIRST_POOL_SIZE + SECOND_POOL_SIZE);
160 // --
161 pool2 = heapSpace_->TryAllocPool(SECOND_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR,
162 nullptr);
163 ASSERT_NE(pool2, NULLPOOL);
164 heapSpace_->FreePool(pool1.GetMem(), pool1.GetSize());
165 // -- Emulate simple GC
166 heapSpace_->ComputeNewSize();
167 ASSERT_EQ(GetCurrentMaxSize(), FIRST_POOL_SIZE + SECOND_POOL_SIZE);
168 // --
169 heapSpace_->FreePool(pool2.GetMem(), pool2.GetSize());
170 }
171
TEST_F(HeapSpaceTest,EmulateAllocBeforeAndDuringGenGCTest)172 TEST_F(HeapSpaceTest, EmulateAllocBeforeAndDuringGenGCTest)
173 {
174 static constexpr size_t INIT_HEAP_SIZE = 16_MB;
175 static constexpr size_t FIRST_POOL_SIZE = 4_MB;
176 static constexpr size_t SECOND_POOL_SIZE = 10_MB;
177 GenerationalSpacesHolder gsh(DEFAULT_TEST_YOUNG_SIZE, DEFAULT_TEST_YOUNG_SIZE, INIT_HEAP_SIZE, INIT_HEAP_SIZE * 2U);
178 auto youngPool = genSpaces_->AllocAlonePoolForYoung(SpaceType::SPACE_TYPE_OBJECT,
179 AllocatorType::BUMP_ALLOCATOR_WITH_TLABS, nullptr);
180 // Check young pool allocation
181 ASSERT_NE(youngPool, NULLPOOL);
182 ASSERT_EQ(youngPool.GetSize(), DEFAULT_TEST_YOUNG_SIZE);
183 // Check current heap space sizes before "runtime work"
184 ASSERT_EQ(GetCurrentYoungMaxSize(), DEFAULT_TEST_YOUNG_SIZE);
185 ASSERT_EQ(GetCurrentTenuredMaxSize(), INIT_HEAP_SIZE - DEFAULT_TEST_YOUNG_SIZE);
186
187 auto pool1 = genSpaces_->TryAllocPoolForYoung(FIRST_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
188 AllocatorType::FREELIST_ALLOCATOR, nullptr);
189 ASSERT_EQ(pool1, NULLPOOL);
190 // -- Emulate simple GC
191 genSpaces_->SetIsWorkGC(true);
192 pool1 = genSpaces_->TryAllocPoolForTenured(FIRST_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
193 AllocatorType::RUNSLOTS_ALLOCATOR, nullptr);
194 ASSERT_EQ(pool1.GetSize(), FIRST_POOL_SIZE);
195 genSpaces_->ComputeNewSize();
196 ASSERT_EQ(GetCurrentYoungMaxSize(), DEFAULT_TEST_YOUNG_SIZE);
197 ASSERT_EQ(GetCurrentTenuredMaxSize(), INIT_HEAP_SIZE - DEFAULT_TEST_YOUNG_SIZE);
198 // --
199 // Try too big pool, now no space for such pool
200 auto pool2 = genSpaces_->TryAllocPoolForTenured(SECOND_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
201 AllocatorType::FREELIST_ALLOCATOR, nullptr);
202 ASSERT_EQ(pool2, NULLPOOL) << "Now no space for such pool, so we must have NULLPOOL";
203 // -- Emulate simple GC
204 genSpaces_->SetIsWorkGC(true);
205 ASSERT_TRUE(genSpaces_->CanAllocInSpace(false, SECOND_POOL_SIZE)) << "We can allocate pool during GC";
206 pool2 = genSpaces_->TryAllocPoolForTenured(SECOND_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
207 AllocatorType::FREELIST_ALLOCATOR, nullptr);
208 ASSERT_EQ(pool2.GetSize(), SECOND_POOL_SIZE) << "We can allocate pool during GC";
209 ASSERT_EQ(GetCurrentTenuredMaxSize(), FIRST_POOL_SIZE + SECOND_POOL_SIZE);
210 genSpaces_->ComputeNewSize();
211 ASSERT_EQ(GetCurrentTenuredMaxSize(), FIRST_POOL_SIZE + 2U * SECOND_POOL_SIZE);
212 // --
213 genSpaces_->FreePool(pool2.GetMem(), pool2.GetSize());
214 genSpaces_->FreePool(pool1.GetMem(), pool1.GetSize());
215 genSpaces_->FreeYoungPool(youngPool.GetMem(), youngPool.GetSize());
216 }
217
TEST_F(HeapSpaceTest,SharedPoolTest)218 TEST_F(HeapSpaceTest, SharedPoolTest)
219 {
220 static constexpr size_t INIT_HEAP_SIZE = 32_MB;
221 static constexpr size_t INIT_YOUNG_SIZE = 2_MB;
222 static constexpr size_t MAX_YOUNG_SIZE = 8_MB;
223 static constexpr size_t SHARED_POOL_SIZE = 8_MB;
224 static constexpr size_t REGION_SIZE = 1_MB;
225 static constexpr bool IS_YOUNG = true;
226 GenerationalSpacesHolder gsh(INIT_YOUNG_SIZE, MAX_YOUNG_SIZE, INIT_HEAP_SIZE);
227 auto sharedPool = genSpaces_->AllocSharedPool(SHARED_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
228 AllocatorType::REGION_ALLOCATOR, nullptr);
229 ASSERT_EQ(sharedPool.GetSize(), SHARED_POOL_SIZE);
230 ASSERT_EQ(GetCurrentYoungMaxSize(), INIT_YOUNG_SIZE);
231 ASSERT_EQ(GetCurrentTenuredMaxSize(), INIT_HEAP_SIZE - INIT_YOUNG_SIZE);
232 ASSERT_TRUE(genSpaces_->CanAllocInSpace(IS_YOUNG, INIT_YOUNG_SIZE));
233 ASSERT_TRUE(genSpaces_->CanAllocInSpace(!IS_YOUNG, INIT_YOUNG_SIZE));
234 genSpaces_->IncreaseYoungOccupiedInSharedPool(REGION_SIZE);
235 genSpaces_->IncreaseTenuredOccupiedInSharedPool(REGION_SIZE);
236 ASSERT_FALSE(genSpaces_->CanAllocInSpace(IS_YOUNG, INIT_YOUNG_SIZE));
237 ASSERT_TRUE(genSpaces_->CanAllocInSpace(!IS_YOUNG, INIT_YOUNG_SIZE));
238 auto pool1 = genSpaces_->TryAllocPoolForTenured(REGION_SIZE, SpaceType::SPACE_TYPE_OBJECT,
239 AllocatorType::REGION_ALLOCATOR, nullptr);
240 ASSERT_EQ(pool1.GetSize(), REGION_SIZE);
241 genSpaces_->ReduceYoungOccupiedInSharedPool(REGION_SIZE);
242 ASSERT_TRUE(genSpaces_->CanAllocInSpace(IS_YOUNG, INIT_YOUNG_SIZE));
243 genSpaces_->ReduceTenuredOccupiedInSharedPool(REGION_SIZE);
244 ASSERT_TRUE(genSpaces_->CanAllocInSpace(IS_YOUNG, INIT_YOUNG_SIZE));
245 ASSERT_TRUE(genSpaces_->CanAllocInSpace(!IS_YOUNG, INIT_YOUNG_SIZE));
246 genSpaces_->FreeTenuredPool(pool1.GetMem(), pool1.GetSize());
247 genSpaces_->FreeSharedPool(sharedPool.GetMem(), sharedPool.GetSize());
248 }
249
TEST_F(HeapSpaceTest,ClampNewMaxSizeTest)250 TEST_F(HeapSpaceTest, ClampNewMaxSizeTest)
251 {
252 // NOLINTNEXTLINE(readability-magic-numbers)
253 HeapSpaceHolder hsh(10_MB, DEFAULT_TEST_HEAP_SIZE, 0U, PERCENT_100_U32);
254
255 auto pool1 =
256 heapSpace_->TryAllocPool(4_MB, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR, nullptr);
257 ASSERT_NE(pool1, NULLPOOL);
258 auto pool2 =
259 heapSpace_->TryAllocPool(6_MB, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR, nullptr);
260 ASSERT_NE(pool2, NULLPOOL);
261
262 ASSERT_EQ(heapSpace_->GetHeapSize(), 10_MB);
263
264 heapSpace_->ClampCurrentMaxHeapSize();
265 heapSpace_->SetIsWorkGC(true);
266
267 auto pool3 =
268 heapSpace_->TryAllocPool(6_MB, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR, nullptr);
269 ASSERT_EQ(pool3, NULLPOOL);
270
271 pool3 = heapSpace_->TryAllocPool(PANDA_DEFAULT_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
272 AllocatorType::FREELIST_ALLOCATOR, nullptr);
273 ASSERT_NE(pool3, NULLPOOL);
274
275 heapSpace_->FreePool(pool1.GetMem(), pool1.GetSize());
276 heapSpace_->FreePool(pool2.GetMem(), pool2.GetSize());
277 heapSpace_->FreePool(pool3.GetMem(), pool3.GetSize());
278 }
279
280 } // namespace ark::mem::test
281