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