• 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 <ctime>
17 
18 #include "gtest/gtest.h"
19 #include "runtime/mem/alloc_config.h"
20 #include "runtime/mem/bump-allocator-inl.h"
21 #include "libpandabase/test_utilities.h"
22 
23 namespace ark::mem {
24 
25 template <bool USE_TLABS>
26 using NonObjectBumpAllocator =
27     BumpPointerAllocator<EmptyMemoryConfig, BumpPointerAllocatorLockConfig::CommonLock, USE_TLABS>;
28 
29 class BumpAllocatorTest : public testing::Test {
30 public:
BumpAllocatorTest()31     BumpAllocatorTest()
32     {
33         // Logger::InitializeStdLogging(Logger::Level::DEBUG, Logger::Component::ALL);
34 #ifdef PANDA_NIGHTLY_TEST_ON
35         seed_ = std::time(NULL);
36 #else
37         // NOLINTNEXTLINE(readability-magic-numbers)
38         seed_ = 0x0BADDEAD;
39 #endif
40         srand(seed_);
41         ark::mem::MemConfig::Initialize(0, 8_MB, 0, 0, 0, 0);
42         PoolManager::Initialize();
43     }
44 
~BumpAllocatorTest()45     ~BumpAllocatorTest() override
46     {
47         for (auto i : allocatedMemMmap_) {
48             ark::os::mem::UnmapRaw(std::get<0>(i), std::get<1>(i));
49         }
50         for (auto i : allocatedArenas_) {
51             delete i;
52         }
53         PoolManager::Finalize();
54         ark::mem::MemConfig::Finalize();
55         // Logger::Destroy();
56     }
57 
58     NO_COPY_SEMANTIC(BumpAllocatorTest);
59     NO_MOVE_SEMANTIC(BumpAllocatorTest);
60 
61 protected:
AllocateArena(size_t size)62     Arena *AllocateArena(size_t size)
63     {
64         void *mem = ark::os::mem::MapRWAnonymousRaw(size);
65         ASAN_UNPOISON_MEMORY_REGION(mem, size);
66         std::pair<void *, size_t> newPair {mem, size};
67         allocatedMemMmap_.push_back(newPair);
68         auto arena = new Arena(size, mem);
69         allocatedArenas_.push_back(arena);
70         return arena;
71     }
72 
73     template <class AllocType, size_t ELEMENTS_COUNT>
AllocInCommonBuffer(NonObjectBumpAllocator<true> & allocator,std::array<AllocType *,ELEMENTS_COUNT> & elements)74     void AllocInCommonBuffer(NonObjectBumpAllocator<true> &allocator, std::array<AllocType *, ELEMENTS_COUNT> &elements)
75     {
76         for (size_t i = 0; i < ELEMENTS_COUNT; ++i) {
77             elements[i] = static_cast<AllocType *>(allocator.Alloc(sizeof(AllocType)));
78             ASSERT_TRUE(elements[i] != nullptr);
79             *elements[i] = AllocType(i) % std::numeric_limits<AllocType>::max();
80         }
81     }
82 
83     template <class AllocType, size_t ELEMENTS_COUNT>
AllocInTLAB(TLAB * tlab,std::array<AllocType *,ELEMENTS_COUNT> & elements)84     void AllocInTLAB(TLAB *tlab, std::array<AllocType *, ELEMENTS_COUNT> &elements)
85     {
86         for (size_t i = 0; i < ELEMENTS_COUNT; ++i) {
87             elements[i] = static_cast<AllocType *>(tlab->Alloc(sizeof(AllocType)));
88             ASSERT_TRUE(elements[i] != nullptr);
89             *elements[i] = AllocType(i) % std::numeric_limits<AllocType>::max();
90         }
91     }
92 
93     template <class AllocType, size_t ELEMENTS_COUNT>
CheckAlloc(std::array<AllocType *,ELEMENTS_COUNT> & elements)94     void CheckAlloc(std::array<AllocType *, ELEMENTS_COUNT> &elements)
95     {
96         size_t mask = DEFAULT_ALIGNMENT_IN_BYTES - 1;
97         for (size_t i = 0; i < ELEMENTS_COUNT; ++i) {
98             ASSERT_NE(elements[i], nullptr) << "value of i: " << i;
99             ASSERT_EQ(reinterpret_cast<size_t>(elements[i]) & mask, static_cast<size_t>(0)) << "value of i: " << i;
100             ASSERT_EQ(*elements[i], AllocType(i) % std::numeric_limits<AllocType>::max()) << "value of i: " << i;
101         }
102     }
103 
104     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
105     unsigned seed_ {};
106 
107 private:
108     std::vector<std::pair<void *, size_t>> allocatedMemMmap_;
109     std::vector<Arena *> allocatedArenas_;
110 };
111 
DEATH_TEST_F(BumpAllocatorTest,AlignedAlloc)112 DEATH_TEST_F(BumpAllocatorTest, AlignedAlloc)
113 {
114     testing::FLAGS_gtest_death_test_style = "threadsafe";
115     constexpr size_t BUFF_SIZE = 1_MB;
116     constexpr size_t ARRAY_SIZE = 1024;
117     auto pool = PoolManager::GetMmapMemPool()->AllocPool(BUFF_SIZE, SpaceType::SPACE_TYPE_INTERNAL,
118                                                          AllocatorType::BUMP_ALLOCATOR);
119     mem::MemStatsType memStats;
120     NonObjectBumpAllocator<false> bpAllocator(pool, SpaceType::SPACE_TYPE_INTERNAL, &memStats);
121     Alignment align = DEFAULT_ALIGNMENT;
122     std::array<int *, ARRAY_SIZE> arr {};
123 
124     size_t mask = GetAlignmentInBytes(align) - 1;
125 
126     // Allocations
127     srand(seed_);
128     for (size_t i = 0; i < ARRAY_SIZE; ++i) {
129         arr[i] = static_cast<int *>(bpAllocator.Alloc(sizeof(int), align));
130         // NOLINTNEXTLINE(cert-msc50-cpp)
131         *arr[i] = rand() % std::numeric_limits<int>::max();
132     }
133 
134     // Allocations checking
135     srand(seed_);
136     for (size_t i = 0; i < ARRAY_SIZE; ++i) {
137         ASSERT_NE(arr[i], nullptr) << "value of i: " << i << ", align: " << align << ", seed:" << seed_;
138         ASSERT_EQ(reinterpret_cast<size_t>(arr[i]) & mask, static_cast<size_t>(0))
139             << "value of i: " << i << ", align: " << align << ", seed:" << seed_;
140         // NOLINTNEXTLINE(cert-msc50-cpp)
141         ASSERT_EQ(*arr[i], rand() % std::numeric_limits<int>::max())
142             << "value of i: " << i << ", align: " << align << ", seed:" << seed_;
143     }
144     static_assert(LOG_ALIGN_MAX != DEFAULT_ALIGNMENT, "We expect minimal alignment != DEFAULT_ALIGNMENT");
145     void *ptr;
146 #ifndef NDEBUG
147     EXPECT_DEATH_IF_SUPPORTED(ptr = bpAllocator.Alloc(sizeof(int), LOG_ALIGN_MAX), "alignment == DEFAULT_ALIGNMENT")
148         << ", seed:" << seed_;
149 #endif
150     ptr = bpAllocator.Alloc(1_MB);
151     ASSERT_EQ(ptr, nullptr) << "Here Alloc with allocation size = 1 MB should return nullptr"
152                             << ", seed:" << seed_;
153 }
154 
TEST_F(BumpAllocatorTest,CreateTLABAndAlloc)155 TEST_F(BumpAllocatorTest, CreateTLABAndAlloc)
156 {
157     using AllocType = uint64_t;
158     static_assert(sizeof(AllocType) % DEFAULT_ALIGNMENT_IN_BYTES == 0);
159     constexpr size_t TLAB_SIZE = 1_MB;
160     constexpr size_t COMMON_BUFFER_SIZE = 1_MB;
161     constexpr size_t TLAB_ALLOC_COUNT_SIZE = TLAB_SIZE / sizeof(AllocType);
162     constexpr size_t COMMON_ALLOC_COUNT_SIZE = COMMON_BUFFER_SIZE / sizeof(AllocType);
163 
164     std::array<AllocType *, TLAB_ALLOC_COUNT_SIZE> tlabElements {};
165     std::array<AllocType *, COMMON_ALLOC_COUNT_SIZE> commonElements {};
166     auto pool = PoolManager::GetMmapMemPool()->AllocPool(TLAB_SIZE + COMMON_BUFFER_SIZE, SpaceType::SPACE_TYPE_INTERNAL,
167                                                          AllocatorType::BUMP_ALLOCATOR);
168     mem::MemStatsType memStats;
169     NonObjectBumpAllocator<true> allocator(pool, SpaceType::SPACE_TYPE_OBJECT, &memStats, 1U);
170     {
171         AllocInCommonBuffer(allocator, commonElements);
172         TLAB *tlab = allocator.CreateNewTLAB(TLAB_SIZE);
173         ASSERT_TRUE(tlab != nullptr) << ", seed:" << seed_;
174         ASSERT_TRUE(allocator.CreateNewTLAB(TLAB_SIZE) == nullptr) << ", seed:" << seed_;
175         AllocInTLAB(tlab, tlabElements);
176         // Check that we don't have memory in the buffer:
177         ASSERT_TRUE(allocator.Alloc(sizeof(AllocType)) == nullptr);
178         ASSERT_TRUE(tlab->Alloc(sizeof(AllocType)) == nullptr);
179         CheckAlloc(commonElements);
180         CheckAlloc(tlabElements);
181     }
182     allocator.Reset();
183     {
184         TLAB *tlab = allocator.CreateNewTLAB(TLAB_SIZE);
185         ASSERT_TRUE(tlab != nullptr) << ", seed:" << seed_;
186         ASSERT_TRUE(allocator.CreateNewTLAB(TLAB_SIZE) == nullptr) << ", seed:" << seed_;
187         AllocInTLAB(tlab, tlabElements);
188         AllocInCommonBuffer(allocator, commonElements);
189         // Check that we don't have memory in the buffer:
190         ASSERT_TRUE(allocator.Alloc(sizeof(AllocType)) == nullptr);
191         ASSERT_TRUE(tlab->Alloc(sizeof(AllocType)) == nullptr);
192         CheckAlloc(tlabElements);
193         CheckAlloc(commonElements);
194     }
195 }
196 
TEST_F(BumpAllocatorTest,CreateTooManyTLABS)197 TEST_F(BumpAllocatorTest, CreateTooManyTLABS)
198 {
199     constexpr size_t TLAB_SIZE = 1_MB;
200     constexpr size_t TLAB_COUNT = 3;
201     auto pool = PoolManager::GetMmapMemPool()->AllocPool(TLAB_SIZE * TLAB_COUNT, SpaceType::SPACE_TYPE_INTERNAL,
202                                                          AllocatorType::BUMP_ALLOCATOR);
203     mem::MemStatsType memStats;
204     NonObjectBumpAllocator<true> allocator(pool, SpaceType::SPACE_TYPE_OBJECT, &memStats, TLAB_COUNT - 1);
205     {
206         for (size_t i = 0; i < TLAB_COUNT - 1; i++) {
207             TLAB *tlab = allocator.CreateNewTLAB(TLAB_SIZE);
208             ASSERT_TRUE(tlab != nullptr) << ", seed:" << seed_;
209         }
210         TLAB *tlab = allocator.CreateNewTLAB(TLAB_SIZE);
211         ASSERT_TRUE(tlab == nullptr) << ", seed:" << seed_;
212     }
213     allocator.Reset();
214     {
215         for (size_t i = 0; i < TLAB_COUNT - 1; i++) {
216             TLAB *tlab = allocator.CreateNewTLAB(TLAB_SIZE);
217             ASSERT_TRUE(tlab != nullptr) << ", seed:" << seed_;
218         }
219         TLAB *tlab = allocator.CreateNewTLAB(TLAB_SIZE);
220         ASSERT_TRUE(tlab == nullptr) << ", seed:" << seed_;
221     }
222 }
223 
224 }  // namespace ark::mem
225