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