• 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 "libpandabase/mem/mem.h"
17 #include "libpandabase/os/mem.h"
18 #include "libpandabase/utils/logger.h"
19 #include "runtime/tests/allocator_test_base.h"
20 #include "runtime/mem/internal_allocator-inl.h"
21 
22 #include <gtest/gtest.h>
23 
24 namespace ark::mem::test {
25 
26 class InternalAllocatorTest : public testing::Test {
27 public:
InternalAllocatorTest()28     InternalAllocatorTest()
29     {
30         ark::mem::MemConfig::Initialize(0, MEMORY_POOL_SIZE, 0, 0, 0, 0);
31         PoolManager::Initialize();
32         memStats_ = new mem::MemStatsType();
33         allocator_ = new InternalAllocatorT<InternalAllocatorConfig::PANDA_ALLOCATORS>(memStats_);
34     }
35 
~InternalAllocatorTest()36     ~InternalAllocatorTest() override
37     {
38         delete static_cast<Allocator *>(allocator_);
39         PoolManager::Finalize();
40         ark::mem::MemConfig::Finalize();
41         delete memStats_;
42     }
43 
44     NO_COPY_SEMANTIC(InternalAllocatorTest);
45     NO_MOVE_SEMANTIC(InternalAllocatorTest);
46 
47 protected:
48     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
49     InternalAllocatorPtr allocator_;
50 
51     static constexpr size_t MEMORY_POOL_SIZE = 16_MB;
52 
InfinitiveAllocate(size_t allocSize)53     void InfinitiveAllocate(size_t allocSize)
54     {
55         void *mem = nullptr;
56         do {
57             mem = allocator_->Alloc(allocSize);
58         } while (mem != nullptr);
59     }
60 
61     // Check that we don't have OOM and there is free space for mem pools
CheckFreeSpaceForPools()62     bool CheckFreeSpaceForPools()
63     {
64         size_t currentSpaceSize = PoolManager::GetMmapMemPool()
65                                       ->nonObjectSpacesCurrentSize_[SpaceTypeToIndex(SpaceType::SPACE_TYPE_INTERNAL)];
66         size_t maxSpaceSize =
67             PoolManager::GetMmapMemPool()->nonObjectSpacesMaxSize_[SpaceTypeToIndex(SpaceType::SPACE_TYPE_INTERNAL)];
68         ASSERT(currentSpaceSize <= maxSpaceSize);
69         return (maxSpaceSize - currentSpaceSize) >= InternalAllocator<>::RunSlotsAllocatorT::GetMinPoolSize();
70     }
71 
72 private:
73     mem::MemStatsType *memStats_;
74 };
75 
TEST_F(InternalAllocatorTest,AvoidInfiniteLoopTest)76 TEST_F(InternalAllocatorTest, AvoidInfiniteLoopTest)
77 {
78     // Regular object sizes
79     InfinitiveAllocate(RunSlots<>::MaxSlotSize());
80     // Large object sizes
81     InfinitiveAllocate(FreeListAllocator<EmptyMemoryConfig>::GetMaxSize());
82     // Humongous object sizes
83     InfinitiveAllocate(FreeListAllocator<EmptyMemoryConfig>::GetMaxSize() + 1);
84 }
85 
86 struct A {
87     NO_COPY_SEMANTIC(A);
88     NO_MOVE_SEMANTIC(A);
89 
90     static size_t count_;
Aark::mem::test::A91     A()
92     {
93         value = ++count_;
94     }
~Aark::mem::test::A95     ~A()
96     {
97         --count_;
98     }
99 
100     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
101     uint8_t value;
102 };
103 
104 size_t A::count_ = 0;
105 
TEST_F(InternalAllocatorTest,NewDeleteArray)106 TEST_F(InternalAllocatorTest, NewDeleteArray)
107 {
108     constexpr size_t COUNT = 5;
109 
110     // NOLINTNEXTLINE(modernize-avoid-c-arrays)
111     auto arr = allocator_->New<A[]>(COUNT);
112     ASSERT_NE(arr, nullptr);
113     ASSERT_EQ(ToUintPtr(arr) % DEFAULT_INTERNAL_ALIGNMENT_IN_BYTES, 0);
114     ASSERT_EQ(A::count_, COUNT);
115     for (uint8_t i = 1; i <= COUNT; ++i) {
116         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
117         ASSERT_EQ(arr[i - 1].value, i);
118     }
119     allocator_->DeleteArray(arr);
120     ASSERT_EQ(A::count_, 0);
121 }
122 
TEST_F(InternalAllocatorTest,ZeroSizeTest)123 TEST_F(InternalAllocatorTest, ZeroSizeTest)
124 {
125     ASSERT(allocator_->Alloc(0) == nullptr);
126     // Check that zero-size allocation did not result in infinite pool allocations
127     ASSERT(CheckFreeSpaceForPools());
128 
129     // Checks on correct allocations of different size
130     // Regular object size
131     void *mem = allocator_->Alloc(RunSlots<>::MaxSlotSize());
132     ASSERT(mem != nullptr);
133     allocator_->Free(mem);
134 
135     // Large object size
136     mem = allocator_->Alloc(FreeListAllocator<EmptyMemoryConfig>::GetMaxSize());
137     ASSERT(mem != nullptr);
138     allocator_->Free(mem);
139 
140     // Humongous object size
141     mem = allocator_->Alloc(FreeListAllocator<EmptyMemoryConfig>::GetMaxSize() + 1);
142     ASSERT(mem != nullptr);
143     allocator_->Free(mem);
144 }
145 
TEST_F(InternalAllocatorTest,AllocAlignmentTest)146 TEST_F(InternalAllocatorTest, AllocAlignmentTest)
147 {
148     constexpr size_t ALIGNMENT = DEFAULT_INTERNAL_ALIGNMENT_IN_BYTES * 2U;
149     constexpr size_t N = RunSlots<>::MaxSlotSize() + DEFAULT_INTERNAL_ALIGNMENT_IN_BYTES;
150 
151     struct alignas(ALIGNMENT) S {
152         // NOLINTNEXTLINE(modernize-avoid-c-arrays)
153         uint8_t a[N];
154     };
155 
156     auto isAligned = [](void *ptr) { return IsAligned(reinterpret_cast<uintptr_t>(ptr), ALIGNMENT); };
157 
158     auto *ptr = allocator_->Alloc(N);
159     if (!isAligned(ptr)) {
160         allocator_->Free(ptr);
161         ptr = nullptr;
162     }
163 
164     {
165         auto *p = allocator_->AllocArray<S>(1);
166         ASSERT_TRUE(isAligned(p));
167         allocator_->Free(p);
168     }
169 
170     {
171         auto *p = allocator_->New<S>();
172         ASSERT_TRUE(isAligned(p));
173         allocator_->Delete(p);
174     }
175 
176     {
177         // NOLINTNEXTLINE(modernize-avoid-c-arrays)
178         auto *p = allocator_->New<S[]>(1);
179         ASSERT_TRUE(isAligned(p));
180         allocator_->DeleteArray(p);
181     }
182 
183     if (ptr != nullptr) {
184         allocator_->Free(ptr);
185     }
186 }
187 
TEST_F(InternalAllocatorTest,AllocLocalAlignmentTest)188 TEST_F(InternalAllocatorTest, AllocLocalAlignmentTest)
189 {
190     constexpr size_t ALIGNMENT = DEFAULT_INTERNAL_ALIGNMENT_IN_BYTES * 2U;
191     constexpr size_t N = RunSlots<>::MaxSlotSize() + DEFAULT_INTERNAL_ALIGNMENT_IN_BYTES;
192 
193     struct alignas(ALIGNMENT) S {
194         // NOLINTNEXTLINE(modernize-avoid-c-arrays)
195         uint8_t a[N];
196     };
197 
198     auto isAligned = [](void *ptr) { return IsAligned(reinterpret_cast<uintptr_t>(ptr), ALIGNMENT); };
199 
200     auto *ptr = allocator_->AllocLocal(N);
201     if (!isAligned(ptr)) {
202         allocator_->Free(ptr);
203         ptr = nullptr;
204     }
205 
206     {
207         auto *p = allocator_->AllocArrayLocal<S>(1);
208         ASSERT_TRUE(isAligned(p));
209         allocator_->Free(p);
210     }
211 
212     {
213         auto *p = allocator_->AllocArrayLocal<S>(1);
214         ASSERT_TRUE(isAligned(p));
215         allocator_->Free(p);
216     }
217 
218     {
219         auto *p = allocator_->NewLocal<S>();
220         ASSERT_TRUE(isAligned(p));
221         allocator_->Delete(p);
222     }
223 
224     {
225         // NOLINTNEXTLINE(modernize-avoid-c-arrays)
226         auto *p = allocator_->NewLocal<S[]>(1);
227         ASSERT_TRUE(isAligned(p));
228         allocator_->DeleteArray(p);
229     }
230 
231     if (ptr != nullptr) {
232         allocator_->Free(ptr);
233     }
234 }
235 
TEST_F(InternalAllocatorTest,MoveContainerTest)236 TEST_F(InternalAllocatorTest, MoveContainerTest)
237 {
238     using TestValueType = int;
239     constexpr auto MAGIC_VALUE = TestValueType {};
240     AllocatorAdapter<TestValueType> adapter = allocator_->Adapter();
241     using TestVector = std::vector<TestValueType, decltype(adapter)>;
242     TestVector vector1(adapter);
243     TestVector vector2(adapter);
244     // Swap
245     auto vector3 = std::move(vector2);
246     vector2 = std::move(vector1);
247     vector1 = std::move(vector3);
248     vector2.emplace_back(MAGIC_VALUE);
249     ASSERT_EQ(vector2.back(), MAGIC_VALUE);
250     ASSERT_EQ(vector2.get_allocator(), adapter);
251 
252     using TestDeque = std::deque<TestValueType, decltype(adapter)>;
253     TestDeque *dequeTmp = allocator_->New<TestDeque>(allocator_->Adapter());
254     *dequeTmp = TestDeque(allocator_->Adapter());
255     dequeTmp->push_back(MAGIC_VALUE);
256     ASSERT_EQ(dequeTmp->get_allocator(), allocator_->Adapter());
257     ASSERT_EQ(dequeTmp->back(), MAGIC_VALUE);
258     allocator_->Delete(dequeTmp);
259 }
260 
261 }  // namespace ark::mem::test
262