• 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 <gtest/gtest.h>
17 #include <string>
18 
19 #include "runtime/include/runtime.h"
20 #include "runtime/include/runtime_options.h"
21 #include "runtime/include/panda_vm.h"
22 #include "runtime/include/class_linker.h"
23 #include "runtime/include/thread_scopes.h"
24 #include "runtime/mem/vm_handle.h"
25 #include "runtime/handle_scope-inl.h"
26 #include "runtime/include/coretypes/array.h"
27 #include "runtime/include/coretypes/string.h"
28 #include "runtime/mem/gc/card_table.h"
29 #include "runtime/mem/gc/g1/g1-allocator.h"
30 #include "runtime/mem/rem_set-inl.h"
31 #include "runtime/mem/region_space.h"
32 #include "runtime/include/gc_task.h"
33 #include "runtime/mem/gc/g1/g1-gc.h"
34 
35 #include "runtime/tests/test_utils.h"
36 #include "runtime/mem/object_helpers.h"
37 
38 namespace ark::mem {
39 
40 // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions,-warnings-as-errors)
41 class ExplicitGC : public testing::Test {
42 public:
43     ExplicitGC() = default;
44 
~ExplicitGC()45     ~ExplicitGC() override
46     {
47         [[maybe_unused]] bool success = Runtime::Destroy();
48         ASSERT(success);
49         Logger::Destroy();
50     }
51 
52     NO_COPY_SEMANTIC(ExplicitGC);
53     NO_MOVE_SEMANTIC(ExplicitGC);
54 
SetupRuntime(const std::string & gcType,bool isExplicitFull) const55     void SetupRuntime(const std::string &gcType, bool isExplicitFull) const
56     {
57         ark::Logger::ComponentMask componentMask;
58         componentMask.set(Logger::Component::GC);
59 
60         Logger::InitializeStdLogging(Logger::Level::INFO, componentMask);
61         EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::INFO, Logger::Component::GC));
62 
63         RuntimeOptions options;
64         options.SetLoadRuntimes({"core"});
65         options.SetGcType(gcType);
66         options.SetRunGcInPlace(true);
67         options.SetCompilerEnableJit(false);
68         options.SetGcWorkersCount(0);
69         options.SetGcTriggerType("debug-never");
70         options.SetShouldLoadBootPandaFiles(false);
71         options.SetShouldInitializeIntrinsics(false);
72         options.SetExplicitConcurrentGcEnabled(isExplicitFull);
73         [[maybe_unused]] bool success = Runtime::Create(options);
74         ASSERT(success);
75     }
76 };
77 
TEST_F(ExplicitGC,TestG1GCPhases)78 TEST_F(ExplicitGC, TestG1GCPhases)
79 {
80     SetupRuntime("g1-gc", true);
81 
82     uint32_t garbageRate = Runtime::GetOptions().GetG1RegionGarbageRateThreshold();
83     // NOLINTNEXTLINE(readability-magic-numbers,-warnings-as-errors)
84     size_t bigLen = garbageRate * DEFAULT_REGION_SIZE / 100U + sizeof(coretypes::String);
85 
86     Runtime *runtime = Runtime::GetCurrent();
87     GC *gc = runtime->GetPandaVM()->GetGC();
88     ObjectAllocator allocator;
89     MTManagedThread *thread = MTManagedThread::GetCurrent();
90     ScopedManagedCodeThread s(thread);
91     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
92 
93     VMHandle<coretypes::Array> holder;
94     std::string expectedLog;
95     std::string log;
96 
97     holder = VMHandle<coretypes::Array>(thread, allocator.AllocArray(2U, ClassRoot::ARRAY_STRING, false));
98     holder->Set(0, allocator.AllocString(bigLen));
99     holder->Set(1, allocator.AllocString(bigLen));
100 
101     {
102         ScopedNativeCodeThread sn(thread);
103         testing::internal::CaptureStderr();
104         GCTask task(GCTaskCause::EXPLICIT_CAUSE);
105         task.Run(*gc);  // run young
106         expectedLog = "[YOUNG (Explicit)]";
107         log = testing::internal::GetCapturedStderr();
108         ASSERT_NE(log.find(expectedLog), std::string::npos) << "Expected:\n" << expectedLog << "\nLog:\n" << log;
109     }
110 
111     ASSERT_TRUE(ObjectToRegion(holder->Get<ObjectHeader *>(1))->HasFlag(RegionFlag::IS_OLD));
112     ASSERT_TRUE(ObjectToRegion(holder->Get<ObjectHeader *>(0))->HasFlag(RegionFlag::IS_OLD));
113 
114     holder->Set(0, static_cast<ObjectHeader *>(nullptr));
115     holder->Set(1, static_cast<ObjectHeader *>(nullptr));
116 
117     {
118         ScopedNativeCodeThread sn(thread);
119         testing::internal::CaptureStderr();
120         GCTask task(GCTaskCause::HEAP_USAGE_THRESHOLD_CAUSE);
121         task.Run(*gc);  // prepare for mix
122         expectedLog = "[TENURED (Threshold)]";
123         log = testing::internal::GetCapturedStderr();
124         ASSERT_NE(log.find(expectedLog), std::string::npos) << "Expected:\n" << expectedLog << "\nLog:\n" << log;
125     }
126 
127     {
128         ScopedNativeCodeThread sn(thread);
129         testing::internal::CaptureStderr();
130         GCTask task(GCTaskCause::EXPLICIT_CAUSE);
131         task.Run(*gc);  // run mixed gc
132         expectedLog = "[MIXED (Explicit)]";
133         log = testing::internal::GetCapturedStderr();
134         ASSERT_NE(log.find(expectedLog), std::string::npos) << "Expected:\n" << expectedLog << "\nLog:\n" << log;
135     }
136 }
137 
TEST_F(ExplicitGC,TestGenGCPhases)138 TEST_F(ExplicitGC, TestGenGCPhases)
139 {
140     SetupRuntime("gen-gc", true);
141 
142     Runtime *runtime = Runtime::GetCurrent();
143     GC *gc = runtime->GetPandaVM()->GetGC();
144     MTManagedThread *thread = MTManagedThread::GetCurrent();
145     ScopedManagedCodeThread s(thread);
146     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
147     ObjectAllocator objectAllocator;
148 
149     std::string expectedLog;
150     std::string log;
151 
152     VMHandle<ObjectHeader> obj;
153     obj = VMHandle<ObjectHeader>(thread, objectAllocator.AllocObjectInYoung());
154 
155     {
156         ScopedNativeCodeThread sn(thread);
157         testing::internal::CaptureStderr();
158         GCTask task(GCTaskCause::EXPLICIT_CAUSE);
159         task.Run(*gc);  // run young
160         expectedLog = "[YOUNG (Explicit)]";
161         log = testing::internal::GetCapturedStderr();
162         ASSERT_NE(log.find(expectedLog), std::string::npos) << "Expected:\n" << expectedLog << "\nLog:\n" << log;
163     }
164 }
165 
TEST_F(ExplicitGC,TestG1GCWithFullExplicit)166 TEST_F(ExplicitGC, TestG1GCWithFullExplicit)
167 {
168     SetupRuntime("g1-gc", false);
169 
170     Runtime *runtime = Runtime::GetCurrent();
171     GC *gc = runtime->GetPandaVM()->GetGC();
172     MTManagedThread *thread = MTManagedThread::GetCurrent();
173     ScopedManagedCodeThread s(thread);
174     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
175     ObjectAllocator objectAllocator;
176 
177     std::string expectedLog;
178     std::string log;
179 
180     VMHandle<ObjectHeader> obj;
181     obj = VMHandle<ObjectHeader>(thread, objectAllocator.AllocObjectInYoung());
182 
183     {
184         ScopedNativeCodeThread sn(thread);
185         testing::internal::CaptureStderr();
186         GCTask task(GCTaskCause::EXPLICIT_CAUSE);
187         task.Run(*gc);  // run full
188         expectedLog = "[FULL (Explicit)]";
189         log = testing::internal::GetCapturedStderr();
190         ASSERT_NE(log.find(expectedLog), std::string::npos) << "Expected:\n" << expectedLog << "\nLog:\n" << log;
191     }
192 }
193 
TEST_F(ExplicitGC,TestGenGCWithFullExplicit)194 TEST_F(ExplicitGC, TestGenGCWithFullExplicit)
195 {
196     SetupRuntime("gen-gc", false);
197 
198     Runtime *runtime = Runtime::GetCurrent();
199     GC *gc = runtime->GetPandaVM()->GetGC();
200     MTManagedThread *thread = MTManagedThread::GetCurrent();
201     ScopedManagedCodeThread s(thread);
202     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
203     ObjectAllocator objectAllocator;
204 
205     std::string expectedLog;
206     std::string log;
207 
208     VMHandle<ObjectHeader> obj;
209     obj = VMHandle<ObjectHeader>(thread, objectAllocator.AllocObjectInYoung());
210 
211     {
212         ScopedNativeCodeThread sn(thread);
213         testing::internal::CaptureStderr();
214         GCTask task(GCTaskCause::EXPLICIT_CAUSE);
215         task.Run(*gc);  // run full
216         expectedLog = "[FULL (Explicit)]";
217         log = testing::internal::GetCapturedStderr();
218         ASSERT_NE(log.find(expectedLog), std::string::npos) << "Expected:\n" << expectedLog << "\nLog:\n" << log;
219     }
220 }
221 
222 }  // namespace ark::mem
223