• 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 
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