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 "gtest/gtest.h"
17 #include "runtime/include/runtime.h"
18 #include "runtime/include/mem/panda_containers.h"
19 #include "runtime/mem/runslots_allocator-inl.h"
20
21 namespace panda::mem::test {
22
23 class PandaContainersTest : public testing::Test {
24 public:
PandaContainersTest()25 PandaContainersTest()
26 {
27 RuntimeOptions options;
28 options.SetShouldLoadBootPandaFiles(false);
29 options.SetShouldInitializeIntrinsics(false);
30 options.SetLimitStandardAlloc(true);
31 options.SetInternalAllocatorType("panda_allocators");
32 Runtime::Create(options);
33 thread_ = panda::MTManagedThread::GetCurrent();
34 thread_->ManagedCodeBegin();
35 }
36
37 template <class T>
GetLocalObjects(T * allocator)38 size_t GetLocalObjects(T *allocator)
39 {
40 size_t num_objects = 0;
41 allocator->IterateOverObjects([&num_objects]([[maybe_unused]] ObjectHeader *obj) { num_objects++; });
42 return num_objects;
43 }
44
~PandaContainersTest()45 ~PandaContainersTest() override
46 {
47 thread_->ManagedCodeEnd();
48 Runtime::Destroy();
49 }
50
51 protected:
52 panda::MTManagedThread *thread_;
53 };
54
55 constexpr size_t MAX_SIZE = InternalAllocator<>::LocalSmallObjectAllocator::GetMaxSize();
TEST_F(PandaContainersTest,LocalTest)56 TEST_F(PandaContainersTest, LocalTest)
57 {
58 ASSERT(!Runtime::GetCurrent()->GetOptions().UseMallocForInternalAllocations());
59 auto local_allocator = panda::ManagedThread::GetCurrent()->GetLocalInternalAllocator();
60 ASSERT_EQ(GetLocalObjects(local_allocator), 0);
61 {
62 PandaVectorTL<uint8_t> vector_local;
63 vector_local.push_back(0);
64 // std::vector allocated memory block for it's elements via local_allocator
65 ASSERT_EQ(GetLocalObjects(local_allocator), 1);
66 for (size_t i = 1; i < MAX_SIZE; i++) {
67 vector_local.push_back(i % MAX_SIZE);
68 if (vector_local.capacity() <= MAX_SIZE) {
69 // Threre is 1 memory block for all elements
70 ASSERT_EQ(GetLocalObjects(local_allocator), 1);
71 } else {
72 // When vector size exceeds MAX_SIZE=256 bytes, we allocate it without thread-local runslots allocator
73 ASSERT_EQ(GetLocalObjects(local_allocator), 0);
74 }
75 }
76 // Simple check on data consistency
77 for (size_t i = 0; i < MAX_SIZE; i++) {
78 ASSERT_EQ(vector_local.at(i), i % MAX_SIZE);
79 }
80 vector_local.push_back(0);
81 // When vector size exceeds MAX_SIZE=256 bytes, we allocate it without thread-local runslots allocator
82 ASSERT_EQ(GetLocalObjects(local_allocator), 0);
83 }
84 ASSERT_EQ(GetLocalObjects(local_allocator), 0);
85 }
86
87 // Check that, when we use GLOBAL scope, there is no memory in thread-local allocator
TEST_F(PandaContainersTest,GlobalTest)88 TEST_F(PandaContainersTest, GlobalTest)
89 {
90 auto local_allocator = panda::ManagedThread::GetCurrent()->GetLocalInternalAllocator();
91 ASSERT_EQ(GetLocalObjects(local_allocator), 0);
92 {
93 PandaVector<uint8_t> vector_global;
94 vector_global.push_back(0);
95 ASSERT_EQ(GetLocalObjects(local_allocator), 0);
96 for (size_t i = 1; i < MAX_SIZE; i++) {
97 vector_global.push_back(i % MAX_SIZE);
98 ASSERT_EQ(GetLocalObjects(local_allocator), 0);
99 }
100
101 for (size_t i = 0; i < MAX_SIZE; i++) {
102 ASSERT_EQ(vector_global.at(i), i % MAX_SIZE);
103 }
104 vector_global.push_back(0);
105 ASSERT_EQ(GetLocalObjects(local_allocator), 0);
106 }
107 ASSERT_EQ(GetLocalObjects(local_allocator), 0);
108 }
109
110 } // namespace panda::mem::test
111