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