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