• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 panda::mem::test {
24 
25 class HeapSpaceTest : public testing::Test {
26 public:
HeapSpaceTest()27     explicit HeapSpaceTest()
28     {
29         // Logger::InitializeStdLogging(Logger::Level::DEBUG, Logger::Component::ALL);
30     };
31 
~HeapSpaceTest()32     ~HeapSpaceTest()
33     {
34         // Logger::Destroy();
35     }
36 
37 protected:
38     static constexpr size_t DEFAULT_TEST_HEAP_SIZE = 64_MB;
39     static constexpr size_t DEFAULT_TEST_YOUNG_SIZE = 4_MB;
40 
GetCurrentMaxSize() const41     size_t GetCurrentMaxSize() const
42     {
43         return heap_space_->GetCurrentSize();
44     }
45 
GetCurrentYoungMaxSize() const46     size_t GetCurrentYoungMaxSize() const
47     {
48         return gen_spaces_->GetCurrentMaxYoungSize();
49     }
50 
GetCurrentTenuredMaxSize() const51     size_t GetCurrentTenuredMaxSize() const
52     {
53         return gen_spaces_->GetCurrentSize();
54     }
55 
56     struct HeapSpaceHolder {
HeapSpaceHolderpanda::mem::test::HeapSpaceTest::HeapSpaceHolder57         HeapSpaceHolder(size_t initial_heap_size = DEFAULT_TEST_HEAP_SIZE,
58                         size_t max_heap_size = DEFAULT_TEST_HEAP_SIZE, uint32_t min_percentage = 30U,
59                         uint32_t max_percentage = 70U)
60         {
61             MemConfig::Initialize(max_heap_size, 0_MB, 0_MB, 0_MB, initial_heap_size);
62             PoolManager::Initialize();
63             HeapSpaceTest::heap_space_ = new HeapSpace();
64             HeapSpaceTest::heap_space_->Initialize(MemConfig::GetInitialHeapSizeLimit(), MemConfig::GetHeapSizeLimit(),
65                                                    min_percentage, max_percentage);
66         }
67 
~HeapSpaceHolderpanda::mem::test::HeapSpaceTest::HeapSpaceHolder68         ~HeapSpaceHolder() noexcept
69         {
70             delete HeapSpaceTest::heap_space_;
71             HeapSpaceTest::heap_space_ = nullptr;
72             PoolManager::Finalize();
73             MemConfig::Finalize();
74         }
75     };
76 
77     struct GenerationalSpacesHolder {
GenerationalSpacesHolderpanda::mem::test::HeapSpaceTest::GenerationalSpacesHolder78         GenerationalSpacesHolder(size_t init_young_size = DEFAULT_TEST_YOUNG_SIZE,
79                                  size_t young_size = DEFAULT_TEST_YOUNG_SIZE,
80                                  size_t initial_heap_size = DEFAULT_TEST_HEAP_SIZE,
81                                  size_t max_heap_size = DEFAULT_TEST_HEAP_SIZE, uint32_t min_percentage = 0U,
82                                  uint32_t max_percentage = PERCENT_100_U32)
83         {
84             MemConfig::Initialize(max_heap_size, 0_MB, 0_MB, 0_MB, initial_heap_size);
85             PoolManager::Initialize();
86             HeapSpaceTest::gen_spaces_ = new GenerationalSpaces();
87             HeapSpaceTest::gen_spaces_->Initialize(init_young_size, true, young_size, true,
88                                                    MemConfig::GetInitialHeapSizeLimit(), MemConfig::GetHeapSizeLimit(),
89                                                    min_percentage, max_percentage);
90         }
91 
~GenerationalSpacesHolderpanda::mem::test::HeapSpaceTest::GenerationalSpacesHolder92         ~GenerationalSpacesHolder() noexcept
93         {
94             delete HeapSpaceTest::gen_spaces_;
95             HeapSpaceTest::gen_spaces_ = nullptr;
96             PoolManager::Finalize();
97             MemConfig::Finalize();
98         }
99     };
100 
101     static HeapSpace *heap_space_;
102     static GenerationalSpaces *gen_spaces_;
103 };
104 
105 HeapSpace *HeapSpaceTest::heap_space_ = nullptr;
106 GenerationalSpaces *HeapSpaceTest::gen_spaces_ = nullptr;
107 
TEST_F(HeapSpaceTest,AllocFreeAndCheckSizesTest)108 TEST_F(HeapSpaceTest, AllocFreeAndCheckSizesTest)
109 {
110     HeapSpaceHolder hsh;
111 
112     auto pool_1 =
113         heap_space_->TryAllocPool(4_MB, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR, nullptr);
114     ASSERT_NE(pool_1, NULLPOOL);
115     auto pool_2 =
116         heap_space_->TryAllocPool(6_MB, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR, nullptr);
117     ASSERT_NE(pool_2, NULLPOOL);
118 
119     ASSERT_EQ(heap_space_->GetHeapSize(), 10_MB);
120 
121     heap_space_->FreePool(pool_1.GetMem(), pool_1.GetSize());
122     ASSERT_EQ(heap_space_->GetHeapSize(), 6_MB);
123     auto *arena_1 =
124         heap_space_->TryAllocArena(6_MB, SpaceType::SPACE_TYPE_OBJECT, AllocatorType::FREELIST_ALLOCATOR, nullptr);
125     ASSERT_NE(arena_1, nullptr);
126     ASSERT_EQ(heap_space_->GetHeapSize(), 12_MB);
127     heap_space_->FreePool(pool_2.GetMem(), pool_2.GetSize());
128     ASSERT_EQ(heap_space_->GetHeapSize(), 6_MB);
129     heap_space_->FreeArena(arena_1);
130     ASSERT_EQ(heap_space_->GetHeapSize(), 0_MB);
131 }
132 
TEST_F(HeapSpaceTest,EmulateAllocBeforeAndAfterSTWGCTest)133 TEST_F(HeapSpaceTest, EmulateAllocBeforeAndAfterSTWGCTest)
134 {
135     static constexpr size_t INIT_HEAP_SIZE = 4_MB;
136     static constexpr size_t FIRST_POOL_SIZE = INIT_HEAP_SIZE / 2;
137     static constexpr size_t SECOND_POOL_SIZE = INIT_HEAP_SIZE * 3 / 4;
138     HeapSpaceHolder hsh(INIT_HEAP_SIZE, 2 * INIT_HEAP_SIZE, 0U, PERCENT_100_U32);
139 
140     ASSERT_EQ(GetCurrentMaxSize(), INIT_HEAP_SIZE) << "Current heap limit must be equal initial heap size";
141     auto pool_1 = heap_space_->TryAllocPool(FIRST_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
142                                             AllocatorType::FREELIST_ALLOCATOR, nullptr);
143     ASSERT_NE(pool_1, NULLPOOL);
144     // -- Emulate simple GC
145     heap_space_->ComputeNewSize();
146     ASSERT_EQ(GetCurrentMaxSize(), INIT_HEAP_SIZE);
147     // --
148     auto pool_2 = heap_space_->TryAllocPool(SECOND_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
149                                             AllocatorType::FREELIST_ALLOCATOR, nullptr);
150     ASSERT_EQ(pool_2, NULLPOOL) << "We now can't allocate pool";
151     // -- Emulate simple GC
152     heap_space_->ComputeNewSize();
153     ASSERT_EQ(GetCurrentMaxSize(), FIRST_POOL_SIZE + SECOND_POOL_SIZE);
154     // --
155     pool_2 = heap_space_->TryAllocPool(SECOND_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
156                                        AllocatorType::FREELIST_ALLOCATOR, nullptr);
157     ASSERT_NE(pool_2, NULLPOOL);
158     heap_space_->FreePool(pool_1.GetMem(), pool_1.GetSize());
159     // -- Emulate simple GC
160     heap_space_->ComputeNewSize();
161     ASSERT_EQ(GetCurrentMaxSize(), FIRST_POOL_SIZE + SECOND_POOL_SIZE);
162     // --
163     heap_space_->FreePool(pool_2.GetMem(), pool_2.GetSize());
164 }
165 
TEST_F(HeapSpaceTest,EmulateAllocBeforeAndDuringGenGCTest)166 TEST_F(HeapSpaceTest, EmulateAllocBeforeAndDuringGenGCTest)
167 {
168     static constexpr size_t INIT_HEAP_SIZE = 16_MB;
169     static constexpr size_t FIRST_POOL_SIZE = 4_MB;
170     static constexpr size_t SECOND_POOL_SIZE = 10_MB;
171     GenerationalSpacesHolder gsh(DEFAULT_TEST_YOUNG_SIZE, DEFAULT_TEST_YOUNG_SIZE, INIT_HEAP_SIZE, INIT_HEAP_SIZE * 2);
172     auto young_pool = gen_spaces_->AllocAlonePoolForYoung(SpaceType::SPACE_TYPE_OBJECT,
173                                                           AllocatorType::BUMP_ALLOCATOR_WITH_TLABS, nullptr);
174     // Check young pool allocation
175     ASSERT_NE(young_pool, NULLPOOL);
176     ASSERT_EQ(young_pool.GetSize(), DEFAULT_TEST_YOUNG_SIZE);
177     // Check current heap space sizes before "runtime work"
178     ASSERT_EQ(GetCurrentYoungMaxSize(), DEFAULT_TEST_YOUNG_SIZE);
179     ASSERT_EQ(GetCurrentTenuredMaxSize(), INIT_HEAP_SIZE - DEFAULT_TEST_YOUNG_SIZE);
180 
181     auto pool_1 = gen_spaces_->TryAllocPoolForYoung(FIRST_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
182                                                     AllocatorType::FREELIST_ALLOCATOR, nullptr);
183     ASSERT_EQ(pool_1, NULLPOOL);
184     // -- Emulate simple GC
185     gen_spaces_->SetIsWorkGC(true);
186     pool_1 = gen_spaces_->TryAllocPoolForTenured(FIRST_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
187                                                  AllocatorType::RUNSLOTS_ALLOCATOR, nullptr);
188     ASSERT_EQ(pool_1.GetSize(), FIRST_POOL_SIZE);
189     gen_spaces_->ComputeNewSize();
190     ASSERT_EQ(GetCurrentYoungMaxSize(), DEFAULT_TEST_YOUNG_SIZE);
191     ASSERT_EQ(GetCurrentTenuredMaxSize(), INIT_HEAP_SIZE - DEFAULT_TEST_YOUNG_SIZE);
192     // --
193     // Try too big pool, now no space for such pool
194     auto pool_2 = gen_spaces_->TryAllocPoolForTenured(SECOND_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
195                                                       AllocatorType::FREELIST_ALLOCATOR, nullptr);
196     ASSERT_EQ(pool_2, NULLPOOL) << "Now no space for such pool, so we must have NULLPOOL";
197     // -- Emulate simple GC
198     gen_spaces_->SetIsWorkGC(true);
199     ASSERT_TRUE(gen_spaces_->CanAllocInSpace(false, SECOND_POOL_SIZE)) << "We can allocate pool during GC";
200     pool_2 = gen_spaces_->TryAllocPoolForTenured(SECOND_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
201                                                  AllocatorType::FREELIST_ALLOCATOR, nullptr);
202     ASSERT_EQ(pool_2.GetSize(), SECOND_POOL_SIZE) << "We can allocate pool during GC";
203     ASSERT_EQ(GetCurrentTenuredMaxSize(), FIRST_POOL_SIZE + SECOND_POOL_SIZE);
204     gen_spaces_->ComputeNewSize();
205     ASSERT_EQ(GetCurrentTenuredMaxSize(), FIRST_POOL_SIZE + 2 * SECOND_POOL_SIZE);
206     // --
207     gen_spaces_->FreePool(pool_2.GetMem(), pool_2.GetSize());
208     gen_spaces_->FreePool(pool_1.GetMem(), pool_1.GetSize());
209     gen_spaces_->FreeYoungPool(young_pool.GetMem(), young_pool.GetSize());
210 }
211 
TEST_F(HeapSpaceTest,SharedPoolTest)212 TEST_F(HeapSpaceTest, SharedPoolTest)
213 {
214     static constexpr size_t INIT_HEAP_SIZE = 32_MB;
215     static constexpr size_t INIT_YOUNG_SIZE = 2_MB;
216     static constexpr size_t MAX_YOUNG_SIZE = 8_MB;
217     static constexpr size_t SHARED_POOL_SIZE = 8_MB;
218     static constexpr size_t REGION_SIZE = 1_MB;
219     static constexpr bool IS_YOUNG = true;
220     GenerationalSpacesHolder gsh(INIT_YOUNG_SIZE, MAX_YOUNG_SIZE, INIT_HEAP_SIZE);
221     auto shared_pool = gen_spaces_->AllocSharedPool(SHARED_POOL_SIZE, SpaceType::SPACE_TYPE_OBJECT,
222                                                     AllocatorType::REGION_ALLOCATOR, nullptr);
223     ASSERT_EQ(shared_pool.GetSize(), SHARED_POOL_SIZE);
224     ASSERT_EQ(GetCurrentYoungMaxSize(), INIT_YOUNG_SIZE);
225     ASSERT_EQ(GetCurrentTenuredMaxSize(), INIT_HEAP_SIZE - INIT_YOUNG_SIZE);
226     ASSERT_TRUE(gen_spaces_->CanAllocInSpace(IS_YOUNG, INIT_YOUNG_SIZE));
227     ASSERT_TRUE(gen_spaces_->CanAllocInSpace(!IS_YOUNG, INIT_YOUNG_SIZE));
228     gen_spaces_->IncreaseYoungOccupiedInSharedPool(REGION_SIZE);
229     gen_spaces_->IncreaseTenuredOccupiedInSharedPool(REGION_SIZE);
230     ASSERT_FALSE(gen_spaces_->CanAllocInSpace(IS_YOUNG, INIT_YOUNG_SIZE));
231     ASSERT_TRUE(gen_spaces_->CanAllocInSpace(!IS_YOUNG, INIT_YOUNG_SIZE));
232     auto pool_1 = gen_spaces_->TryAllocPoolForTenured(REGION_SIZE, SpaceType::SPACE_TYPE_OBJECT,
233                                                       AllocatorType::REGION_ALLOCATOR, nullptr);
234     ASSERT_EQ(pool_1.GetSize(), REGION_SIZE);
235     gen_spaces_->ReduceYoungOccupiedInSharedPool(REGION_SIZE);
236     ASSERT_TRUE(gen_spaces_->CanAllocInSpace(IS_YOUNG, INIT_YOUNG_SIZE));
237     gen_spaces_->ReduceTenuredOccupiedInSharedPool(REGION_SIZE);
238     ASSERT_TRUE(gen_spaces_->CanAllocInSpace(IS_YOUNG, INIT_YOUNG_SIZE));
239     ASSERT_TRUE(gen_spaces_->CanAllocInSpace(!IS_YOUNG, INIT_YOUNG_SIZE));
240     gen_spaces_->FreeTenuredPool(pool_1.GetMem(), pool_1.GetSize());
241     gen_spaces_->FreeSharedPool(shared_pool.GetMem(), shared_pool.GetSize());
242 }
243 
244 }  // namespace panda::mem::test
245