• 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 "mem/arena.h"
17 #include "mem/arena_allocator.h"
18 #include "mem/arena_allocator_stl_adapter.h"
19 #include "mem/pool_manager.h"
20 #include "mem/mem.h"
21 #include "mem/mem_config.h"
22 
23 #include "utils/arena_containers.h"
24 
25 #include "gtest/gtest.h"
26 #include "utils/logger.h"
27 
28 #include <string>
29 #include <array>
30 #include <limits>
31 #include <cstdint>
32 #include <ctime>
33 
34 namespace panda {
35 
36 constexpr const int64_t DEFAULT_SEED = 123456;
37 
38 class ArenaAllocatorTest : public testing::Test {
39 public:
ArenaAllocatorTest()40     ArenaAllocatorTest()
41     {
42 #ifdef PANDA_NIGHTLY_TEST_ON
43         seed_ = std::time(NULL);
44 #else
45         seed_ = DEFAULT_SEED;
46 #endif
47     }
48 
~ArenaAllocatorTest()49     ~ArenaAllocatorTest() {}
50 
51 protected:
52     static constexpr size_t MIN_LOG_ALIGN_SIZE_T = static_cast<size_t>(LOG_ALIGN_MIN);
53     static constexpr size_t MAX_LOG_ALIGN_SIZE_T = static_cast<size_t>(LOG_ALIGN_MAX);
54     static constexpr size_t ARRAY_SIZE = 1024;
55 
56     unsigned int seed_;
57 
58     template <class T>
MAX_VALUE()59     static constexpr T MAX_VALUE()
60     {
61         return std::numeric_limits<T>::max();
62     }
63 
IsAligned(const void * ptr,size_t alignment)64     static bool IsAligned(const void *ptr, size_t alignment)
65     {
66         return reinterpret_cast<uintptr_t>(ptr) % alignment == 0;
67     }
68 
SetUp()69     void SetUp() override
70     {
71         panda::mem::MemConfig::Initialize(0, 128_MB, 0, 0);
72         PoolManager::Initialize();
73     }
74 
75     template <class T>
AllocateWithAlignment() const76     void AllocateWithAlignment() const
77     {
78         ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
79 
80         for (Alignment align = LOG_ALIGN_MIN; align <= LOG_ALIGN_MAX;
81              align = static_cast<Alignment>(static_cast<size_t>(align) + 1)) {
82             std::array<T *, ARRAY_SIZE> arr;
83 
84             size_t mask = GetAlignmentInBytes(align) - 1;
85 
86             // Allocations
87             srand(seed_);
88             for (size_t i = 0; i < ARRAY_SIZE; ++i) {
89                 arr[i] = static_cast<T *>(aa.Alloc(sizeof(T), align));
90                 *arr[i] = rand() % MAX_VALUE<T>();
91             }
92 
93             // Allocations checking
94             srand(seed_);
95             for (size_t i = 0; i < ARRAY_SIZE; ++i) {
96                 ASSERT_NE(arr[i], nullptr) << "value of i: " << i << ", align: " << align;
97                 ASSERT_EQ(reinterpret_cast<size_t>(arr[i]) & mask, 0U) << "value of i: " << i << ", align: " << align;
98                 ASSERT_EQ(*arr[i], rand() % MAX_VALUE<T>()) << "value of i: " << i << ", align: " << align;
99             }
100         }
101     }
102 
103     template <class T>
AllocateWithDiffAlignment() const104     void AllocateWithDiffAlignment() const
105     {
106         ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
107 
108         std::array<T *, ARRAY_SIZE> arr;
109 
110         // Allocations
111         srand(seed_);
112         for (size_t i = 0; i < ARRAY_SIZE; ++i) {
113             auto random_value = rand();
114             size_t rand_align = MIN_LOG_ALIGN_SIZE_T + random_value % (MAX_LOG_ALIGN_SIZE_T - MIN_LOG_ALIGN_SIZE_T);
115             arr[i] = static_cast<T *>(aa.Alloc(sizeof(T), static_cast<Alignment>(rand_align)));
116             *arr[i] = random_value % MAX_VALUE<T>();
117         }
118 
119         // Allocations checking
120         srand(seed_);
121         for (size_t i = 0; i < ARRAY_SIZE; ++i) {
122             auto random_value = rand();
123             size_t align = MIN_LOG_ALIGN_SIZE_T + random_value % (MAX_LOG_ALIGN_SIZE_T - MIN_LOG_ALIGN_SIZE_T);
124             size_t mask = GetAlignmentInBytes(static_cast<Alignment>(align)) - 1;
125 
126             ASSERT_NE(arr[i], nullptr);
127             ASSERT_EQ(reinterpret_cast<size_t>(arr[i]) & mask, 0U) << "value of i: " << i << ", align: " << align;
128             ASSERT_EQ(*arr[i], random_value % MAX_VALUE<T>()) << "value of i: " << i;
129         }
130     }
131 
TearDown()132     void TearDown() override
133     {
134         PoolManager::Finalize();
135         panda::mem::MemConfig::Finalize();
136     }
137 };
138 
139 class ComplexClass final {
140 public:
ComplexClass()141     ComplexClass() : value_(0), str_value_("0") {}
ComplexClass(size_t value)142     explicit ComplexClass(size_t value) : value_(value), str_value_(std::to_string(value_)) {}
ComplexClass(size_t value,const std::string str_value)143     ComplexClass(size_t value, const std::string str_value) : value_(value), str_value_(str_value) {}
144     ComplexClass(const ComplexClass &other) = default;
145     ComplexClass(ComplexClass &&other) noexcept = default;
146 
147     ComplexClass &operator=(const ComplexClass &other) = default;
148     ComplexClass &operator=(ComplexClass &&other) = default;
149 
getValue() const150     size_t getValue() const noexcept
151     {
152         return value_;
153     }
getString() const154     std::string getString() const noexcept
155     {
156         return str_value_;
157     }
158 
setValue(size_t value)159     void setValue(size_t value)
160     {
161         value_ = value;
162         str_value_ = std::to_string(value);
163     }
164 
~ComplexClass()165     ~ComplexClass() {}
166 
167 private:
168     size_t value_;
169     std::string str_value_;
170 };
171 
172 HWTEST_F(ArenaAllocatorTest, AllocateTest, testing::ext::TestSize.Level0)
173 {
174     void *addr;
175     void *tmp;
176     ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
177 
178     addr = aa.Alloc(24);
179     ASSERT_NE(addr, nullptr);
180     ASSERT_TRUE(IsAligned(addr, GetAlignmentInBytes(DEFAULT_ARENA_ALIGNMENT)));
181     addr = aa.Alloc(4);
182     ASSERT_NE(addr, nullptr);
183     ASSERT_TRUE(IsAligned(addr, GetAlignmentInBytes(DEFAULT_ARENA_ALIGNMENT)));
184     tmp = aa.AllocArray<int>(1024);
185     // Make sure that we force to using dynamic pool if STACK pool enabled
186     for (int i = 0; i < 5; ++i) {
187         void *mem = nullptr;
188         mem = aa.Alloc(DEFAULT_ARENA_SIZE / 2);
189         ASSERT_NE(mem, nullptr);
190         *(static_cast<char *>(mem)) = 33;  // Try to catch segfault just in case something wrong
191     }
192     ASSERT_NE(tmp = aa.Alloc(DEFAULT_ARENA_SIZE - AlignUp(sizeof(Arena), GetAlignmentInBytes(DEFAULT_ARENA_ALIGNMENT))),
193               nullptr);
194     size_t maxAlignDrift = (DEFAULT_ALIGNMENT_IN_BYTES > alignof(Arena)) ?
195                            (DEFAULT_ALIGNMENT_IN_BYTES - alignof(Arena)) : 0;
196     ASSERT_EQ(tmp = aa.Alloc(DEFAULT_ARENA_SIZE + maxAlignDrift + 1), nullptr);
197 }
198 
199 HWTEST_F(ArenaAllocatorTest, AllocateVectorTest, testing::ext::TestSize.Level0)
200 {
201     constexpr size_t SIZE = 2048;
202     constexpr size_t SMALL_MAGIC_CONSTANT = 3;
203 
204     ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
205     ArenaVector<unsigned> vec(aa.Adapter());
206 
207     for (size_t i = 0; i < SIZE; ++i) {
208         vec.push_back(i * SMALL_MAGIC_CONSTANT);
209     }
210 
211     ASSERT_EQ(SIZE, vec.size());
212     vec.shrink_to_fit();
213     ASSERT_EQ(SIZE, vec.size());
214 
215     for (size_t i = 0; i < SIZE; ++i) {
216         ASSERT_EQ(i * SMALL_MAGIC_CONSTANT, vec[i]) << "value of i: " << i;
217     }
218 }
219 
220 HWTEST_F(ArenaAllocatorTest, AllocateVectorWithComplexTypeTest, testing::ext::TestSize.Level0)
221 {
222     constexpr size_t SIZE = 512;
223     constexpr size_t MAGIC_CONSTANT_1 = std::numeric_limits<size_t>::max() / (SIZE + 2);
224     srand(seed_);
225     size_t MAGIC_CONSTANT_2 = rand() % SIZE;
226 
227     ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
228     ArenaVector<ComplexClass> vec(aa.Adapter());
229 
230     // Allocate SIZE objects
231     for (size_t i = 0; i < SIZE; ++i) {
232         vec.emplace_back(i * MAGIC_CONSTANT_1 + MAGIC_CONSTANT_2, std::to_string(i));
233     }
234 
235     // Size checking
236     ASSERT_EQ(SIZE, vec.size());
237 
238     // Allocations checking
239     for (size_t i = 0; i < SIZE; ++i) {
240         ASSERT_EQ(vec[i].getValue(), i * MAGIC_CONSTANT_1 + MAGIC_CONSTANT_2) << "value of i: " << i;
241         ASSERT_EQ(vec[i].getString(), std::to_string(i)) << i;
242     }
243     ComplexClass *data_ptr = vec.data();
244     for (size_t i = 0; i < SIZE; ++i) {
245         ASSERT_EQ(data_ptr[i].getValue(), i * MAGIC_CONSTANT_1 + MAGIC_CONSTANT_2) << "value of i: " << i;
246         ASSERT_EQ(data_ptr[i].getString(), std::to_string(i)) << "value of i: " << i;
247     }
248 
249     // Resizing and new elements assignment
250     constexpr size_t SIZE_2 = SIZE << 1;
251     vec.assign(SIZE_2, ComplexClass(1, "1"));
252 
253     // Size checking
254     ASSERT_EQ(SIZE_2, vec.size());
255     vec.shrink_to_fit();
256     ASSERT_EQ(SIZE_2, vec.size());
257 
258     // Allocations and assignment checking
259     for (size_t i = 0; i < SIZE_2; ++i) {
260         ASSERT_EQ(vec[i].getValue(), 1U) << "value of i: " << i;
261         ASSERT_EQ(vec[i].getString(), "1") << "value of i: " << i;
262     }
263 
264     // Increasing size
265     constexpr size_t SIZE_4 = SIZE_2 << 1;
266     vec.resize(SIZE_4, ComplexClass());
267 
268     // Size checking
269     ASSERT_EQ(SIZE_4, vec.size());
270 
271     // Allocations checking
272     for (size_t i = 0; i < SIZE_4 / 2; ++i) {
273         ASSERT_EQ(vec[i].getValue(), 1U) << "value of i: " << i;
274         ASSERT_EQ(vec[i].getString(), "1") << "value of i: " << i;
275     }
276     for (size_t i = SIZE_4 / 2; i < SIZE_4; ++i) {
277         ASSERT_EQ(vec[i].getValue(), 0U) << "value of i: " << i;
278         ASSERT_EQ(vec[i].getString(), "0") << "value of i: " << i;
279     }
280 
281     // Decreasing size
282     vec.resize(SIZE);
283 
284     // Size checking
285     ASSERT_EQ(SIZE, vec.size());
286     vec.shrink_to_fit();
287     ASSERT_EQ(SIZE, vec.size());
288 
289     // Allocations checking
290     for (size_t i = 0; i < SIZE; ++i) {
291         ASSERT_EQ(vec[i].getValue(), 1U) << "value of i: " << i;
292         ASSERT_EQ(vec[i].getString(), "1") << "value of i: " << i;
293     }
294 }
295 
296 HWTEST_F(ArenaAllocatorTest, AllocateDequeWithComplexTypeTest, testing::ext::TestSize.Level0)
297 {
298     constexpr size_t SIZE = 2048;
299     constexpr size_t MAGIC_CONSTANT_1 = std::numeric_limits<size_t>::max() / (SIZE + 2);
300     srand(seed_);
301     size_t MAGIC_CONSTANT_2 = rand() % SIZE;
302 
303     size_t i;
304 
305     ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
306     ArenaDeque<ComplexClass> deq(aa.Adapter());
307 
308     // Allocate SIZE objects
309     for (size_t j = 0; j < SIZE; ++j) {
310         deq.emplace_back(j * MAGIC_CONSTANT_1 + MAGIC_CONSTANT_2, std::to_string(j));
311     }
312 
313     // Size checking
314     ASSERT_EQ(SIZE, deq.size());
315 
316     // Allocations checking
317     i = 0;
318     for (auto it = deq.cbegin(); it != deq.cend(); ++it, ++i) {
319         ASSERT_EQ(it->getValue(), i * MAGIC_CONSTANT_1 + MAGIC_CONSTANT_2) << "value of i: " << i;
320         ASSERT_EQ(it->getString(), std::to_string(i)) << "value of i: " << i;
321     }
322 
323     // Resizing and new elements assignment
324     constexpr size_t SIZE_2 = SIZE << 1;
325     deq.assign(SIZE_2, ComplexClass(1, "1"));
326 
327     // Size checking
328     ASSERT_EQ(SIZE_2, deq.size());
329     deq.shrink_to_fit();
330     ASSERT_EQ(SIZE_2, deq.size());
331 
332     // Allocations and assignment checking
333     i = SIZE_2 - 1;
334     for (auto it = deq.crbegin(); it != deq.crend(); ++it, --i) {
335         ASSERT_EQ(it->getValue(), 1U) << "value of i: " << i;
336         ASSERT_EQ(it->getString(), "1") << "value of i: " << i;
337     }
338 
339     // Increasing size
340     constexpr size_t SIZE_4 = SIZE_2 << 1;
341     deq.resize(SIZE_4, ComplexClass());
342 
343     // Size checking
344     ASSERT_EQ(SIZE_4, deq.size());
345 
346     // Allocations checking
347     auto it = deq.cbegin();
348     for (size_t j = 0; j < SIZE_4 / 2; ++j, ++it) {
349         ASSERT_EQ(it->getValue(), 1U) << "value of i: " << j;
350         ASSERT_EQ(it->getString(), "1") << "value of i: " << j;
351     }
352     for (size_t j = SIZE_4 / 2; j < SIZE_4; ++j, ++it) {
353         ASSERT_EQ(it->getValue(), 0U) << "value of i: " << j;
354         ASSERT_EQ(it->getString(), "0") << "value of i: " << j;
355     }
356 
357     // Decreasing size
358     deq.resize(SIZE);
359 
360     // Size checking
361     ASSERT_EQ(SIZE, deq.size());
362     deq.shrink_to_fit();
363     ASSERT_EQ(SIZE, deq.size());
364 
365     // Allocations checking
366     i = 0;
367     for (auto t_it = deq.cbegin(); t_it != deq.cend(); ++t_it, ++i) {
368         ASSERT_EQ(t_it->getValue(), 1U) << "value of i: " << i;
369         ASSERT_EQ(t_it->getString(), "1") << "value of i: " << i;
370     }
371 }
372 
373 HWTEST_F(ArenaAllocatorTest, LongRandomTest, testing::ext::TestSize.Level0)
374 {
375     constexpr size_t SIZE = 3250000;
376     constexpr size_t HALF_SIZE = SIZE >> 1;
377     constexpr size_t DOUBLE_SIZE = SIZE << 1;
378     constexpr uint32_t MAX_VAL = MAX_VALUE<uint32_t>();
379 
380     ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
381     ArenaDeque<uint32_t> st(aa.Adapter());
382     size_t i = 0;
383 
384     srand(seed_);
385 
386     // Allocations
387     for (size_t j = 0; j < SIZE; ++j) {
388         st.push_back(rand() % MAX_VAL);
389     }
390 
391     // Size checking
392     ASSERT_EQ(st.size(), SIZE);
393 
394     // Allocations checking
395     srand(seed_);
396     i = 0;
397     for (auto t_it = st.cbegin(); t_it != st.cend(); ++t_it, ++i) {
398         ASSERT_EQ(*t_it, rand() % MAX_VAL) << "value of i: " << i;
399     }
400 
401     // Decreasing size
402     st.resize(HALF_SIZE);
403 
404     // Size chcking
405     ASSERT_EQ(st.size(), HALF_SIZE);
406 
407     // Allocations checking
408     srand(seed_);
409     i = 0;
410     for (auto t_it = st.cbegin(); t_it != st.cend(); ++t_it, ++i) {
411         ASSERT_EQ(*t_it, rand() % MAX_VAL) << "value of i: " << i;
412     }
413 
414     // Increasing size
415     st.resize(DOUBLE_SIZE, rand() % MAX_VAL);
416 
417     // Allocations checking
418     srand(seed_);
419     auto it = st.cbegin();
420     for (i = 0; i < HALF_SIZE; ++it, ++i) {
421         ASSERT_EQ(*it, rand() % MAX_VAL) << "value of i: " << i;
422     }
423     for (uint32_t value = rand() % MAX_VAL; it != st.cend(); ++it, ++i) {
424         ASSERT_EQ(*it, value) << "value of i: " << i;
425     }
426 
427     // Change values
428     srand(seed_ >> 1);
429     for (auto t_it = st.begin(); t_it != st.end(); ++t_it) {
430         *t_it = rand() % MAX_VAL;
431     }
432 
433     // Changes checking
434     srand(seed_ >> 1);
435     i = 0;
436     for (auto t_it = st.cbegin(); t_it != st.cend(); ++t_it, ++i) {
437         ASSERT_EQ(*t_it, rand() % MAX_VAL) << "value of i: " << i;
438     }
439 }
440 
441 HWTEST_F(ArenaAllocatorTest, LogAlignmentSmallSizesTest, testing::ext::TestSize.Level0)
442 {
443     constexpr size_t MAX_SMALL_SIZE = 32;
444 
445     for (size_t size = 1; size < MAX_SMALL_SIZE; ++size) {
446         ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
447 
448         for (Alignment align = LOG_ALIGN_MIN; align <= LOG_ALIGN_MAX;
449              align = static_cast<Alignment>(static_cast<size_t>(align) + 1)) {
450             void *ptr = aa.Alloc(size, align);
451             size_t mask = GetAlignmentInBytes(align) - 1;
452 
453             ASSERT_NE(ptr, nullptr);
454             ASSERT_EQ(reinterpret_cast<size_t>(ptr) & mask, 0U)
455                 << "alignment: " << align << "addr: " << reinterpret_cast<size_t>(ptr);
456         }
457     }
458 }
459 
460 HWTEST_F(ArenaAllocatorTest, LogAlignmentBigSizeTest, testing::ext::TestSize.Level0)
461 {
462     constexpr size_t SIZE = 0.3_KB;
463     ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
464 
465     for (Alignment align = LOG_ALIGN_MIN; align <= LOG_ALIGN_MAX;
466          align = static_cast<Alignment>(static_cast<size_t>(align) + 1)) {
467         void *ptr = aa.Alloc(SIZE, align);
468         size_t mask = GetAlignmentInBytes(align) - 1;
469 
470         ASSERT_NE(ptr, nullptr);
471         ASSERT_EQ(reinterpret_cast<size_t>(ptr) & mask, 0U)
472             << "alignment: " << align << "addr: " << reinterpret_cast<size_t>(ptr);
473     }
474 }
475 
476 HWTEST_F(ArenaAllocatorTest, ArrayUINT16AlignmentTest, testing::ext::TestSize.Level0)
477 {
478     AllocateWithAlignment<uint16_t>();
479 }
480 
481 HWTEST_F(ArenaAllocatorTest, ArrayUINT32AlignmentTest, testing::ext::TestSize.Level0)
482 {
483     AllocateWithAlignment<uint32_t>();
484 }
485 
486 HWTEST_F(ArenaAllocatorTest, ArrayUINT64AlignmentTest, testing::ext::TestSize.Level0)
487 {
488     AllocateWithAlignment<uint64_t>();
489 }
490 
491 HWTEST_F(ArenaAllocatorTest, ArrayUINT16WithDiffAlignmentTest, testing::ext::TestSize.Level0)
492 {
493     AllocateWithDiffAlignment<uint16_t>();
494 }
495 
496 HWTEST_F(ArenaAllocatorTest, ArrayUINT32WithDiffAlignmentTest, testing::ext::TestSize.Level0)
497 {
498     AllocateWithDiffAlignment<uint32_t>();
499 }
500 
501 HWTEST_F(ArenaAllocatorTest, ArrayUINT64WithDiffAlignmentTest, testing::ext::TestSize.Level0)
502 {
503     AllocateWithDiffAlignment<uint64_t>();
504 }
505 
506 HWTEST_F(ArenaAllocatorTest, FunctionNewTest, testing::ext::TestSize.Level0)
507 {
508     ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
509     std::array<ComplexClass *, ARRAY_SIZE> arr;
510 
511     // Allocations
512     srand(seed_);
513     for (size_t i = 0; i < ARRAY_SIZE; ++i) {
514         arr[i] = aa.New<ComplexClass>(rand() % MAX_VALUE<size_t>());
515     }
516 
517     // Allocations checking
518     srand(seed_);
519     for (size_t i = 0; i < ARRAY_SIZE; ++i) {
520         ASSERT_NE(arr[i], nullptr);
521         size_t random_value = rand() % MAX_VALUE<size_t>();
522         ASSERT_EQ(arr[i]->getValue(), random_value);
523         ASSERT_EQ(arr[i]->getString(), std::to_string(random_value));
524     }
525 
526     // Change values
527     srand(seed_ >> 1);
528     for (size_t i = 0; i < ARRAY_SIZE; ++i) {
529         arr[i]->setValue(rand() % MAX_VALUE<size_t>());
530     }
531 
532     // Changes checking
533     srand(seed_ >> 1);
534     for (size_t i = 0; i < ARRAY_SIZE; ++i) {
535         size_t random_value = rand() % MAX_VALUE<size_t>();
536         ASSERT_EQ(arr[i]->getValue(), random_value);
537         ASSERT_EQ(arr[i]->getString(), std::to_string(random_value));
538     }
539 }
540 
541 HWTEST_F(ArenaAllocatorTest, ResizeWrapperTest, testing::ext::TestSize.Level0)
542 {
543     static constexpr size_t VECTOR_SIZE = 1000;
544     ArenaAllocator aa(SpaceType::SPACE_TYPE_INTERNAL);
545     size_t old_size = aa.GetAllocatedSize();
546     {
547         ArenaResizeWrapper<false> wrapper(&aa);
548         ArenaVector<size_t> vector(aa.Adapter());
549         for (size_t i = 0; i < VECTOR_SIZE; i++) {
550             vector.push_back(i);
551         }
552     }
553     ASSERT_TRUE(old_size == aa.GetAllocatedSize());
554 }
555 
556 }  // namespace panda
557