• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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