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