• 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 #ifndef PANDA_RUNTIME_TESTS_PYGOTE_SPACE_ALLOCATOR_TEST_H_
16 #define PANDA_RUNTIME_TESTS_PYGOTE_SPACE_ALLOCATOR_TEST_H_
17 
18 #include <sys/mman.h>
19 #include <gtest/gtest.h>
20 
21 #include "libpandabase/os/mem.h"
22 #include "libpandabase/utils/logger.h"
23 #include "runtime/mem/runslots_allocator-inl.h"
24 #include "runtime/mem/pygote_space_allocator-inl.h"
25 #include "runtime/include/object_header.h"
26 #include "runtime/mem/refstorage/global_object_storage.h"
27 
28 namespace panda::mem {
29 
30 class PygoteSpaceAllocatorTest : public testing::Test {
31 public:
32     using PygoteAllocator = PygoteSpaceAllocator<ObjectAllocConfig>;
33 
PygoteSpaceAllocatorTest()34     PygoteSpaceAllocatorTest() {}
35 
~PygoteSpaceAllocatorTest()36     ~PygoteSpaceAllocatorTest() {}
37 
38 protected:
GetPygoteSpaceAllocator()39     PygoteAllocator *GetPygoteSpaceAllocator()
40     {
41         return thread_->GetVM()->GetHeapManager()->GetObjectAllocator().AsObjectAllocator()->GetPygoteSpaceAllocator();
42     }
43 
GetObjectClass()44     Class *GetObjectClass()
45     {
46         auto runtime = panda::Runtime::GetCurrent();
47         LanguageContext ctx = runtime->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
48         return runtime->GetClassLinker()->GetExtension(ctx)->GetClassRoot(ClassRoot::OBJECT);
49     }
50 
PygoteFork()51     void PygoteFork()
52     {
53         thread_->ManagedCodeEnd();
54         auto runtime = panda::Runtime::GetCurrent();
55         runtime->PreZygoteFork();
56         runtime->PostZygoteFork();
57         thread_->ManagedCodeBegin();
58     }
59 
TriggerGc()60     void TriggerGc()
61     {
62         auto gc = thread_->GetVM()->GetGC();
63         auto task = GCTask(GCTaskCause::EXPLICIT_CAUSE);
64         // trigger tenured gc
65         gc->WaitForGCInManaged(task);
66         gc->WaitForGCInManaged(task);
67         gc->WaitForGCInManaged(task);
68     }
69 
70     panda::MTManagedThread *thread_ {nullptr};
71     RuntimeOptions options_;
72 
73     void InitAllocTest();
74 
75     void ForkedAllocTest();
76 
77     void NonMovableLiveObjectAllocTest();
78 
79     void NonMovableUnliveObjectAllocTest();
80 
81     void MovableLiveObjectAllocTest();
82 
83     void MovableUnliveObjectAllocTest();
84 
85     void MuchObjectAllocTest();
86 };
87 
InitAllocTest()88 inline void PygoteSpaceAllocatorTest::InitAllocTest()
89 {
90     [[maybe_unused]] auto pygote_space_allocator = GetPygoteSpaceAllocator();
91     auto cls = GetObjectClass();
92 
93     auto non_movable_header = panda::ObjectHeader::CreateNonMovable(cls);
94     ASSERT_NE(non_movable_header, nullptr);
95     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
96     ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movable_header)));
97 
98     auto movable_header = panda::ObjectHeader::Create(cls);
99     ASSERT_NE(non_movable_header, nullptr);
100     ASSERT_FALSE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(movable_header)));
101 
102     pygote_space_allocator->Free(non_movable_header);
103     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
104     ASSERT_FALSE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movable_header)));
105 }
106 
ForkedAllocTest()107 inline void PygoteSpaceAllocatorTest::ForkedAllocTest()
108 {
109     [[maybe_unused]] auto pygote_space_allocator = GetPygoteSpaceAllocator();
110     auto cls = GetObjectClass();
111 
112     PygoteFork();
113 
114     auto non_movable_header = panda::ObjectHeader::CreateNonMovable(cls);
115     ASSERT_NE(non_movable_header, nullptr);
116     ASSERT_FALSE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
117 
118     auto movable_header = panda::ObjectHeader::Create(cls);
119     ASSERT_NE(movable_header, nullptr);
120     ASSERT_FALSE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(movable_header)));
121 }
122 
NonMovableLiveObjectAllocTest()123 inline void PygoteSpaceAllocatorTest::NonMovableLiveObjectAllocTest()
124 {
125     [[maybe_unused]] auto pygote_space_allocator = GetPygoteSpaceAllocator();
126     auto cls = GetObjectClass();
127     auto global_object_storage = thread_->GetVM()->GetGlobalObjectStorage();
128 
129     auto non_movable_header = panda::ObjectHeader::CreateNonMovable(cls);
130     ASSERT_NE(non_movable_header, nullptr);
131     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
132     ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movable_header)));
133     [[maybe_unused]] auto *ref =
134         global_object_storage->Add(non_movable_header, panda::mem::Reference::ObjectType::GLOBAL);
135 
136     PygoteFork();
137 
138     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
139     ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movable_header)));
140 
141     TriggerGc();
142 
143     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
144     ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movable_header)));
145 
146     pygote_space_allocator->Free(non_movable_header);
147     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
148     ASSERT_FALSE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movable_header)));
149 }
150 
NonMovableUnliveObjectAllocTest()151 inline void PygoteSpaceAllocatorTest::NonMovableUnliveObjectAllocTest()
152 {
153     [[maybe_unused]] auto pygote_space_allocator = GetPygoteSpaceAllocator();
154     auto cls = GetObjectClass();
155     auto global_object_storage = thread_->GetVM()->GetGlobalObjectStorage();
156 
157     auto non_movable_header = panda::ObjectHeader::CreateNonMovable(cls);
158     ASSERT_NE(non_movable_header, nullptr);
159     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
160     ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movable_header)));
161     [[maybe_unused]] auto *ref =
162         global_object_storage->Add(non_movable_header, panda::mem::Reference::ObjectType::GLOBAL);
163 
164     PygoteFork();
165 
166     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
167     ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movable_header)));
168     global_object_storage->Remove(ref);
169 
170     TriggerGc();
171 
172     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movable_header)));
173     ASSERT_FALSE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movable_header)));
174 }
175 
MovableLiveObjectAllocTest()176 inline void PygoteSpaceAllocatorTest::MovableLiveObjectAllocTest()
177 {
178     [[maybe_unused]] auto pygote_space_allocator = GetPygoteSpaceAllocator();
179     auto cls = GetObjectClass();
180     auto global_object_storage = thread_->GetVM()->GetGlobalObjectStorage();
181 
182     auto movable_header = panda::ObjectHeader::Create(cls);
183     ASSERT_NE(movable_header, nullptr);
184     ASSERT_FALSE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(movable_header)));
185     [[maybe_unused]] auto *ref = global_object_storage->Add(movable_header, panda::mem::Reference::ObjectType::GLOBAL);
186 
187     PygoteFork();
188 
189     auto obj = global_object_storage->Get(ref);
190     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(obj)));
191     ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(obj)));
192 
193     TriggerGc();
194 
195     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(obj)));
196     ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(obj)));
197 }
198 
MovableUnliveObjectAllocTest()199 inline void PygoteSpaceAllocatorTest::MovableUnliveObjectAllocTest()
200 {
201     [[maybe_unused]] auto pygote_space_allocator = GetPygoteSpaceAllocator();
202     auto cls = GetObjectClass();
203     auto global_object_storage = thread_->GetVM()->GetGlobalObjectStorage();
204 
205     auto movable_header = panda::ObjectHeader::Create(cls);
206     ASSERT_NE(movable_header, nullptr);
207     ASSERT_FALSE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(movable_header)));
208     [[maybe_unused]] auto *ref = global_object_storage->Add(movable_header, panda::mem::Reference::ObjectType::GLOBAL);
209 
210     PygoteFork();
211 
212     auto obj = global_object_storage->Get(ref);
213     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(obj)));
214     ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(obj)));
215     global_object_storage->Remove(ref);
216 
217     TriggerGc();
218 
219     ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(obj)));
220     ASSERT_FALSE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(obj)));
221 }
222 
MuchObjectAllocTest()223 inline void PygoteSpaceAllocatorTest::MuchObjectAllocTest()
224 {
225     [[maybe_unused]] auto pygote_space_allocator = GetPygoteSpaceAllocator();
226     auto cls = GetObjectClass();
227     auto global_object_storage = thread_->GetVM()->GetGlobalObjectStorage();
228 
229     static constexpr size_t obj_num = 1024;
230 
231     PandaVector<Reference *> movable_refs;
232     PandaVector<Reference *> non_movable_refs;
233     for (size_t i = 0; i < obj_num; i++) {
234         auto movable = panda::ObjectHeader::Create(cls);
235         movable_refs.push_back(global_object_storage->Add(movable, panda::mem::Reference::ObjectType::GLOBAL));
236         auto non_movable = panda::ObjectHeader::CreateNonMovable(cls);
237         non_movable_refs.push_back(global_object_storage->Add(non_movable, panda::mem::Reference::ObjectType::GLOBAL));
238     }
239 
240     PygoteFork();
241 
242     PandaVector<ObjectHeader *> movable_objs;
243     PandaVector<ObjectHeader *> non_movable_objs;
244     for (auto movalbe_ref : movable_refs) {
245         auto obj = global_object_storage->Get(movalbe_ref);
246         ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(obj)));
247         ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(obj)));
248         global_object_storage->Remove(movalbe_ref);
249         movable_objs.push_back(obj);
250     }
251 
252     for (auto non_movalbe_ref : non_movable_refs) {
253         auto obj = global_object_storage->Get(non_movalbe_ref);
254         ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(obj)));
255         ASSERT_TRUE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(obj)));
256         global_object_storage->Remove(non_movalbe_ref);
257         non_movable_objs.push_back(obj);
258     }
259 
260     TriggerGc();
261 
262     for (auto movalbe_obj : movable_objs) {
263         ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(movalbe_obj)));
264         ASSERT_FALSE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(movalbe_obj)));
265     }
266 
267     for (auto non_movalbe_obj : non_movable_objs) {
268         ASSERT_TRUE(pygote_space_allocator->ContainObject(static_cast<ObjectHeader *>(non_movalbe_obj)));
269         ASSERT_FALSE(pygote_space_allocator->IsLive(static_cast<ObjectHeader *>(non_movalbe_obj)));
270     }
271 }
272 
273 }  // namespace panda::mem
274 
275 #endif  // PANDA_RUNTIME_TESTS_PYGOTE_SPACE_ALLOCATOR_TEST_H_
276