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 #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 ark {
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 // NOLINTNEXTLINE(readability-magic-numbers)
34 seed_ = 0xDEADBEEF;
35 #endif
36 srand(seed_);
37 }
38
~PoolMapTest()39 ~PoolMapTest() override
40 {
41 ResetPoolMap();
42 }
43
44 NO_COPY_SEMANTIC(PoolMapTest);
45 NO_MOVE_SEMANTIC(PoolMapTest);
46
47 protected:
48 static constexpr size_t MINIMAL_POOL_SIZE = PANDA_POOL_ALIGNMENT_IN_BYTES;
49
AddToPoolMap(Pool pool,SpaceType spaceType,AllocatorType allocatorType,void * allocatorAddr=nullptr)50 void AddToPoolMap(Pool pool, SpaceType spaceType, AllocatorType allocatorType, void *allocatorAddr = nullptr)
51 {
52 if (allocatorAddr == nullptr) {
53 allocatorAddr = pool.GetMem();
54 }
55 pools_.push_back(pool);
56 poolMap_.AddPoolToMap(pool.GetMem(), pool.GetSize(), spaceType, allocatorType, allocatorAddr);
57 }
58
RemovePoolFromMap(Pool pool)59 void RemovePoolFromMap(Pool pool)
60 {
61 auto items = std::remove(pools_.begin(), pools_.end(), pool);
62 ASSERT(items != pools_.end());
63 pools_.erase(items, pools_.end());
64 poolMap_.RemovePoolFromMap(pool.GetMem(), pool.GetSize());
65 }
66
ResetPoolMap()67 void ResetPoolMap()
68 {
69 for (auto i : pools_) {
70 poolMap_.RemovePoolFromMap(i.GetMem(), i.GetSize());
71 }
72 pools_.clear();
73 }
74
IsEmptyPoolMap() const75 bool IsEmptyPoolMap() const
76 {
77 return poolMap_.IsEmpty();
78 }
79
GetRandSpaceType() const80 SpaceType GetRandSpaceType() const
81 {
82 // NOLINTNEXTLINE(cert-msc50-cpp)
83 int randIndex = rand() % ALL_SPACE_TYPES.size();
84 return ALL_SPACE_TYPES[randIndex];
85 }
86
GetRandAllocatorType() const87 AllocatorType GetRandAllocatorType() const
88 {
89 // NOLINTNEXTLINE(cert-msc50-cpp)
90 int randIndex = rand() % ALL_ALLOCATOR_TYPES.size();
91 return ALL_ALLOCATOR_TYPES[randIndex];
92 }
93
RandHeapAddr() const94 size_t RandHeapAddr() const
95 {
96 // NOLINTNEXTLINE(cert-msc50-cpp)
97 return AlignUp(rand() % PANDA_MAX_HEAP_SIZE, DEFAULT_ALIGNMENT_IN_BYTES);
98 }
99
CheckRandomPoolAddress(Pool pool,SpaceType spaceType,AllocatorType allocatorType,uintptr_t allocatorAddr)100 void CheckRandomPoolAddress(Pool pool, SpaceType spaceType, AllocatorType allocatorType, uintptr_t allocatorAddr)
101 {
102 void *poolAddr = RandAddrFromPool(pool);
103 ASSERT_EQ(GetSpaceTypeForAddr(poolAddr), spaceType);
104 ASSERT_EQ(GetAllocatorInfoForAddr(poolAddr).GetType(), allocatorType);
105 ASSERT_EQ(ToUintPtr(GetAllocatorInfoForAddr(poolAddr).GetAllocatorHeaderAddr()), allocatorAddr);
106 }
107
108 private:
RandAddrFromPool(Pool pool) const109 void *RandAddrFromPool(Pool pool) const
110 {
111 // NOLINTNEXTLINE(cert-msc50-cpp)
112 return ToVoidPtr(ToUintPtr(pool.GetMem()) + rand() % pool.GetSize());
113 }
114
GetAllocatorInfoForAddr(const void * addr) const115 AllocatorInfo GetAllocatorInfoForAddr(const void *addr) const
116 {
117 return poolMap_.GetAllocatorInfo(addr);
118 }
119
GetSpaceTypeForAddr(const void * addr) const120 SpaceType GetSpaceTypeForAddr(const void *addr) const
121 {
122 return poolMap_.GetSpaceType(addr);
123 }
124
125 static constexpr std::array<SpaceType, 6U> ALL_SPACE_TYPES = {SpaceType::SPACE_TYPE_OBJECT,
126 SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT,
127 SpaceType::SPACE_TYPE_NON_MOVABLE_OBJECT,
128 SpaceType::SPACE_TYPE_INTERNAL,
129 SpaceType::SPACE_TYPE_CODE,
130 SpaceType::SPACE_TYPE_COMPILER};
131
132 static constexpr std::array<AllocatorType, 8U> ALL_ALLOCATOR_TYPES = {
133 AllocatorType::RUNSLOTS_ALLOCATOR, AllocatorType::FREELIST_ALLOCATOR, AllocatorType::HUMONGOUS_ALLOCATOR,
134 AllocatorType::ARENA_ALLOCATOR, AllocatorType::BUMP_ALLOCATOR, AllocatorType::TLAB_ALLOCATOR,
135 AllocatorType::REGION_ALLOCATOR, AllocatorType::FRAME_ALLOCATOR};
136
137 unsigned int seed_;
138 std::vector<Pool> pools_;
139 PoolMap poolMap_;
140 };
141
TEST_F(PoolMapTest,TwoConsistentPoolsTest)142 TEST_F(PoolMapTest, TwoConsistentPoolsTest)
143 {
144 static constexpr size_t FIRST_POOL_SIZE = 4U * MINIMAL_POOL_SIZE;
145 static constexpr size_t SECOND_POOL_SIZE = 10U * MINIMAL_POOL_SIZE;
146 static constexpr uintptr_t FIRST_POOL_ADDR = 0;
147 static constexpr uintptr_t SECOND_POOL_ADDR = FIRST_POOL_ADDR + FIRST_POOL_SIZE;
148 static constexpr SpaceType FIRST_SPACE_TYPE = SpaceType::SPACE_TYPE_INTERNAL;
149 static constexpr SpaceType SECOND_SPACE_TYPE = SpaceType::SPACE_TYPE_OBJECT;
150 static constexpr AllocatorType FIRST_ALLOCATOR_TYPE = AllocatorType::RUNSLOTS_ALLOCATOR;
151 static constexpr AllocatorType SECOND_ALLOCATOR_TYPE = AllocatorType::FREELIST_ALLOCATOR;
152
153 uintptr_t firstPoolAllocatorHeaderAddr = RandHeapAddr();
154
155 Pool firstPool(FIRST_POOL_SIZE, ToVoidPtr(FIRST_POOL_ADDR));
156 Pool secondPool(SECOND_POOL_SIZE, ToVoidPtr(SECOND_POOL_ADDR));
157
158 AddToPoolMap(firstPool, FIRST_SPACE_TYPE, FIRST_ALLOCATOR_TYPE, ToVoidPtr(firstPoolAllocatorHeaderAddr));
159 AddToPoolMap(secondPool, SECOND_SPACE_TYPE, SECOND_ALLOCATOR_TYPE);
160
161 CheckRandomPoolAddress(firstPool, FIRST_SPACE_TYPE, FIRST_ALLOCATOR_TYPE, firstPoolAllocatorHeaderAddr);
162 // We haven't initialized second allocator header address.
163 // Therefore it must return a pointer to the first pool byte.
164 CheckRandomPoolAddress(secondPool, SECOND_SPACE_TYPE, SECOND_ALLOCATOR_TYPE, SECOND_POOL_ADDR);
165
166 // Check that we remove elements from pool map correctly
167 RemovePoolFromMap(firstPool);
168 RemovePoolFromMap(secondPool);
169
170 ASSERT_TRUE(IsEmptyPoolMap());
171 ResetPoolMap();
172 }
173
TEST_F(PoolMapTest,AddRemoveDifferentPoolsTest)174 TEST_F(PoolMapTest, AddRemoveDifferentPoolsTest)
175 {
176 static constexpr size_t MAX_POOL_SIZE = 256U * MINIMAL_POOL_SIZE;
177 static constexpr size_t ITERATIONS = 200;
178 static constexpr uintptr_t POOL_START_ADDR = PANDA_POOL_ALIGNMENT_IN_BYTES;
179 for (size_t i = 0; i < ITERATIONS; i++) {
180 // NOLINTNEXTLINE(cert-msc50-cpp)
181 size_t poolSize = AlignUp(rand() % MAX_POOL_SIZE, PANDA_POOL_ALIGNMENT_IN_BYTES);
182 SpaceType space = GetRandSpaceType();
183 AllocatorType allocator = GetRandAllocatorType();
184 Pool pool(poolSize, ToVoidPtr(POOL_START_ADDR));
185
186 AddToPoolMap(pool, space, allocator);
187 CheckRandomPoolAddress(pool, space, allocator, POOL_START_ADDR);
188 RemovePoolFromMap(pool);
189 }
190
191 ASSERT_TRUE(IsEmptyPoolMap());
192 ResetPoolMap();
193 }
194
195 } // namespace ark
196