1 /*
2 * Copyright (c) 2021 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 #include "mem/pool_map.h"
18 #include "mem/mem_pool.h"
19 #include "mem/mem.h"
20
21 #include <ctime>
22 #include <algorithm>
23
24 namespace panda {
25
26 class PoolMapTest : public testing::Test {
27 public:
PoolMapTest()28 PoolMapTest()
29 {
30 #ifdef PANDA_NIGHTLY_TEST_ON
31 seed_ = std::time(NULL);
32 #else
33 seed_ = 0xDEADBEEF;
34 #endif
35 srand(seed_);
36 }
37
~PoolMapTest()38 ~PoolMapTest()
39 {
40 ResetPoolMap();
41 }
42
43 protected:
44 static constexpr size_t MINIMAL_POOL_SIZE = PANDA_POOL_ALIGNMENT_IN_BYTES;
45
AddToPoolMap(Pool pool,SpaceType space_type,AllocatorType allocator_type,const void * allocator_addr=nullptr)46 void AddToPoolMap(Pool pool, SpaceType space_type, AllocatorType allocator_type,
47 const void *allocator_addr = nullptr)
48 {
49 if (allocator_addr == nullptr) {
50 allocator_addr = pool.GetMem();
51 }
52 pools_.push_back(pool);
53 pool_map_.AddPoolToMap(pool.GetMem(), pool.GetSize(), space_type, allocator_type, allocator_addr);
54 }
55
RemovePoolFromMap(Pool pool)56 void RemovePoolFromMap(Pool pool)
57 {
58 auto items = std::remove(pools_.begin(), pools_.end(), pool);
59 ASSERT(items != pools_.end());
60 pools_.erase(items, pools_.end());
61 pool_map_.RemovePoolFromMap(pool.GetMem(), pool.GetSize());
62 }
63
ResetPoolMap()64 void ResetPoolMap()
65 {
66 for (auto i : pools_) {
67 pool_map_.RemovePoolFromMap(i.GetMem(), i.GetSize());
68 }
69 pools_.clear();
70 }
71
IsEmptyPoolMap() const72 bool IsEmptyPoolMap() const
73 {
74 return pool_map_.IsEmpty();
75 }
76
GetRandSpaceType() const77 SpaceType GetRandSpaceType() const
78 {
79 int rand_index = rand() % ALL_SPACE_TYPES.size();
80 return ALL_SPACE_TYPES[rand_index];
81 }
82
GetRandAllocatorType() const83 AllocatorType GetRandAllocatorType() const
84 {
85 int rand_index = rand() % ALL_ALLOCATOR_TYPES.size();
86 return ALL_ALLOCATOR_TYPES[rand_index];
87 }
88
RandHeapAddr() const89 size_t RandHeapAddr() const
90 {
91 return AlignUp(rand() % PANDA_MAX_HEAP_SIZE, DEFAULT_ALIGNMENT_IN_BYTES);
92 }
93
CheckRandomPoolAddress(Pool pool,SpaceType space_type,AllocatorType allocator_type,uintptr_t allocator_addr) const94 void CheckRandomPoolAddress(Pool pool, SpaceType space_type, AllocatorType allocator_type,
95 uintptr_t allocator_addr) const
96 {
97 void *pool_addr = RandAddrFromPool(pool);
98 ASSERT_EQ(GetSpaceTypeForAddr(pool_addr), space_type);
99 ASSERT_EQ(GetAllocatorInfoForAddr(pool_addr).GetType(), allocator_type);
100 ASSERT_EQ(ToUintPtr(GetAllocatorInfoForAddr(pool_addr).GetAllocatorHeaderAddr()), allocator_addr);
101 }
102
103 private:
RandAddrFromPool(Pool pool) const104 void *RandAddrFromPool(Pool pool) const
105 {
106 return ToVoidPtr(ToUintPtr(pool.GetMem()) + rand() % pool.GetSize());
107 }
108
GetAllocatorInfoForAddr(void * addr) const109 AllocatorInfo GetAllocatorInfoForAddr(void *addr) const
110 {
111 return pool_map_.GetAllocatorInfo(addr);
112 }
113
GetSpaceTypeForAddr(void * addr) const114 SpaceType GetSpaceTypeForAddr(void *addr) const
115 {
116 return pool_map_.GetSpaceType(addr);
117 }
118
119 static constexpr std::array<SpaceType, 6> ALL_SPACE_TYPES = {SpaceType::SPACE_TYPE_OBJECT,
120 SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT,
121 SpaceType::SPACE_TYPE_NON_MOVABLE_OBJECT,
122 SpaceType::SPACE_TYPE_INTERNAL,
123 SpaceType::SPACE_TYPE_CODE,
124 SpaceType::SPACE_TYPE_COMPILER};
125
126 static constexpr std::array<AllocatorType, 8> ALL_ALLOCATOR_TYPES = {
127 AllocatorType::RUNSLOTS_ALLOCATOR, AllocatorType::FREELIST_ALLOCATOR, AllocatorType::HUMONGOUS_ALLOCATOR,
128 AllocatorType::ARENA_ALLOCATOR, AllocatorType::BUMP_ALLOCATOR, AllocatorType::TLAB_ALLOCATOR,
129 AllocatorType::REGION_ALLOCATOR, AllocatorType::FRAME_ALLOCATOR};
130
131 unsigned int seed_;
132 std::vector<Pool> pools_;
133 PoolMap pool_map_;
134 };
135
TEST_F(PoolMapTest,TwoConsistentPoolsTest)136 TEST_F(PoolMapTest, TwoConsistentPoolsTest)
137 {
138 static constexpr size_t FIRST_POOL_SIZE = 4 * MINIMAL_POOL_SIZE;
139 static constexpr size_t SECOND_POOL_SIZE = 10 * MINIMAL_POOL_SIZE;
140 static constexpr uintptr_t FIRST_POOL_ADDR = 0;
141 static constexpr uintptr_t SECOND_POOL_ADDR = FIRST_POOL_ADDR + FIRST_POOL_SIZE;
142 static constexpr SpaceType FIRST_SPACE_TYPE = SpaceType::SPACE_TYPE_INTERNAL;
143 static constexpr SpaceType SECOND_SPACE_TYPE = SpaceType::SPACE_TYPE_OBJECT;
144 static constexpr AllocatorType FIRST_ALLOCATOR_TYPE = AllocatorType::RUNSLOTS_ALLOCATOR;
145 static constexpr AllocatorType SECOND_ALLOCATOR_TYPE = AllocatorType::FREELIST_ALLOCATOR;
146
147 uintptr_t first_pool_allocator_header_addr = RandHeapAddr();
148
149 Pool first_pool(FIRST_POOL_SIZE, ToVoidPtr(FIRST_POOL_ADDR));
150 Pool second_pool(SECOND_POOL_SIZE, ToVoidPtr(SECOND_POOL_ADDR));
151
152 AddToPoolMap(first_pool, FIRST_SPACE_TYPE, FIRST_ALLOCATOR_TYPE, ToVoidPtr(first_pool_allocator_header_addr));
153 AddToPoolMap(second_pool, SECOND_SPACE_TYPE, SECOND_ALLOCATOR_TYPE);
154
155 CheckRandomPoolAddress(first_pool, FIRST_SPACE_TYPE, FIRST_ALLOCATOR_TYPE, first_pool_allocator_header_addr);
156 // We haven't initialized second allocator header address.
157 // Therefore it must return a pointer to the first pool byte.
158 CheckRandomPoolAddress(second_pool, SECOND_SPACE_TYPE, SECOND_ALLOCATOR_TYPE, SECOND_POOL_ADDR);
159
160 // Check that we remove elements from pool map correctly
161 RemovePoolFromMap(first_pool);
162 RemovePoolFromMap(second_pool);
163
164 ASSERT_TRUE(IsEmptyPoolMap());
165 ResetPoolMap();
166 }
167
TEST_F(PoolMapTest,AddRemoveDifferentPoolsTest)168 TEST_F(PoolMapTest, AddRemoveDifferentPoolsTest)
169 {
170 static constexpr size_t MAX_POOL_SIZE = 256 * MINIMAL_POOL_SIZE;
171 static constexpr size_t ITERATIONS = 200;
172 static constexpr uintptr_t POOL_START_ADDR = PANDA_POOL_ALIGNMENT_IN_BYTES;
173 for (size_t i = 0; i < ITERATIONS; i++) {
174 size_t pool_size = AlignUp(rand() % MAX_POOL_SIZE, PANDA_POOL_ALIGNMENT_IN_BYTES);
175 SpaceType space = GetRandSpaceType();
176 AllocatorType allocator = GetRandAllocatorType();
177 Pool pool(pool_size, ToVoidPtr(POOL_START_ADDR));
178
179 AddToPoolMap(pool, space, allocator);
180 CheckRandomPoolAddress(pool, space, allocator, POOL_START_ADDR);
181 RemovePoolFromMap(pool);
182 }
183
184 ASSERT_TRUE(IsEmptyPoolMap());
185 ResetPoolMap();
186 }
187
188 } // namespace panda
189