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