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 <array>
17 #include <cstdint>
18 #include <limits>
19 #include <string>
20
21 #include "libpandabase/mem/mem.h"
22 #include "libpandabase/mem/mem_config.h"
23 #include "libpandabase/mem/pool_manager.h"
24 #include "libpandabase/utils/logger.h"
25 #include "runtime/mem/frame_allocator-inl.h"
26 #include "runtime/tests/allocator_test_base.h"
27
28 namespace panda::mem {
29
30 class FrameAllocatorTest : public AllocatorTest<FrameAllocator<>> {
31 public:
FrameAllocatorTest()32 FrameAllocatorTest()
33 {
34 panda::mem::MemConfig::Initialize(0, 256_MB, 0, 0);
35 // Logger::InitializeStdLogging(Logger::Level::DEBUG, Logger::Component::ALL);
36 }
37
~FrameAllocatorTest()38 ~FrameAllocatorTest()
39 {
40 // Logger::Destroy();
41 panda::mem::MemConfig::Finalize();
42 }
43
SmallAllocateTest(bool use_malloc) const44 void SmallAllocateTest(bool use_malloc) const
45 {
46 constexpr size_t ITERATIONS = 32;
47 constexpr size_t FRAME_SIZE = 256;
48 FrameAllocator<> alloc(use_malloc);
49 std::array<void *, ITERATIONS + 1> array {nullptr};
50 for (size_t i = 1; i <= ITERATIONS; i++) {
51 array[i] = alloc.Alloc(FRAME_SIZE);
52 ASSERT_NE(array[i], nullptr);
53 *(static_cast<uint64_t *>(array[i])) = i;
54 }
55 for (size_t i = ITERATIONS; i != 0; i--) {
56 ASSERT_EQ(*(static_cast<uint64_t *>(array[i])), i);
57 alloc.Free(array[i]);
58 }
59 }
60
CornerAllocationSizeTest(bool use_malloc) const61 void CornerAllocationSizeTest(bool use_malloc) const
62 {
63 constexpr size_t FIRST_FRAME_SIZE = FrameAllocator<>::FIRST_ARENA_SIZE;
64 constexpr size_t SECOND_FRAME_SIZE = FrameAllocator<>::ARENA_SIZE_GREW_LEVEL;
65 constexpr size_t THIRD_FRAME_SIZE = FIRST_FRAME_SIZE + SECOND_FRAME_SIZE;
66 FrameAllocator<> alloc1(use_malloc);
67 FrameAllocator<> alloc2(use_malloc);
68 FrameAllocator<> alloc3(use_malloc);
69 {
70 void *mem = alloc1.Alloc(FIRST_FRAME_SIZE);
71 ASSERT_NE(mem, nullptr);
72 alloc1.Free(mem);
73 DeallocateLastArena(&alloc1);
74 mem = alloc1.Alloc(SECOND_FRAME_SIZE);
75 ASSERT_NE(mem, nullptr);
76 }
77 {
78 void *mem = alloc2.Alloc(SECOND_FRAME_SIZE);
79 ASSERT_NE(mem, nullptr);
80 alloc2.Free(mem);
81 DeallocateLastArena(&alloc2);
82 mem = alloc2.Alloc(THIRD_FRAME_SIZE);
83 ASSERT_NE(mem, nullptr);
84 }
85 {
86 void *mem = alloc3.Alloc(THIRD_FRAME_SIZE);
87 ASSERT_NE(mem, nullptr);
88 alloc3.Free(mem);
89 DeallocateLastArena(&alloc3);
90 mem = alloc3.Alloc(THIRD_FRAME_SIZE);
91 ASSERT_NE(mem, nullptr);
92 }
93 ASSERT_NE(alloc1.Alloc(FIRST_FRAME_SIZE), nullptr);
94 ASSERT_NE(alloc2.Alloc(SECOND_FRAME_SIZE), nullptr);
95 ASSERT_NE(alloc3.Alloc(THIRD_FRAME_SIZE), nullptr);
96 }
97
98 template <Alignment alignment>
AlignmentTest(bool use_malloc) const99 void AlignmentTest(bool use_malloc) const
100 {
101 FrameAllocator<alignment> alloc(use_malloc);
102 constexpr size_t MAX_SIZE = 256;
103 std::array<void *, MAX_SIZE + 1> array {nullptr};
104 for (size_t i = 1; i <= MAX_SIZE; i++) {
105 array[i] = alloc.Alloc(i * GetAlignmentInBytes(alignment));
106 if (array[i] == nullptr) {
107 break;
108 }
109 ASSERT_NE(array[i], nullptr);
110 ASSERT_EQ(ToUintPtr(array[i]), AlignUp(ToUintPtr(array[i]), GetAlignmentInBytes(alignment)));
111 *(static_cast<uint64_t *>(array[i])) = i;
112 }
113 for (size_t i = MAX_SIZE; i != 0; i--) {
114 if (array[i] == nullptr) {
115 break;
116 }
117 ASSERT_EQ(*(static_cast<uint64_t *>(array[i])), i);
118 alloc.Free(array[i]);
119 }
120 }
121
CycledAllocateFreeForHugeFramesTest(bool use_malloc)122 void CycledAllocateFreeForHugeFramesTest(bool use_malloc)
123 {
124 constexpr size_t ITERATIONS = 1024;
125 constexpr size_t FRAME_SIZE = 512;
126 constexpr int CYCLE_COUNT = 16;
127
128 FrameAllocator<> alloc(use_malloc);
129 std::vector<std::pair<void *, size_t>> vec;
130
131 for (int j = 0; j < CYCLE_COUNT; j++) {
132 for (size_t i = 1; i <= ITERATIONS; i++) {
133 void *mem = alloc.Alloc(FRAME_SIZE);
134 ASSERT_TRUE(mem != nullptr)
135 << "Didn't allocate " << FRAME_SIZE << " bytes in " << j << " cycle, seed: " << seed_;
136 vec.emplace_back(mem, SetBytesFromByteArray(mem, FRAME_SIZE));
137 }
138 for (size_t i = 1; i <= ITERATIONS / 2; i++) {
139 std::pair<void *, size_t> last_pair = vec.back();
140 ASSERT_TRUE(CompareBytesWithByteArray(last_pair.first, FRAME_SIZE, last_pair.second))
141 << "iteration: " << i << ", size: " << FRAME_SIZE << ", address: " << std::hex << last_pair.first
142 << ", index in byte array: " << last_pair.second << ", seed: " << seed_;
143 alloc.Free(last_pair.first);
144 vec.pop_back();
145 }
146 }
147 while (!vec.empty()) {
148 std::pair<void *, size_t> last_pair = vec.back();
149 ASSERT_TRUE(CompareBytesWithByteArray(last_pair.first, FRAME_SIZE, last_pair.second))
150 << "vector size: " << vec.size() << ", size: " << FRAME_SIZE << ", address: " << std::hex
151 << last_pair.first << ", index in byte array: " << last_pair.second << ", seed: " << seed_;
152 alloc.Free(last_pair.first);
153 vec.pop_back();
154 }
155 }
156
ValidateArenaGrownPolicy(bool use_malloc) const157 void ValidateArenaGrownPolicy(bool use_malloc) const
158 {
159 constexpr size_t ITERATIONS = 16;
160 FrameAllocator<> alloc(use_malloc);
161 size_t last_alloc_arena_size = 0;
162 for (size_t i = 0; i < ITERATIONS; i++) {
163 size_t new_arena_size = AllocNewArena(&alloc);
164 ASSERT_EQ(new_arena_size > last_alloc_arena_size, true);
165 last_alloc_arena_size = new_arena_size;
166 }
167
168 for (size_t i = 0; i < ITERATIONS; i++) {
169 DeallocateLastArena(&alloc);
170 }
171
172 size_t new_arena_size = AllocNewArena(&alloc);
173 ASSERT_EQ(new_arena_size == last_alloc_arena_size, true);
174 }
175
CheckAddrInsideAllocator(bool use_malloc) const176 void CheckAddrInsideAllocator(bool use_malloc) const
177 {
178 constexpr size_t ITERATIONS = 16;
179 static constexpr size_t FRAME_SIZE = 256;
180 void *invalid_addr = std::malloc(10);
181
182 FrameAllocator<> alloc(use_malloc);
183 ASSERT_FALSE(alloc.Contains(invalid_addr));
184 for (size_t i = 0; i < ITERATIONS; i++) {
185 AllocNewArena(&alloc);
186 }
187 void *addr1_inside = alloc.Alloc(FRAME_SIZE);
188 ASSERT_TRUE(alloc.Contains(addr1_inside));
189 ASSERT_FALSE(alloc.Contains(invalid_addr));
190
191 alloc.Free(addr1_inside);
192 ASSERT_FALSE(alloc.Contains(addr1_inside));
193 ASSERT_FALSE(alloc.Contains(invalid_addr));
194
195 addr1_inside = alloc.Alloc(FRAME_SIZE);
196 for (size_t i = 0; i < ITERATIONS; i++) {
197 AllocNewArena(&alloc);
198 }
199 auto *addr2_inside = alloc.Alloc(FRAME_SIZE * 2);
200 ASSERT_TRUE(alloc.Contains(addr1_inside));
201 ASSERT_TRUE(alloc.Contains(addr2_inside));
202 ASSERT_FALSE(alloc.Contains(invalid_addr));
203 free(invalid_addr);
204 }
205
206 protected:
AddMemoryPoolToAllocator(FrameAllocator<> & allocator)207 void AddMemoryPoolToAllocator([[maybe_unused]] FrameAllocator<> &allocator) override {}
AddMemoryPoolToAllocatorProtected(FrameAllocator<> & allocator)208 void AddMemoryPoolToAllocatorProtected([[maybe_unused]] FrameAllocator<> &allocator) override {}
AllocatedByThisAllocator(FrameAllocator<> & allocator,void * mem)209 bool AllocatedByThisAllocator([[maybe_unused]] FrameAllocator<> &allocator, [[maybe_unused]] void *mem) override
210 {
211 return false;
212 }
213
PrintMemory(void * dst,size_t size)214 void PrintMemory(void *dst, size_t size)
215 {
216 std::cout << "Print at memory: ";
217 auto *mem = static_cast<uint8_t *>(dst);
218 for (size_t i = 0; i < size; i++) {
219 std::cout << *mem++;
220 }
221 std::cout << std::endl;
222 }
223
PrintAtIndex(size_t idx,size_t size)224 void PrintAtIndex(size_t idx, size_t size)
225 {
226 std::cout << "Print at index: ";
227 ASSERT(idx + size < BYTE_ARRAY_SIZE);
228 uint8_t *mem = static_cast<uint8_t *>(&byte_array_[idx]);
229 for (size_t i = 0; i < size; i++) {
230 std::cout << *mem++;
231 }
232 std::cout << std::endl;
233 }
234
SetUp()235 void SetUp() override
236 {
237 PoolManager::Initialize();
238 }
239
TearDown()240 void TearDown() override
241 {
242 PoolManager::Finalize();
243 }
244
AllocNewArena(FrameAllocator<> * alloc) const245 size_t AllocNewArena(FrameAllocator<> *alloc) const
246 {
247 bool is_allocated = alloc->TryAllocateNewArena();
248 ASSERT(is_allocated);
249 return is_allocated ? alloc->biggest_arena_size_ : 0;
250 }
251
DeallocateLastArena(FrameAllocator<> * alloc) const252 void DeallocateLastArena(FrameAllocator<> *alloc) const
253 {
254 alloc->FreeLastArena();
255 }
256 };
257
TEST_F(FrameAllocatorTest,SmallAllocateTest)258 TEST_F(FrameAllocatorTest, SmallAllocateTest)
259 {
260 SmallAllocateTest(false);
261 SmallAllocateTest(true);
262 }
263
TEST_F(FrameAllocatorTest,CornerAllocationSizeTest)264 TEST_F(FrameAllocatorTest, CornerAllocationSizeTest)
265 {
266 CornerAllocationSizeTest(false);
267 CornerAllocationSizeTest(true);
268 }
269
TEST_F(FrameAllocatorTest,DefaultAlignmentTest)270 TEST_F(FrameAllocatorTest, DefaultAlignmentTest)
271 {
272 AlignmentTest<DEFAULT_FRAME_ALIGNMENT>(false);
273 AlignmentTest<DEFAULT_FRAME_ALIGNMENT>(true);
274 }
275
TEST_F(FrameAllocatorTest,NonDefaultAlignmentTest)276 TEST_F(FrameAllocatorTest, NonDefaultAlignmentTest)
277 {
278 AlignmentTest<Alignment::LOG_ALIGN_4>(false);
279 AlignmentTest<Alignment::LOG_ALIGN_4>(true);
280 AlignmentTest<Alignment::LOG_ALIGN_5>(false);
281 AlignmentTest<Alignment::LOG_ALIGN_5>(true);
282 }
283
TEST_F(FrameAllocatorTest,CycledAllocateFreeForHugeFramesTest)284 TEST_F(FrameAllocatorTest, CycledAllocateFreeForHugeFramesTest)
285 {
286 CycledAllocateFreeForHugeFramesTest(false);
287 CycledAllocateFreeForHugeFramesTest(true);
288 }
289
TEST_F(FrameAllocatorTest,ValidateArenaGrownPolicy)290 TEST_F(FrameAllocatorTest, ValidateArenaGrownPolicy)
291 {
292 ValidateArenaGrownPolicy(false);
293 ValidateArenaGrownPolicy(true);
294 }
295
TEST_F(FrameAllocatorTest,CheckAddrInsideAllocator)296 TEST_F(FrameAllocatorTest, CheckAddrInsideAllocator)
297 {
298 CheckAddrInsideAllocator(false);
299 CheckAddrInsideAllocator(true);
300 }
301
302 } // namespace panda::mem
303