• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 "iostream"
18 #include "runtime/class_linker_context.h"
19 #include "runtime/include/runtime.h"
20 #include "runtime/include/panda_vm.h"
21 #include "runtime/mem/vm_handle.h"
22 #include "runtime/handle_base-inl.h"
23 #include "runtime/handle_scope-inl.h"
24 #include "runtime/mem/mem_stats.h"
25 #include "runtime/mem/mem_stats_default.h"
26 
27 namespace ark::mem::test {
28 
29 class MemStatsGCTest : public testing::Test {
30 public:
SetupRuntime(const std::string & gcType)31     void SetupRuntime(const std::string &gcType)
32     {
33         RuntimeOptions options;
34         options.SetShouldLoadBootPandaFiles(false);
35         options.SetShouldInitializeIntrinsics(false);
36         options.SetUseTlabForAllocations(false);
37         options.SetGcType(gcType);
38         options.SetRunGcInPlace(true);
39         options.SetExplicitConcurrentGcEnabled(false);
40         bool success = Runtime::Create(options);
41         ASSERT_TRUE(success) << "Cannot create Runtime";
42         thread_ = ark::MTManagedThread::GetCurrent();
43         thread_->ManagedCodeBegin();
44     }
45 
46     template <uint64_t OBJECT_COUNT>
47     void MemStatsTest(uint64_t tries, size_t objectSize);
48 
TearDown()49     void TearDown() override
50     {
51         thread_->ManagedCodeEnd();
52         bool success = Runtime::Destroy();
53         ASSERT_TRUE(success) << "Cannot destroy Runtime";
54     }
55 
56 private:
57     void SetAligment(size_t allocSize, size_t objectMaxSize, size_t &aligmentSize, size_t &aligmentDiff);
58     void SetAllocatedStats(uint64_t &allocatedObjects, uint64_t &allocatedBytes, size_t allocSize,
59                            uint64_t objectCount);
60 
61     ark::MTManagedThread *thread_ {};
62 };
63 
SetAligment(size_t allocSize,size_t objectMaxSize,size_t & aligmentSize,size_t & aligmentDiff)64 void MemStatsGCTest::SetAligment(size_t allocSize, size_t objectMaxSize, size_t &aligmentSize, size_t &aligmentDiff)
65 {
66     if (allocSize < objectMaxSize) {
67         aligmentSize = 1UL << RunSlots<>::ConvertToPowerOfTwoUnsafe(allocSize);
68         aligmentDiff = aligmentSize - allocSize;
69     } else {
70         aligmentSize = AlignUp(allocSize, GetAlignmentInBytes(FREELIST_DEFAULT_ALIGNMENT));
71         aligmentDiff = 2U * (aligmentSize - allocSize);
72     }
73 }
74 
SetAllocatedStats(uint64_t & allocatedObjects,uint64_t & allocatedBytes,size_t allocSize,uint64_t objectCount)75 void MemStatsGCTest::SetAllocatedStats(uint64_t &allocatedObjects, uint64_t &allocatedBytes, size_t allocSize,
76                                        uint64_t objectCount)
77 {
78     allocatedObjects += objectCount;
79     allocatedBytes += objectCount * allocSize;
80 }
81 
82 template <uint64_t OBJECT_COUNT>
MemStatsTest(uint64_t tries,size_t objectSize)83 void MemStatsGCTest::MemStatsTest(uint64_t tries, size_t objectSize)
84 {
85     ASSERT(objectSize >= sizeof(coretypes::String));
86     mem::MemStatsType *stats = thread_->GetVM()->GetMemStats();
87     ASSERT_NE(stats, nullptr);
88 
89     auto classLinker = Runtime::GetCurrent()->GetClassLinker();
90     ASSERT_NE(classLinker, nullptr);
91     auto allocator = classLinker->GetAllocator();
92 
93     std::string simpleString;
94     for (size_t j = 0; j < objectSize - sizeof(coretypes::String); j++) {
95         simpleString.append("x");
96     }
97     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
98     auto objectAllocator = thread_->GetVM()->GetGC()->GetObjectAllocator();
99     thread_->GetVM()->GetGC()->WaitForGCInManaged(GCTask(GCTaskCause::EXPLICIT_CAUSE));
100 
101     size_t allocSize = simpleString.size() + sizeof(coretypes::String);
102     size_t aligmentSize = 0;
103     size_t aligmentDiff = 0;
104     SetAligment(allocSize, objectAllocator->GetRegularObjectMaxSize(), aligmentSize, aligmentDiff);
105 
106     uint64_t allocatedObjects = stats->GetTotalObjectsAllocated();
107     uint64_t allocatedBytes = stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT);
108     uint64_t freedObjects = stats->GetTotalObjectsFreed();
109     uint64_t freedBytes = stats->GetFreed(SpaceType::SPACE_TYPE_OBJECT);
110     uint64_t diffTotal = 0;
111     std::array<VMHandle<coretypes::String> *, OBJECT_COUNT> handlers {};
112     for (size_t i = 0; i < tries; i++) {
113         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread_);
114         for (uint64_t j = 0; j < OBJECT_COUNT; j++) {
115             coretypes::String *stringObj =
116                 coretypes::String::CreateFromMUtf8(reinterpret_cast<const uint8_t *>(&simpleString[0]),
117                                                    simpleString.length(), ctx, Runtime::GetCurrent()->GetPandaVM());
118             ASSERT_NE(stringObj, nullptr);
119             handlers[j] = allocator->New<VMHandle<coretypes::String>>(thread_, stringObj);
120         }
121 
122         SetAllocatedStats(allocatedObjects, allocatedBytes, allocSize, OBJECT_COUNT);
123         diffTotal += OBJECT_COUNT * aligmentDiff;
124         ASSERT_EQ(allocatedObjects, stats->GetTotalObjectsAllocated());
125         ASSERT_LE(allocatedBytes, stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT));
126         ASSERT_GE(allocatedBytes + diffTotal, stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT));
127 
128         // run GC
129         thread_->GetVM()->GetGC()->WaitForGCInManaged(GCTask(GCTaskCause::EXPLICIT_CAUSE));
130         ASSERT_EQ(allocatedObjects, stats->GetTotalObjectsAllocated());
131         ASSERT_LE(allocatedBytes, stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT));
132         ASSERT_GE(allocatedBytes + diffTotal, stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT));
133         ASSERT_EQ(freedObjects, stats->GetTotalObjectsFreed());
134         ASSERT_LE(freedBytes, stats->GetFreed(SpaceType::SPACE_TYPE_OBJECT));
135         ASSERT_GE(freedBytes + diffTotal, stats->GetFreed(SpaceType::SPACE_TYPE_OBJECT));
136 
137         for (uint64_t j = 0; j < OBJECT_COUNT; j++) {
138             allocator->Delete(handlers[j]);
139         }
140         freedObjects += OBJECT_COUNT;
141         freedBytes += OBJECT_COUNT * allocSize;
142     }
143 }
144 
145 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
146 constexpr size_t OBJECTS_SIZE[] = {
147     32,   // RunSlots: aligned & object_size = RunSlot size
148     72,   // RunSlots: aligned & object_size != RunSlot size
149     129,  // RunSlots: not aligned
150     512,  // FreeList: aligned
151     1025  // FreeList: not aligned
152 };
153 
TEST_F(MemStatsGCTest,StwGcTest)154 TEST_F(MemStatsGCTest, StwGcTest)
155 {
156     constexpr uint64_t OBJECTS_COUNT = 500;
157     constexpr uint64_t TRIES = 10;
158 
159     SetupRuntime("stw");
160     for (size_t objectSize : OBJECTS_SIZE) {
161         MemStatsTest<OBJECTS_COUNT>(TRIES, objectSize);
162     }
163 }
164 
165 }  // namespace ark::mem::test
166