• 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 <ctime>
17 
18 #include "gtest/gtest.h"
19 #include "runtime/mem/gc/heap-space-misc/crossing_map.h"
20 #include "runtime/mem/internal_allocator-inl.h"
21 
22 namespace ark::mem {
23 
24 class CrossingMapTest : public testing::Test {
25 public:
CrossingMapTest()26     CrossingMapTest()
27     {
28         // Logger::InitializeStdLogging(Logger::Level::DEBUG, Logger::Component::ALL);
29 #ifdef PANDA_NIGHTLY_TEST_ON
30         seed_ = std::time(NULL);
31 #else
32         // NOLINTNEXTLINE(readability-magic-numbers)
33         seed_ = 0xDEADBEEF;
34 #endif
35         srand(seed_);
36         ark::mem::MemConfig::Initialize(MEMORY_POOL_SIZE, MEMORY_POOL_SIZE, 0, 0, 0, 0);
37         PoolManager::Initialize();
38         startAddr_ = GetPoolMinAddress();
39         memStats_ = new mem::MemStatsType();
40         internalAllocator_ = new InternalAllocatorT<InternalAllocatorConfig::PANDA_ALLOCATORS>(memStats_);
41         crossingMap_ = new CrossingMap(internalAllocator_, startAddr_, GetPoolSize());
42         crossingMap_->Initialize();
43         crossingMap_->InitializeCrossingMapForMemory(ToVoidPtr(startAddr_), GetPoolSize());
44     }
45 
~CrossingMapTest()46     ~CrossingMapTest() override
47     {
48         crossingMap_->RemoveCrossingMapForMemory(ToVoidPtr(startAddr_), GetPoolSize());
49         crossingMap_->Destroy();
50         delete crossingMap_;
51         delete static_cast<Allocator *>(internalAllocator_);
52         PoolManager::Finalize();
53         ark::mem::MemConfig::Finalize();
54         // Logger::Destroy();
55         delete memStats_;
56     }
57 
58     NO_COPY_SEMANTIC(CrossingMapTest);
59     NO_MOVE_SEMANTIC(CrossingMapTest);
60 
61 protected:
GetCrossingMap()62     CrossingMap *GetCrossingMap()
63     {
64         return crossingMap_;
65     }
66 
GetRandomObjAddr(size_t size)67     void *GetRandomObjAddr(size_t size)
68     {
69         ASSERT(size < GetPoolSize());
70         // NOLINTNEXTLINE(cert-msc50-cpp)
71         uintptr_t randOffset = rand() % (GetPoolSize() - size);
72         randOffset = (randOffset >> CrossingMap::CROSSING_MAP_OBJ_ALIGNMENT) << CrossingMap::CROSSING_MAP_OBJ_ALIGNMENT;
73         return ToVoidPtr(startAddr_ + randOffset);
74     }
75 
AddPage(void * addr)76     void *AddPage(void *addr)
77     {
78         return ToVoidPtr(ToUintPtr(addr) + PAGE_SIZE);
79     }
80 
IncreaseAddr(void * addr,size_t value)81     void *IncreaseAddr(void *addr, size_t value)
82     {
83         return ToVoidPtr(ToUintPtr(addr) + value);
84     }
85 
DecreaseAddr(void * addr,size_t value)86     void *DecreaseAddr(void *addr, size_t value)
87     {
88         return ToVoidPtr(ToUintPtr(addr) - value);
89     }
90 
GetMapNumFromAddr(void * addr)91     size_t GetMapNumFromAddr(void *addr)
92     {
93         return crossingMap_->GetMapNumFromAddr(addr);
94     }
95 
96     static constexpr size_t MIN_GAP_BETWEEN_OBJECTS = 1U << CrossingMap::CROSSING_MAP_OBJ_ALIGNMENT;
97 
98     static constexpr size_t MEMORY_POOL_SIZE = 64_MB;
99 
100     static constexpr size_t POOLS_SIZE = CrossingMap::CROSSING_MAP_STATIC_ARRAY_GRANULARITY;
101 
GetPoolMinAddress()102     uintptr_t GetPoolMinAddress()
103     {
104         return PoolManager::GetMmapMemPool()->GetMinObjectAddress();
105     }
106 
GetPoolSize()107     size_t GetPoolSize()
108     {
109         return PoolManager::GetMmapMemPool()->GetMaxObjectAddress() -
110                PoolManager::GetMmapMemPool()->GetMinObjectAddress();
111     }
112 
GetLastObjectByte(void * objAddr,size_t objSize)113     void *GetLastObjectByte(void *objAddr, size_t objSize)
114     {
115         ASSERT(objSize != 0);
116         return ToVoidPtr(ToUintPtr(objAddr) + objSize - 1U);
117     }
118 
GetSeed()119     unsigned int GetSeed()
120     {
121         return seed_;
122     }
123 
124 private:
125     unsigned int seed_;
126     InternalAllocatorPtr internalAllocator_;
127     uintptr_t startAddr_;
128     CrossingMap *crossingMap_;
129     mem::MemStatsType *memStats_;
130 };
131 
TEST_F(CrossingMapTest,OneSmallObjTest)132 TEST_F(CrossingMapTest, OneSmallObjTest)
133 {
134     static constexpr size_t OBJ_SIZE = 1;
135     // Use OBJ_SIZE + PAGE_SIZE here or we can get an overflow during AddPage(obj_addr)
136     void *objAddr = GetRandomObjAddr(OBJ_SIZE + PAGE_SIZE);
137     GetCrossingMap()->AddObject(objAddr, OBJ_SIZE);
138     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(objAddr, objAddr) == objAddr) << " seed = " << GetSeed();
139     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(AddPage(objAddr), AddPage(objAddr)) == nullptr)
140         << " seed = " << GetSeed();
141 }
142 
TEST_F(CrossingMapTest,BigSmallObjTest)143 TEST_F(CrossingMapTest, BigSmallObjTest)
144 {
145     static constexpr size_t OBJ_SIZE = PAGE_SIZE * 2U;
146     void *objAddr = GetRandomObjAddr(OBJ_SIZE);
147     GetCrossingMap()->AddObject(objAddr, OBJ_SIZE);
148     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(objAddr, ToVoidPtr(ToUintPtr(objAddr) + OBJ_SIZE)) == objAddr)
149         << " seed = " << GetSeed();
150     if (PANDA_CROSSING_MAP_MANAGE_CROSSED_BORDER) {
151         ASSERT_TRUE(GetCrossingMap()->FindFirstObject(AddPage(objAddr), ToVoidPtr(ToUintPtr(objAddr) + OBJ_SIZE)) ==
152                     objAddr)
153             << " seed = " << GetSeed();
154     }
155     GetCrossingMap()->RemoveObject(objAddr, OBJ_SIZE);
156     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(objAddr, ToVoidPtr(ToUintPtr(objAddr) + OBJ_SIZE)) == nullptr)
157         << " seed = " << GetSeed();
158     if (PANDA_CROSSING_MAP_MANAGE_CROSSED_BORDER) {
159         ASSERT_TRUE(GetCrossingMap()->FindFirstObject(AddPage(objAddr), ToVoidPtr(ToUintPtr(objAddr) + OBJ_SIZE)) ==
160                     nullptr)
161             << " seed = " << GetSeed();
162     }
163 }
164 
TEST_F(CrossingMapTest,HugeObjTest)165 TEST_F(CrossingMapTest, HugeObjTest)
166 {
167     static constexpr size_t OBJ_SIZE = MEMORY_POOL_SIZE >> 1U;
168     void *objAddr = GetRandomObjAddr(OBJ_SIZE);
169     GetCrossingMap()->AddObject(objAddr, OBJ_SIZE);
170     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(objAddr, objAddr) == objAddr) << " seed = " << GetSeed();
171     if (PANDA_CROSSING_MAP_MANAGE_CROSSED_BORDER) {
172         for (size_t i = 1_MB; i < OBJ_SIZE; i += 1_MB) {
173             void *addr = ToVoidPtr(ToUintPtr(objAddr) + i);
174             ASSERT_TRUE(GetCrossingMap()->FindFirstObject(addr, addr) == objAddr) << " seed = " << GetSeed();
175         }
176     }
177     GetCrossingMap()->RemoveObject(objAddr, OBJ_SIZE);
178     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(objAddr, objAddr) == nullptr) << " seed = " << GetSeed();
179     if (PANDA_CROSSING_MAP_MANAGE_CROSSED_BORDER) {
180         for (size_t i = 1_MB; i < OBJ_SIZE; i += 1_MB) {
181             void *addr = ToVoidPtr(ToUintPtr(objAddr) + i);
182             ASSERT_TRUE(GetCrossingMap()->FindFirstObject(addr, addr) == nullptr) << " seed = " << GetSeed();
183         }
184     }
185 }
186 
TEST_F(CrossingMapTest,TwoSequentialObjectsTest)187 TEST_F(CrossingMapTest, TwoSequentialObjectsTest)
188 {
189     static constexpr size_t FIRST_OBJ_SIZE = MIN_GAP_BETWEEN_OBJECTS;
190     static constexpr size_t SECOND_OBJ_SIZE = 1_KB;
191     // Add some extra memory for possible shifts
192     void *firstObjAddr = GetRandomObjAddr(FIRST_OBJ_SIZE + SECOND_OBJ_SIZE + FIRST_OBJ_SIZE);
193     void *secondObjAddr = IncreaseAddr(firstObjAddr, FIRST_OBJ_SIZE);
194     // We must be sure that these objects will be saved in the same locations
195     if (GetMapNumFromAddr(firstObjAddr) != GetMapNumFromAddr(secondObjAddr)) {
196         firstObjAddr = IncreaseAddr(firstObjAddr, FIRST_OBJ_SIZE);
197         secondObjAddr = IncreaseAddr(firstObjAddr, FIRST_OBJ_SIZE);
198         ASSERT_TRUE(GetMapNumFromAddr(firstObjAddr) == GetMapNumFromAddr(secondObjAddr)) << " seed = " << GetSeed();
199     }
200     GetCrossingMap()->AddObject(firstObjAddr, FIRST_OBJ_SIZE);
201     GetCrossingMap()->AddObject(secondObjAddr, SECOND_OBJ_SIZE);
202 
203     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(firstObjAddr, firstObjAddr) == firstObjAddr)
204         << " seed = " << GetSeed();
205 
206     GetCrossingMap()->RemoveObject(firstObjAddr, FIRST_OBJ_SIZE, secondObjAddr);
207     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(firstObjAddr, firstObjAddr) == secondObjAddr)
208         << " seed = " << GetSeed();
209 
210     GetCrossingMap()->RemoveObject(secondObjAddr, SECOND_OBJ_SIZE);
211     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(firstObjAddr, firstObjAddr) == nullptr) << " seed = " << GetSeed();
212 }
213 
TEST_F(CrossingMapTest,TwoNonSequentialObjectsTest)214 TEST_F(CrossingMapTest, TwoNonSequentialObjectsTest)
215 {
216     static constexpr size_t FIRST_OBJ_SIZE = MIN_GAP_BETWEEN_OBJECTS;
217     static constexpr size_t GAP_BETWEEN_OBJECTS = 1_MB;
218     static constexpr size_t SECOND_OBJ_SIZE = 1_KB;
219     // Add some extra memory for possible shifts
220     void *firstObjAddr = GetRandomObjAddr(FIRST_OBJ_SIZE + SECOND_OBJ_SIZE + GAP_BETWEEN_OBJECTS);
221     void *secondObjAddr = IncreaseAddr(firstObjAddr, FIRST_OBJ_SIZE + GAP_BETWEEN_OBJECTS);
222 
223     GetCrossingMap()->AddObject(firstObjAddr, FIRST_OBJ_SIZE);
224     GetCrossingMap()->AddObject(secondObjAddr, SECOND_OBJ_SIZE);
225 
226     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(firstObjAddr, secondObjAddr) == firstObjAddr)
227         << " seed = " << GetSeed();
228 
229     GetCrossingMap()->RemoveObject(firstObjAddr, FIRST_OBJ_SIZE, secondObjAddr);
230     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(firstObjAddr, firstObjAddr) == nullptr) << " seed = " << GetSeed();
231     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(firstObjAddr, secondObjAddr) == secondObjAddr)
232         << " seed = " << GetSeed();
233 
234     GetCrossingMap()->RemoveObject(secondObjAddr, SECOND_OBJ_SIZE);
235     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(firstObjAddr, secondObjAddr) == nullptr) << " seed = " << GetSeed();
236 }
237 
TEST_F(CrossingMapTest,ThreeSequentialObjectsTest)238 TEST_F(CrossingMapTest, ThreeSequentialObjectsTest)
239 {
240     static constexpr size_t FIRST_OBJ_SIZE = 4_MB;
241     static constexpr size_t SECOND_OBJ_SIZE = MIN_GAP_BETWEEN_OBJECTS;
242     static constexpr size_t THIRD_OBJ_SIZE = 1_KB;
243     auto seedInfo = " seed = " + std::to_string(GetSeed());
244 
245     // Add some extra memory for possible shifts
246     void *firstObjAddr = GetRandomObjAddr(FIRST_OBJ_SIZE + SECOND_OBJ_SIZE + THIRD_OBJ_SIZE + 3U * SECOND_OBJ_SIZE);
247     void *secondObjAddr = IncreaseAddr(firstObjAddr, FIRST_OBJ_SIZE);
248     void *thirdObjAddr = IncreaseAddr(secondObjAddr, SECOND_OBJ_SIZE);
249 
250     // We must be sure that the first object will cross the borders for the second one
251     if (GetMapNumFromAddr(GetLastObjectByte(firstObjAddr, FIRST_OBJ_SIZE)) != GetMapNumFromAddr(secondObjAddr)) {
252         firstObjAddr = IncreaseAddr(firstObjAddr, SECOND_OBJ_SIZE);
253         secondObjAddr = IncreaseAddr(firstObjAddr, FIRST_OBJ_SIZE);
254         thirdObjAddr = IncreaseAddr(secondObjAddr, SECOND_OBJ_SIZE);
255         ASSERT_TRUE(GetMapNumFromAddr(GetLastObjectByte(firstObjAddr, FIRST_OBJ_SIZE)) ==
256                     GetMapNumFromAddr(secondObjAddr))
257             << seedInfo;
258     }
259 
260     // We must be sure that the second and the third object will be saved in the same locations
261     if (GetMapNumFromAddr(secondObjAddr) != GetMapNumFromAddr(thirdObjAddr)) {
262         firstObjAddr = IncreaseAddr(firstObjAddr, 2U * SECOND_OBJ_SIZE);
263         secondObjAddr = IncreaseAddr(firstObjAddr, FIRST_OBJ_SIZE);
264         thirdObjAddr = IncreaseAddr(secondObjAddr, SECOND_OBJ_SIZE);
265         ASSERT_TRUE(GetMapNumFromAddr(GetLastObjectByte(firstObjAddr, FIRST_OBJ_SIZE)) ==
266                     GetMapNumFromAddr(secondObjAddr))
267             << seedInfo;
268         ASSERT_TRUE(GetMapNumFromAddr(secondObjAddr) == GetMapNumFromAddr(thirdObjAddr)) << seedInfo;
269     }
270 
271     GetCrossingMap()->AddObject(firstObjAddr, FIRST_OBJ_SIZE);
272     GetCrossingMap()->AddObject(secondObjAddr, SECOND_OBJ_SIZE);
273     GetCrossingMap()->AddObject(thirdObjAddr, THIRD_OBJ_SIZE);
274 
275     if (PANDA_CROSSING_MAP_MANAGE_CROSSED_BORDER) {
276         ASSERT_TRUE(GetCrossingMap()->FindFirstObject(secondObjAddr, secondObjAddr) == firstObjAddr) << seedInfo;
277     } else {
278         ASSERT_TRUE(GetCrossingMap()->FindFirstObject(secondObjAddr, secondObjAddr) == secondObjAddr) << seedInfo;
279     }
280 
281     GetCrossingMap()->RemoveObject(secondObjAddr, SECOND_OBJ_SIZE, thirdObjAddr, firstObjAddr, FIRST_OBJ_SIZE);
282     if (PANDA_CROSSING_MAP_MANAGE_CROSSED_BORDER) {
283         ASSERT_TRUE(GetCrossingMap()->FindFirstObject(secondObjAddr, secondObjAddr) == firstObjAddr) << seedInfo;
284     } else {
285         ASSERT_TRUE(GetCrossingMap()->FindFirstObject(secondObjAddr, secondObjAddr) == thirdObjAddr) << seedInfo;
286     }
287     GetCrossingMap()->RemoveObject(thirdObjAddr, THIRD_OBJ_SIZE, nullptr, firstObjAddr, FIRST_OBJ_SIZE);
288     if (PANDA_CROSSING_MAP_MANAGE_CROSSED_BORDER) {
289         ASSERT_TRUE(GetCrossingMap()->FindFirstObject(secondObjAddr, secondObjAddr) == firstObjAddr) << seedInfo;
290     } else {
291         ASSERT_TRUE(GetCrossingMap()->FindFirstObject(secondObjAddr, secondObjAddr) == nullptr) << seedInfo;
292     }
293 
294     GetCrossingMap()->RemoveObject(firstObjAddr, FIRST_OBJ_SIZE);
295     ASSERT_TRUE(GetCrossingMap()->FindFirstObject(secondObjAddr, secondObjAddr) == nullptr) << seedInfo;
296 }
297 
TEST_F(CrossingMapTest,InitializeCrosingMapForMemoryTest)298 TEST_F(CrossingMapTest, InitializeCrosingMapForMemoryTest)
299 {
300     static constexpr size_t POOL_COUNT = 6;
301     static constexpr size_t GRANULARITY = 2;
302     GetCrossingMap()->RemoveCrossingMapForMemory(ToVoidPtr(GetPoolMinAddress()), GetPoolSize());
303     void *startAddr = GetRandomObjAddr((POOLS_SIZE * 2U + PANDA_POOL_ALIGNMENT_IN_BYTES) * POOL_COUNT +
304                                        PANDA_POOL_ALIGNMENT_IN_BYTES);
305     uintptr_t alignedStartAddr = AlignUp(ToUintPtr(startAddr), PANDA_POOL_ALIGNMENT_IN_BYTES);
306 
307     std::array<bool, POOL_COUNT> deletedPools {};
308     for (size_t i = 0; i < POOL_COUNT; i++) {
309         void *poolAddr = ToVoidPtr(alignedStartAddr + i * (POOLS_SIZE * 2U + PANDA_POOL_ALIGNMENT_IN_BYTES));
310         GetCrossingMap()->InitializeCrossingMapForMemory(poolAddr, POOLS_SIZE * 2U);
311         deletedPools[i] = false;
312     }
313 
314     for (size_t i = 0; i < POOL_COUNT; i += GRANULARITY) {
315         void *poolAddr = ToVoidPtr(alignedStartAddr + i * (POOLS_SIZE * 2U + PANDA_POOL_ALIGNMENT_IN_BYTES));
316         GetCrossingMap()->RemoveCrossingMapForMemory(poolAddr, POOLS_SIZE * 2U);
317         deletedPools[i] = true;
318     }
319 
320     for (size_t i = 0; i < POOL_COUNT; i++) {
321         if (deletedPools[i]) {
322             continue;
323         }
324         void *poolAddr = ToVoidPtr(alignedStartAddr + i * (POOLS_SIZE * 2U + PANDA_POOL_ALIGNMENT_IN_BYTES));
325         GetCrossingMap()->RemoveCrossingMapForMemory(poolAddr, POOLS_SIZE * 2U);
326     }
327 
328     GetCrossingMap()->InitializeCrossingMapForMemory(ToVoidPtr(GetPoolMinAddress()), GetPoolSize());
329 }
330 
331 }  // namespace ark::mem
332