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 "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 panda::mem::test {
25
26 class InternalAllocatorTest : public testing::Test {
27 public:
InternalAllocatorTest()28 InternalAllocatorTest()
29 {
30 // Logger::InitializeStdLogging(Logger::Level::DEBUG, Logger::Component::ALL);
31 panda::mem::MemConfig::Initialize(0, MEMORY_POOL_SIZE, 0, 0);
32 PoolManager::Initialize();
33 mem_stats_ = new mem::MemStatsType();
34 allocator_ = new InternalAllocatorT<InternalAllocatorConfig::PANDA_ALLOCATORS>(mem_stats_);
35 }
36
~InternalAllocatorTest()37 ~InternalAllocatorTest()
38 {
39 delete static_cast<Allocator *>(allocator_);
40 PoolManager::Finalize();
41 panda::mem::MemConfig::Finalize();
42 delete mem_stats_;
43 // Logger::Destroy();
44 }
45
46 protected:
47 mem::MemStatsType *mem_stats_;
48 InternalAllocatorPtr allocator_;
49
50 static constexpr size_t MEMORY_POOL_SIZE = 16_MB;
51
InfinitiveAllocate(size_t alloc_size)52 void InfinitiveAllocate(size_t alloc_size)
53 {
54 void *mem = nullptr;
55 do {
56 mem = allocator_->Alloc(alloc_size);
57 } while (mem != nullptr);
58 }
59
60 // Check that we don't have OOM and there is free space for mem pools
CheckFreeSpaceForPools()61 bool CheckFreeSpaceForPools()
62 {
63 size_t current_space_size = PoolManager::GetMmapMemPool()->internal_space_current_size_;
64 size_t max_space_size = PoolManager::GetMmapMemPool()->internal_space_max_size_;
65 ASSERT(current_space_size <= max_space_size);
66 return (max_space_size - current_space_size) >= InternalAllocator<>::RunSlotsAllocatorT::GetMinPoolSize();
67 }
68 };
69
TEST_F(InternalAllocatorTest,AvoidInfiniteLoopTest)70 TEST_F(InternalAllocatorTest, AvoidInfiniteLoopTest)
71 {
72 // Regular object sizes
73 InfinitiveAllocate(RunSlots<>::MaxSlotSize());
74 // Large object sizes
75 InfinitiveAllocate(FreeListAllocator<EmptyMemoryConfig>::GetMaxSize());
76 // Humongous object sizes
77 InfinitiveAllocate(FreeListAllocator<EmptyMemoryConfig>::GetMaxSize() + 1);
78 }
79
80 struct A {
81 static size_t count;
Apanda::mem::test::A82 A()
83 {
84 value = ++count;
85 }
~Apanda::mem::test::A86 ~A()
87 {
88 --count;
89 }
90
91 uint8_t value;
92 };
93
94 size_t A::count = 0;
95
TEST_F(InternalAllocatorTest,NewDeleteArray)96 TEST_F(InternalAllocatorTest, NewDeleteArray)
97 {
98 constexpr size_t COUNT = 5;
99
100 auto arr = allocator_->New<A[]>(COUNT);
101 ASSERT_NE(arr, nullptr);
102 ASSERT_EQ(ToUintPtr(arr) % DEFAULT_ALIGNMENT_IN_BYTES, 0);
103 ASSERT_EQ(A::count, COUNT);
104 for (uint8_t i = 1; i <= COUNT; ++i) {
105 ASSERT_EQ(arr[i - 1].value, i);
106 }
107 allocator_->DeleteArray(arr);
108 ASSERT_EQ(A::count, 0);
109 }
110
TEST_F(InternalAllocatorTest,ZeroSizeTest)111 TEST_F(InternalAllocatorTest, ZeroSizeTest)
112 {
113 ASSERT(allocator_->Alloc(0) == nullptr);
114 // Check that zero-size allocation did not result in infinite pool allocations
115 ASSERT(CheckFreeSpaceForPools());
116
117 // Checks on correct allocations of different size
118 // Regular object size
119 void *mem = allocator_->Alloc(RunSlots<>::MaxSlotSize());
120 ASSERT(mem != nullptr);
121 allocator_->Free(mem);
122
123 // Large object size
124 mem = allocator_->Alloc(FreeListAllocator<EmptyMemoryConfig>::GetMaxSize());
125 ASSERT(mem != nullptr);
126 allocator_->Free(mem);
127
128 // Humongous object size
129 mem = allocator_->Alloc(FreeListAllocator<EmptyMemoryConfig>::GetMaxSize() + 1);
130 ASSERT(mem != nullptr);
131 allocator_->Free(mem);
132 }
133
TEST_F(InternalAllocatorTest,AllocAlignmentTest)134 TEST_F(InternalAllocatorTest, AllocAlignmentTest)
135 {
136 constexpr size_t ALIGNMENT = DEFAULT_ALIGNMENT_IN_BYTES * 2U;
137 constexpr size_t N = RunSlots<>::MaxSlotSize() + DEFAULT_ALIGNMENT_IN_BYTES;
138
139 struct alignas(ALIGNMENT) S {
140 uint8_t a[N];
141 };
142
143 auto is_aligned = [](void *ptr) { return IsAligned(reinterpret_cast<uintptr_t>(ptr), ALIGNMENT); };
144
145 auto *ptr = allocator_->Alloc(N);
146 if (!is_aligned(ptr)) {
147 allocator_->Free(ptr);
148 ptr = nullptr;
149 }
150
151 {
152 auto *p = allocator_->AllocArray<S>(1);
153 ASSERT_TRUE(is_aligned(p));
154 allocator_->Free(p);
155 }
156
157 {
158 auto *p = allocator_->New<S>();
159 ASSERT_TRUE(is_aligned(p));
160 allocator_->Delete(p);
161 }
162
163 {
164 auto *p = allocator_->New<S[]>(1);
165 ASSERT_TRUE(is_aligned(p));
166 allocator_->DeleteArray(p);
167 }
168
169 if (ptr != nullptr) {
170 allocator_->Free(ptr);
171 }
172 }
173
TEST_F(InternalAllocatorTest,AllocLocalAlignmentTest)174 TEST_F(InternalAllocatorTest, AllocLocalAlignmentTest)
175 {
176 constexpr size_t ALIGNMENT = DEFAULT_ALIGNMENT_IN_BYTES * 2U;
177 constexpr size_t N = RunSlots<>::MaxSlotSize() + DEFAULT_ALIGNMENT_IN_BYTES;
178
179 struct alignas(ALIGNMENT) S {
180 uint8_t a[N];
181 };
182
183 auto is_aligned = [](void *ptr) { return IsAligned(reinterpret_cast<uintptr_t>(ptr), ALIGNMENT); };
184
185 auto *ptr = allocator_->AllocLocal(N);
186 if (!is_aligned(ptr)) {
187 allocator_->Free(ptr);
188 ptr = nullptr;
189 }
190
191 {
192 auto *p = allocator_->AllocArrayLocal<S>(1);
193 ASSERT_TRUE(is_aligned(p));
194 allocator_->Free(p);
195 }
196
197 {
198 auto *p = allocator_->AllocArrayLocal<S>(1);
199 ASSERT_TRUE(is_aligned(p));
200 allocator_->Free(p);
201 }
202
203 {
204 auto *p = allocator_->NewLocal<S>();
205 ASSERT_TRUE(is_aligned(p));
206 allocator_->Delete(p);
207 }
208
209 {
210 auto *p = allocator_->NewLocal<S[]>(1);
211 ASSERT_TRUE(is_aligned(p));
212 allocator_->DeleteArray(p);
213 }
214
215 if (ptr != nullptr) {
216 allocator_->Free(ptr);
217 }
218 }
219
220 } // namespace panda::mem::test
221