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 "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 panda::mem::test {
28
29 class MemStatsGCTest : public testing::Test {
30 public:
SetupRuntime(std::string gc_type)31 void SetupRuntime(std::string gc_type)
32 {
33 RuntimeOptions options;
34 options.SetShouldLoadBootPandaFiles(false);
35 options.SetShouldInitializeIntrinsics(false);
36 options.SetUseTlabForAllocations(false);
37 options.SetGcType(gc_type);
38 options.SetRunGcInPlace(true);
39 bool success = Runtime::Create(options);
40 ASSERT_TRUE(success) << "Cannot create Runtime";
41 thread_ = panda::MTManagedThread::GetCurrent();
42 thread_->ManagedCodeBegin();
43 }
44
45 template <uint64_t object_count>
46 void MemStatsTest(uint64_t tries, size_t object_size);
47
TearDown()48 void TearDown() override
49 {
50 thread_->ManagedCodeEnd();
51 bool success = Runtime::Destroy();
52 ASSERT_TRUE(success) << "Cannot destroy Runtime";
53 }
54
55 panda::MTManagedThread *thread_;
56 };
57
58 template <uint64_t object_count>
MemStatsTest(uint64_t tries,size_t object_size)59 void MemStatsGCTest::MemStatsTest(uint64_t tries, size_t object_size)
60 {
61 ASSERT(object_size >= sizeof(coretypes::String));
62 mem::MemStatsType *stats = thread_->GetVM()->GetMemStats();
63 ASSERT_NE(stats, nullptr);
64
65 auto class_linker = Runtime::GetCurrent()->GetClassLinker();
66 ASSERT_NE(class_linker, nullptr);
67 auto allocator = class_linker->GetAllocator();
68
69 std::string simple_string;
70 for (size_t j = 0; j < object_size - sizeof(coretypes::String); j++) {
71 simple_string.append("x");
72 }
73 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
74 auto object_allocator = thread_->GetVM()->GetHeapManager()->GetObjectAllocator().AsObjectAllocator();
75 thread_->GetVM()->GetGC()->WaitForGCInManaged(GCTask(GCTaskCause::EXPLICIT_CAUSE));
76
77 size_t alloc_size = simple_string.size() + sizeof(coretypes::String);
78 size_t aligment_size = 0;
79 size_t aligment_diff = 0;
80 if (alloc_size < object_allocator->GetRegularObjectMaxSize()) {
81 aligment_size = 1UL << RunSlots<>::ConvertToPowerOfTwoUnsafe(alloc_size);
82 aligment_diff = aligment_size - alloc_size;
83 } else {
84 aligment_size = AlignUp(alloc_size, GetAlignmentInBytes(FREELIST_DEFAULT_ALIGNMENT));
85 aligment_diff = 2 * (aligment_size - alloc_size);
86 }
87
88 uint64_t allocated_objects = stats->GetTotalObjectsAllocated();
89 uint64_t allocated_bytes = stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT);
90 uint64_t freed_objects = stats->GetTotalObjectsFreed();
91 uint64_t freed_bytes = stats->GetFreed(SpaceType::SPACE_TYPE_OBJECT);
92 uint64_t diff_total = 0;
93 std::array<VMHandle<coretypes::String> *, object_count> handlers;
94 for (size_t i = 0; i < tries; i++) {
95 [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread_);
96 for (uint64_t j = 0; j < object_count; j++) {
97 coretypes::String *string_obj =
98 coretypes::String::CreateFromMUtf8(reinterpret_cast<const uint8_t *>(&simple_string[0]),
99 simple_string.length(), ctx, Runtime::GetCurrent()->GetPandaVM());
100 ASSERT_NE(string_obj, nullptr);
101 handlers[j] = allocator->New<VMHandle<coretypes::String>>(thread_, string_obj);
102 }
103 allocated_objects += object_count;
104 allocated_bytes += object_count * alloc_size;
105 diff_total += object_count * aligment_diff;
106 ASSERT_EQ(allocated_objects, stats->GetTotalObjectsAllocated());
107 ASSERT_LE(allocated_bytes, stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT));
108 ASSERT_GE(allocated_bytes + diff_total, stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT));
109
110 // run GC
111 thread_->GetVM()->GetGC()->WaitForGCInManaged(GCTask(GCTaskCause::EXPLICIT_CAUSE));
112 ASSERT_EQ(allocated_objects, stats->GetTotalObjectsAllocated());
113 ASSERT_LE(allocated_bytes, stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT));
114 ASSERT_GE(allocated_bytes + diff_total, stats->GetAllocated(SpaceType::SPACE_TYPE_OBJECT));
115 ASSERT_EQ(freed_objects, stats->GetTotalObjectsFreed());
116 ASSERT_LE(freed_bytes, stats->GetFreed(SpaceType::SPACE_TYPE_OBJECT));
117 ASSERT_GE(freed_bytes + diff_total, stats->GetFreed(SpaceType::SPACE_TYPE_OBJECT));
118
119 for (uint64_t j = 0; j < object_count; j++) {
120 allocator->Delete(handlers[j]);
121 }
122 freed_objects += object_count;
123 freed_bytes += object_count * alloc_size;
124 }
125 }
126
127 constexpr size_t OBJECTS_SIZE[] = {
128 32, // RunSlots: aligned & object_size = RunSlot size
129 72, // RunSlots: aligned & object_size != RunSlot size
130 129, // RunSlots: not aligned
131 512, // FreeList: aligned
132 1025 // FreeList: not aligned
133 };
134 constexpr size_t NUM_SIZES = sizeof(OBJECTS_SIZE) / sizeof(OBJECTS_SIZE[0]);
135
TEST_F(MemStatsGCTest,GenGcTest)136 TEST_F(MemStatsGCTest, GenGcTest)
137 {
138 constexpr uint64_t OBJECTS_COUNT = 80;
139 constexpr uint64_t TRIES = 4;
140
141 SetupRuntime("gen-gc");
142 for (size_t i = 0; i < NUM_SIZES; i++) {
143 MemStatsTest<OBJECTS_COUNT>(TRIES, OBJECTS_SIZE[i]);
144 }
145 }
146
TEST_F(MemStatsGCTest,StwGcTest)147 TEST_F(MemStatsGCTest, StwGcTest)
148 {
149 constexpr uint64_t OBJECTS_COUNT = 500;
150 constexpr uint64_t TRIES = 10;
151
152 SetupRuntime("stw");
153 for (size_t i = 0; i < NUM_SIZES; i++) {
154 MemStatsTest<OBJECTS_COUNT>(TRIES, OBJECTS_SIZE[i]);
155 }
156 }
157
158 } // namespace panda::mem::test
159