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 "libpandabase/mem/stack_like_allocator-inl.h"
26 #include "runtime/tests/allocator_test_base.h"
27
28 namespace ark::mem {
29 class StackLikeAllocatorTest : public AllocatorTest<StackLikeAllocator<>> {
30 public:
31 NO_COPY_SEMANTIC(StackLikeAllocatorTest);
32 NO_MOVE_SEMANTIC(StackLikeAllocatorTest);
StackLikeAllocatorTest()33 StackLikeAllocatorTest()
34 {
35 static constexpr size_t INTERNAL_MEMORY_SIZE = 256_MB;
36 ark::mem::MemConfig::Initialize(0, INTERNAL_MEMORY_SIZE, 0, 0, INTERNAL_MEMORY_SIZE, 0);
37 // Logger::InitializeStdLogging(Logger::Level::DEBUG, Logger::Component::ALL);
38 }
39
~StackLikeAllocatorTest()40 ~StackLikeAllocatorTest() override
41 {
42 // Logger::Destroy();
43 ark::mem::MemConfig::Finalize();
44 }
45
46 protected:
AddMemoryPoolToAllocator(StackLikeAllocator<> & allocator)47 void AddMemoryPoolToAllocator([[maybe_unused]] StackLikeAllocator<> &allocator) override {}
AddMemoryPoolToAllocatorProtected(StackLikeAllocator<> & allocator)48 void AddMemoryPoolToAllocatorProtected([[maybe_unused]] StackLikeAllocator<> &allocator) override {}
AllocatedByThisAllocator(StackLikeAllocator<> & allocator,void * mem)49 bool AllocatedByThisAllocator([[maybe_unused]] StackLikeAllocator<> &allocator, [[maybe_unused]] void *mem) override
50 {
51 return false;
52 }
53
PrintMemory(void * dst,size_t size)54 void PrintMemory(void *dst, size_t size)
55 {
56 std::cout << "Print at memory: ";
57 auto mem = static_cast<uint8_t *>(dst);
58 for (size_t i = 0; i < size; i++) {
59 std::cout << *mem++; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
60 }
61 std::cout << std::endl;
62 }
63
PrintAtIndex(size_t idx,size_t size)64 void PrintAtIndex(size_t idx, size_t size)
65 {
66 std::cout << "Print at index: ";
67 ASSERT(idx + size < BYTE_ARRAY_SIZE);
68 auto mem = static_cast<uint8_t *>(&byteArray_[idx]);
69 for (size_t i = 0; i < size; i++) {
70 std::cout << *mem++; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
71 }
72 std::cout << std::endl;
73 }
74
SetUp()75 void SetUp() override
76 {
77 PoolManager::Initialize();
78 }
79
TearDown()80 void TearDown() override
81 {
82 PoolManager::Finalize();
83 }
84 };
85
TEST_F(StackLikeAllocatorTest,SmallAllocateTest)86 TEST_F(StackLikeAllocatorTest, SmallAllocateTest)
87 {
88 constexpr size_t ITERATIONS = 32;
89 constexpr size_t FRAME_SIZE = 256;
90 StackLikeAllocator<> alloc;
91 std::array<void *, ITERATIONS + 1> array {nullptr};
92 for (size_t i = 1; i <= ITERATIONS; i++) {
93 array[i] = alloc.Alloc(FRAME_SIZE);
94 ASSERT_NE(array[i], nullptr);
95 *(static_cast<uint64_t *>(array[i])) = i;
96 }
97 for (size_t i = ITERATIONS; i != 0; i--) {
98 ASSERT_EQ(*(static_cast<uint64_t *>(array[i])), i);
99 alloc.Free(array[i]);
100 }
101 }
102
103 template <Alignment ALIGNMENT>
AlignmentTest(StackLikeAllocator<ALIGNMENT> & alloc)104 void AlignmentTest(StackLikeAllocator<ALIGNMENT> &alloc)
105 {
106 constexpr size_t MAX_SIZE = 256;
107 std::array<void *, MAX_SIZE + 1> array {nullptr};
108 for (size_t i = 1; i <= MAX_SIZE; i++) {
109 array[i] = alloc.Alloc(i * GetAlignmentInBytes(ALIGNMENT));
110 if (array[i] == nullptr) {
111 break;
112 }
113 ASSERT_NE(array[i], nullptr);
114 ASSERT_EQ(ToUintPtr(array[i]), AlignUp(ToUintPtr(array[i]), GetAlignmentInBytes(ALIGNMENT)));
115 *(static_cast<uint64_t *>(array[i])) = i;
116 }
117 for (size_t i = MAX_SIZE; i != 0; i--) {
118 if (array[i] == nullptr) {
119 break;
120 }
121 ASSERT_EQ(*(static_cast<uint64_t *>(array[i])), i);
122 alloc.Free(array[i]);
123 }
124 }
125
TEST_F(StackLikeAllocatorTest,DefaultAlignmentTest)126 TEST_F(StackLikeAllocatorTest, DefaultAlignmentTest)
127 {
128 StackLikeAllocator<> alloc;
129 AlignmentTest(alloc);
130 }
131
TEST_F(StackLikeAllocatorTest,NonDefaultAlignmentTest)132 TEST_F(StackLikeAllocatorTest, NonDefaultAlignmentTest)
133 {
134 StackLikeAllocator<Alignment::LOG_ALIGN_4> alloc4;
135 AlignmentTest(alloc4);
136 StackLikeAllocator<Alignment::LOG_ALIGN_5> alloc5;
137 AlignmentTest(alloc5);
138 }
139
TEST_F(StackLikeAllocatorTest,CycledAllocateFreeForHugeFramesTest)140 TEST_F(StackLikeAllocatorTest, CycledAllocateFreeForHugeFramesTest)
141 {
142 constexpr size_t ITERATIONS = 1024;
143 constexpr size_t FRAME_SIZE = 512;
144 constexpr int CYCLE_COUNT = 16;
145
146 StackLikeAllocator<> alloc;
147 std::vector<std::pair<void *, size_t>> vec;
148
149 for (int j = 0; j < CYCLE_COUNT; j++) {
150 for (size_t i = 1; i <= ITERATIONS; i++) {
151 void *mem = alloc.Alloc(FRAME_SIZE);
152 ASSERT_TRUE(mem != nullptr) << "Didn't allocate " << FRAME_SIZE << " bytes in " << j
153 << " cycle, seed: " << seed_;
154 vec.emplace_back(mem, SetBytesFromByteArray(mem, FRAME_SIZE));
155 }
156 for (size_t i = 1; i <= ITERATIONS / 2U; i++) {
157 std::pair<void *, size_t> lastPair = vec.back();
158 ASSERT_TRUE(CompareBytesWithByteArray(lastPair.first, FRAME_SIZE, lastPair.second))
159 << "iteration: " << i << ", size: " << FRAME_SIZE << ", address: " << std::hex << lastPair.first
160 << ", index in byte array: " << lastPair.second << ", seed: " << seed_;
161 alloc.Free(lastPair.first);
162 vec.pop_back();
163 }
164 }
165 while (!vec.empty()) {
166 std::pair<void *, size_t> lastPair = vec.back();
167 ASSERT_TRUE(CompareBytesWithByteArray(lastPair.first, FRAME_SIZE, lastPair.second))
168 << "vector size: " << vec.size() << ", size: " << FRAME_SIZE << ", address: " << std::hex << lastPair.first
169 << ", index in byte array: " << lastPair.second << ", seed: " << seed_;
170 alloc.Free(lastPair.first);
171 vec.pop_back();
172 }
173 }
174
TEST_F(StackLikeAllocatorTest,CheckAddrInsideAllocator)175 TEST_F(StackLikeAllocatorTest, CheckAddrInsideAllocator)
176 {
177 static constexpr size_t FRAME_SIZE = 256;
178 static constexpr size_t ALLOCATION_SIZE = 10;
179 void *invalidAddr = std::malloc(ALLOCATION_SIZE); // NOLINT(cppcoreguidelines-no-malloc)
180
181 StackLikeAllocator<> alloc;
182 ASSERT_FALSE(alloc.Contains(invalidAddr)); // NOLINT(clang-analyzer-unix.Malloc)
183
184 void *addr1Inside = alloc.Alloc(FRAME_SIZE);
185 ASSERT_TRUE(alloc.Contains(addr1Inside));
186 ASSERT_FALSE(alloc.Contains(invalidAddr)); // NOLINT(clang-analyzer-unix.Malloc)
187
188 alloc.Free(addr1Inside);
189 ASSERT_FALSE(alloc.Contains(addr1Inside));
190 ASSERT_FALSE(alloc.Contains(invalidAddr));
191
192 addr1Inside = alloc.Alloc(FRAME_SIZE);
193
194 auto *addr2Inside = alloc.Alloc(FRAME_SIZE * 2);
195 ASSERT_TRUE(alloc.Contains(addr1Inside));
196 ASSERT_TRUE(alloc.Contains(addr2Inside));
197 ASSERT_FALSE(alloc.Contains(invalidAddr));
198 free(invalidAddr); // NOLINT(cppcoreguidelines-no-malloc)
199 }
200 } // namespace ark::mem
201