• 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 <sys/mman.h>
17 
18 #include "libpandabase/mem/mem.h"
19 #include "libpandabase/os/mem.h"
20 #include "libpandabase/utils/asan_interface.h"
21 #include "libpandabase/utils/logger.h"
22 #include "libpandabase/utils/math_helpers.h"
23 #include "runtime/mem/alloc_config.h"
24 #include "runtime/mem/humongous_obj_allocator-inl.h"
25 #include "runtime/tests/allocator_test_base.h"
26 
27 namespace ark::mem {
28 
29 using NonObjectHumongousObjAllocator = HumongousObjAllocator<EmptyAllocConfigWithCrossingMap>;
30 
31 class HumongousObjAllocatorTest : public AllocatorTest<NonObjectHumongousObjAllocator> {
32 public:
33     NO_COPY_SEMANTIC(HumongousObjAllocatorTest);
34     NO_MOVE_SEMANTIC(HumongousObjAllocatorTest);
35 
HumongousObjAllocatorTest()36     HumongousObjAllocatorTest()
37     {
38         // Logger::InitializeStdLogging(Logger::Level::DEBUG, Logger::Component::ALL);
39         // NOLINTNEXTLINE(readability-magic-numbers)
40         ark::mem::MemConfig::Initialize(0, 1024_MB, 0, 0, 0, 0);
41         PoolManager::Initialize();
42     }
43 
~HumongousObjAllocatorTest()44     ~HumongousObjAllocatorTest() override
45     {
46         ClearPoolManager();
47         PoolManager::Finalize();
48         ark::mem::MemConfig::Finalize();
49         // Logger::Destroy();
50     }
51 
52 protected:
53     static constexpr size_t MIN_ALLOC_SIZE = 1_MB;
54     static constexpr size_t MAX_ALLOC_SIZE = 9_MB;
55     static constexpr Alignment HUMONGOUS_LOG_MAX_ALIGN = LOG_ALIGN_11;
56     static constexpr size_t DEFAULT_POOL_SIZE_FOR_ALLOC =
57         NonObjectHumongousObjAllocator::GetMinPoolSize(MAX_ALLOC_SIZE);
58     static constexpr size_t POOL_HEADER_SIZE = sizeof(NonObjectHumongousObjAllocator::MemoryPoolHeader);
59 
AddMemoryPoolToAllocator(NonObjectHumongousObjAllocator & alloc)60     void AddMemoryPoolToAllocator(NonObjectHumongousObjAllocator &alloc) override
61     {
62         AddMemoryPoolToAllocator(alloc, DEFAULT_POOL_SIZE_FOR_ALLOC);
63     }
64 
AddMemoryPoolToAllocator(NonObjectHumongousObjAllocator & alloc,size_t size)65     void AddMemoryPoolToAllocator(NonObjectHumongousObjAllocator &alloc, size_t size)
66     {
67         os::memory::LockHolder lock(poolLock_);
68         size = AlignUp(size, PANDA_POOL_ALIGNMENT_IN_BYTES);
69         Pool pool = PoolManager::GetMmapMemPool()->AllocPool(AlignUp(size, PANDA_POOL_ALIGNMENT_IN_BYTES),
70                                                              SpaceType::SPACE_TYPE_INTERNAL,
71                                                              AllocatorType::HUMONGOUS_ALLOCATOR, &alloc);
72         ASSERT(pool.GetSize() >= size);
73         if (pool.GetMem() == nullptr) {
74             ASSERT_TRUE(0 && "Can't get a new pool from PoolManager");
75         }
76         allocatedPoolsByPoolManager_.push_back(pool);
77         if (!alloc.AddMemoryPool(pool.GetMem(), size)) {
78             ASSERT_TRUE(0 && "Can't add mem pool to allocator");
79         }
80     }
81 
AddMemoryPoolToAllocatorProtected(NonObjectHumongousObjAllocator & alloc)82     void AddMemoryPoolToAllocatorProtected(NonObjectHumongousObjAllocator &alloc) override
83     {
84         // We use common PoolManager from Runtime. Therefore, we have the same pool allocation for both cases.
85         AddMemoryPoolToAllocator(alloc);
86     }
87 
AllocatedByThisAllocator(NonObjectHumongousObjAllocator & allocator,void * mem)88     bool AllocatedByThisAllocator(NonObjectHumongousObjAllocator &allocator, void *mem) override
89     {
90         return allocator.AllocatedByHumongousObjAllocator(mem);
91     }
92 
ClearPoolManager()93     void ClearPoolManager()
94     {
95         for (auto i : allocatedPoolsByPoolManager_) {
96             PoolManager::GetMmapMemPool()->FreePool(i.GetMem(), i.GetSize());
97         }
98         allocatedPoolsByPoolManager_.clear();
99     }
100 
101 private:
102     std::vector<Pool> allocatedPoolsByPoolManager_;
103     // Mutex, which allows only one thread to add pool to the pool vector
104     os::memory::Mutex poolLock_;
105 };
106 
TEST_F(HumongousObjAllocatorTest,CheckIncorrectMemoryPoolReusageTest)107 TEST_F(HumongousObjAllocatorTest, CheckIncorrectMemoryPoolReusageTest)
108 {
109     static constexpr size_t POOL_SIZE = 4_MB;
110     static constexpr Alignment OBJECT_ALIGNMENT = DEFAULT_ALIGNMENT;
111     static constexpr size_t FIRST_OBJECT_SIZE = POOL_SIZE - PANDA_POOL_ALIGNMENT_IN_BYTES;
112     static constexpr size_t SECOND_OBJECT_SIZE = POOL_SIZE - GetAlignmentInBytes(OBJECT_ALIGNMENT);
113     ASSERT(PANDA_POOL_ALIGNMENT_IN_BYTES > GetAlignmentInBytes(OBJECT_ALIGNMENT));
114     ASSERT_TRUE(NonObjectHumongousObjAllocator::GetMinPoolSize(FIRST_OBJECT_SIZE) == POOL_SIZE);
115     mem::MemStatsType memStats;
116     NonObjectHumongousObjAllocator allocator(&memStats);
117     AddMemoryPoolToAllocator(allocator, POOL_SIZE);
118     void *firstObject = allocator.Alloc(FIRST_OBJECT_SIZE, OBJECT_ALIGNMENT);
119     ASSERT_TRUE(firstObject != nullptr);
120     allocator.Free(firstObject);
121     void *secondObject = allocator.Alloc(SECOND_OBJECT_SIZE, OBJECT_ALIGNMENT);
122     ASSERT_TRUE(secondObject == nullptr);
123 }
124 
TEST_F(HumongousObjAllocatorTest,SimpleAllocateDifferentObjSizeTest)125 TEST_F(HumongousObjAllocatorTest, SimpleAllocateDifferentObjSizeTest)
126 {
127     LOG(DEBUG, ALLOC) << "SimpleAllocateDifferentObjSizeTest";
128     auto *memStats = new mem::MemStatsType();
129     NonObjectHumongousObjAllocator allocator(memStats);
130     std::vector<void *> values;
131     // NOLINTNEXTLINE(readability-magic-numbers)
132     for (size_t i = 0; i < 20U; i++) {
133         size_t poolSize = DEFAULT_POOL_SIZE_FOR_ALLOC + PAGE_SIZE * i;
134         size_t allocSize = poolSize - sizeof(POOL_HEADER_SIZE) - GetAlignmentInBytes(LOG_ALIGN_MAX);
135         AddMemoryPoolToAllocator(allocator, poolSize);
136         void *mem = allocator.Alloc(allocSize);
137         ASSERT_TRUE(mem != nullptr);
138         values.push_back(mem);
139         LOG(DEBUG, ALLOC) << "Allocate obj with size " << allocSize << " at " << std::hex << mem;
140     }
141     for (auto i : values) {
142         allocator.Free(i);
143     }
144     // NOLINTNEXTLINE(readability-magic-numbers)
145     for (size_t i = 0; i < 20U; i++) {
146         void *mem = allocator.Alloc(MAX_ALLOC_SIZE);
147         ASSERT_TRUE(mem != nullptr);
148     }
149     delete memStats;
150 }
151 
TEST_F(HumongousObjAllocatorTest,AllocateWriteFreeTest)152 TEST_F(HumongousObjAllocatorTest, AllocateWriteFreeTest)
153 {
154     static constexpr size_t ELEMENTS_COUNT = 100;
155     static constexpr size_t POOLS_COUNT = ELEMENTS_COUNT;
156     AllocateAndFree(MIN_ALLOC_SIZE, ELEMENTS_COUNT, POOLS_COUNT);
157 }
158 
TEST_F(HumongousObjAllocatorTest,AllocateRandomFreeTest)159 TEST_F(HumongousObjAllocatorTest, AllocateRandomFreeTest)
160 {
161     static constexpr size_t ELEMENTS_COUNT = 100;
162     static constexpr size_t POOLS_COUNT = ELEMENTS_COUNT;
163     AllocateFreeDifferentSizesTest<MIN_ALLOC_SIZE, MAX_ALLOC_SIZE>(ELEMENTS_COUNT, POOLS_COUNT);
164 }
165 
TEST_F(HumongousObjAllocatorTest,AlignmentAllocTest)166 TEST_F(HumongousObjAllocatorTest, AlignmentAllocTest)
167 {
168     static constexpr size_t MAX_ALLOC = MIN_ALLOC_SIZE + 10U;
169     static constexpr size_t POOLS_COUNT =
170         (MAX_ALLOC - MIN_ALLOC_SIZE + 1) * (HUMONGOUS_LOG_MAX_ALIGN - LOG_ALIGN_MIN + 1);
171     AlignedAllocFreeTest<MIN_ALLOC_SIZE, MAX_ALLOC, LOG_ALIGN_MIN, HUMONGOUS_LOG_MAX_ALIGN>(POOLS_COUNT);
172 }
173 
TEST_F(HumongousObjAllocatorTest,AllocateTooMuchTest)174 TEST_F(HumongousObjAllocatorTest, AllocateTooMuchTest)
175 {
176     static constexpr size_t ELEMENTS_COUNT = 2;
177     AllocateTooMuchTest(MIN_ALLOC_SIZE, ELEMENTS_COUNT);
178 }
179 
TEST_F(HumongousObjAllocatorTest,ObjectIteratorTest)180 TEST_F(HumongousObjAllocatorTest, ObjectIteratorTest)
181 {
182     static constexpr size_t FREE_GRANULARITY = 1;
183     static constexpr size_t POOLS_COUNT = 50;
184     ObjectIteratorTest<MIN_ALLOC_SIZE, MAX_ALLOC_SIZE, LOG_ALIGN_MIN, HUMONGOUS_LOG_MAX_ALIGN>(FREE_GRANULARITY,
185                                                                                                POOLS_COUNT);
186 }
187 
TEST_F(HumongousObjAllocatorTest,ObjectCollectionTest)188 TEST_F(HumongousObjAllocatorTest, ObjectCollectionTest)
189 {
190     static constexpr size_t FREE_GRANULARITY = 1;
191     static constexpr size_t POOLS_COUNT = 50;
192     ObjectCollectionTest<MIN_ALLOC_SIZE, MAX_ALLOC_SIZE, LOG_ALIGN_MIN, HUMONGOUS_LOG_MAX_ALIGN>(FREE_GRANULARITY,
193                                                                                                  POOLS_COUNT);
194 }
195 
TEST_F(HumongousObjAllocatorTest,ObjectIteratorInRangeTest)196 TEST_F(HumongousObjAllocatorTest, ObjectIteratorInRangeTest)
197 {
198     static constexpr size_t FREE_GRANULARITY = 4;
199     static constexpr size_t POOLS_COUNT = 50;
200     ObjectIteratorInRangeTest<MIN_ALLOC_SIZE, MAX_ALLOC_SIZE, LOG_ALIGN_MIN, HUMONGOUS_LOG_MAX_ALIGN>(
201         CrossingMapSingleton::GetCrossingMapGranularity(), FREE_GRANULARITY, POOLS_COUNT);
202 }
203 
TEST_F(HumongousObjAllocatorTest,AsanTest)204 TEST_F(HumongousObjAllocatorTest, AsanTest)
205 {
206     static constexpr size_t ELEMENTS_COUNT = 100;
207     static constexpr size_t POOLS_COUNT = ELEMENTS_COUNT;
208     static constexpr size_t FREE_GRANULARITY = 3;
209     AsanTest<ELEMENTS_COUNT>(FREE_GRANULARITY, POOLS_COUNT);
210 }
211 
TEST_F(HumongousObjAllocatorTest,VisitAndRemoveFreePoolsTest)212 TEST_F(HumongousObjAllocatorTest, VisitAndRemoveFreePoolsTest)
213 {
214     static_assert(PANDA_HUMONGOUS_OBJ_ALLOCATOR_RESERVED_MEM_MAX_POOL_SIZE < MAX_ALLOC_SIZE);
215     static constexpr size_t POOLS_COUNT = 5;
216     VisitAndRemoveFreePools<POOLS_COUNT>(MAX_ALLOC_SIZE);
217 }
218 
TEST_F(HumongousObjAllocatorTest,AllocatedByHumongousObjAllocatorTest)219 TEST_F(HumongousObjAllocatorTest, AllocatedByHumongousObjAllocatorTest)
220 {
221     AllocatedByThisAllocatorTest();
222 }
223 
TEST_F(HumongousObjAllocatorTest,MTAllocFreeTest)224 TEST_F(HumongousObjAllocatorTest, MTAllocFreeTest)
225 {
226     static constexpr size_t MIN_ELEMENTS_COUNT = 10;
227     static constexpr size_t MAX_ELEMENTS_COUNT = 20;
228 #if defined(PANDA_TARGET_ARM64) || defined(PANDA_TARGET_32)
229     // We have an issue with QEMU during MT tests. Issue 2852
230     static constexpr size_t THREADS_COUNT = 1;
231 #else
232     static constexpr size_t THREADS_COUNT = 5;
233 #endif
234     static constexpr size_t MT_TEST_RUN_COUNT = 5;
235     for (size_t i = 0; i < MT_TEST_RUN_COUNT; i++) {
236         MtAllocFreeTest<MIN_ALLOC_SIZE, MAX_ALLOC_SIZE, THREADS_COUNT>(MIN_ELEMENTS_COUNT, MAX_ELEMENTS_COUNT);
237         ClearPoolManager();
238     }
239 }
240 
TEST_F(HumongousObjAllocatorTest,MTAllocIterateTest)241 TEST_F(HumongousObjAllocatorTest, MTAllocIterateTest)
242 {
243     static constexpr size_t MIN_ELEMENTS_COUNT = 10;
244     static constexpr size_t MAX_ELEMENTS_COUNT = 20;
245 #if defined(PANDA_TARGET_ARM64) || defined(PANDA_TARGET_32)
246     // We have an issue with QEMU during MT tests. Issue 2852
247     static constexpr size_t THREADS_COUNT = 1;
248 #else
249     static constexpr size_t THREADS_COUNT = 5;
250 #endif
251     static constexpr size_t MT_TEST_RUN_COUNT = 5;
252     for (size_t i = 0; i < MT_TEST_RUN_COUNT; i++) {
253         MtAllocIterateTest<MIN_ALLOC_SIZE, MAX_ALLOC_SIZE, THREADS_COUNT>(
254             MIN_ELEMENTS_COUNT, MAX_ELEMENTS_COUNT, CrossingMapSingleton::GetCrossingMapGranularity());
255         ClearPoolManager();
256     }
257 }
258 
TEST_F(HumongousObjAllocatorTest,MTAllocCollectTest)259 TEST_F(HumongousObjAllocatorTest, MTAllocCollectTest)
260 {
261     static constexpr size_t MIN_ELEMENTS_COUNT = 10;
262     static constexpr size_t MAX_ELEMENTS_COUNT = 20;
263 #if defined(PANDA_TARGET_ARM64) || defined(PANDA_TARGET_32)
264     // We have an issue with QEMU during MT tests. Issue 2852
265     static constexpr size_t THREADS_COUNT = 1;
266 #else
267     static constexpr size_t THREADS_COUNT = 5;
268 #endif
269     static constexpr size_t MT_TEST_RUN_COUNT = 5;
270     for (size_t i = 0; i < MT_TEST_RUN_COUNT; i++) {
271         MtAllocCollectTest<MIN_ALLOC_SIZE, MAX_ALLOC_SIZE, THREADS_COUNT>(MIN_ELEMENTS_COUNT, MAX_ELEMENTS_COUNT);
272         ClearPoolManager();
273     }
274 }
275 
276 }  // namespace ark::mem
277