1 /*
2 * Copyright (c) 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 "ecmascript/dfx/hprof/heap_profiler.h"
17 #include "ecmascript/dfx/hprof/heap_snapshot.h"
18 #include "ecmascript/tests/test_helper.h"
19
20 using namespace panda::ecmascript;
21 namespace panda::ecmascript {
22 class HeapSnapShotFriendTest {
23 public:
HeapSnapShotFriendTest(const EcmaVM * vm,StringHashMap * stringTable,DumpSnapShotOption dumpOption,bool traceAllocation,EntryIdMap * entryIdMap)24 explicit HeapSnapShotFriendTest(const EcmaVM *vm, StringHashMap *stringTable, DumpSnapShotOption dumpOption,
25 bool traceAllocation, EntryIdMap* entryIdMap)
26 : heapSnapshot(vm, stringTable, dumpOption, traceAllocation, entryIdMap) {}
27
GeneratePrivateStringNodeTest(size_t size)28 Node *GeneratePrivateStringNodeTest(size_t size)
29 {
30 return heapSnapshot.GeneratePrivateStringNode(size);
31 }
32
MoveNodeTest(uintptr_t address,TaggedObject * forwardAddress,size_t size)33 void MoveNodeTest(uintptr_t address, TaggedObject *forwardAddress, size_t size)
34 {
35 return heapSnapshot.MoveNode(address, forwardAddress, size);
36 }
37
InsertEntryTest(Node * node)38 void InsertEntryTest(Node *node)
39 {
40 heapSnapshot.entryMap_.InsertEntry(node);
41 }
42
GenerateNodeNameTest(TaggedObject * taggedObject)43 CString *GenerateNodeNameTest(TaggedObject *taggedObject)
44 {
45 return heapSnapshot.GenerateNodeName(taggedObject);
46 }
47
GenerateNodeTypeTest(TaggedObject * taggedObject)48 NodeType GenerateNodeTypeTest(TaggedObject *taggedObject)
49 {
50 return heapSnapshot.GenerateNodeType(taggedObject);
51 }
52
GetEntryMapTest()53 HeapEntryMap &GetEntryMapTest()
54 {
55 return heapSnapshot.entryMap_;
56 }
57
GetChunkTest()58 Chunk &GetChunkTest()
59 {
60 return heapSnapshot.chunk_;
61 }
62 private:
63 HeapSnapshot heapSnapshot;
64 };
65
66 class HeapProfilerFriendTest {
67 public:
HeapProfilerFriendTest(const EcmaVM * vm)68 explicit HeapProfilerFriendTest(const EcmaVM *vm) : heapProfiler(vm) {}
69
MakeHeapSnapshotTest(HeapProfiler::SampleType type,DumpSnapShotOption dumpOption)70 HeapSnapshot *MakeHeapSnapshotTest(HeapProfiler::SampleType type, DumpSnapShotOption dumpOption)
71 {
72 return heapProfiler.MakeHeapSnapshot(type, dumpOption);
73 }
74
GetEntryIdMapTest()75 EntryIdMap *GetEntryIdMapTest()
76 {
77 return heapProfiler.GetEntryIdMap();
78 }
79
GetEcmaStringTableTest()80 StringHashMap *GetEcmaStringTableTest()
81 {
82 return heapProfiler.GetEcmaStringTable();
83 }
84 private:
85 HeapProfiler heapProfiler;
86 };
87 }
88
89 namespace panda::test {
90 class HeapSnapShotTest : public testing::Test {
91 public:
SetUp()92 void SetUp() override
93 {
94 TestHelper::CreateEcmaVMWithScope(ecmaVm_, thread_, scope_);
95 ecmaVm_->SetEnableForceGC(false);
96 }
97
TearDown()98 void TearDown() override
99 {
100 TestHelper::DestroyEcmaVMWithScope(ecmaVm_, scope_);
101 }
102
103 EcmaVM *ecmaVm_ {nullptr};
104 EcmaHandleScope *scope_ {nullptr};
105 JSThread *thread_ {nullptr};
106 };
107
108 const std::set<CString> variableMap({
109 "string1", "string2", "string3", "string4",
110 "string5", "string6", "string7", "string8",
111 "string1string2", "string3string4", "string5string6", "string7string8",
112 "string1string2string3string4", "string5string6string7string8",
113 "string1string2string3string4string5string6string7string8"
114 });
115
HWTEST_F_L0(HeapSnapShotTest,TestGenerateStringNode)116 HWTEST_F_L0(HeapSnapShotTest, TestGenerateStringNode)
117 {
118 const std::string abcFileName = HPROF_TEST_ABC_FILES_DIR "heap_snapshot.abc";
119
120 std::string entryPoint = "heap_snapshot";
121 bool result = JSNApi::Execute(ecmaVm_, abcFileName, entryPoint);
122 ASSERT_TRUE(result);
123
124 // start MakeHeapSnapshot
125 DumpSnapShotOption dumpOption;
126 HeapProfilerFriendTest tester(ecmaVm_);
127 HeapSnapshot *snapshot = tester.MakeHeapSnapshotTest(HeapProfiler::SampleType::ONE_SHOT, dumpOption);
128 size_t totalSize = 0;
129 // global string also generate node
130 for (auto node : *snapshot->GetNodes()) {
131 if (variableMap.find(*node->GetName()) != variableMap.end()) {
132 totalSize += node->GetSelfSize();
133 }
134 }
135 // lineString: 24
136 // treeString: 32
137 // totalSize: 8 * 24 + 7 * 32
138 ASSERT_EQ(totalSize, 416);
139 }
140
HWTEST_F_L0(HeapSnapShotTest,TestGeneratePrivateStringNode)141 HWTEST_F_L0(HeapSnapShotTest, TestGeneratePrivateStringNode)
142 {
143 HeapProfilerFriendTest tester(ecmaVm_);
144 DumpSnapShotOption dumpOption;
145 dumpOption.isPrivate = true;
146 HeapSnapShotFriendTest heapSnapShotTest(ecmaVm_, tester.GetEcmaStringTableTest(),
147 dumpOption, false, tester.GetEntryIdMapTest());
148 Node *node = heapSnapShotTest.GeneratePrivateStringNodeTest(0);
149 // lineString: 24
150 ASSERT_EQ(node->GetSelfSize(), 24);
151 }
152
HWTEST_F_L0(HeapSnapShotTest,TestMoveNode)153 HWTEST_F_L0(HeapSnapShotTest, TestMoveNode)
154 {
155 HeapProfilerFriendTest tester(ecmaVm_);
156 DumpSnapShotOption dumpOption;
157 HeapSnapShotFriendTest heapSnapShotTest(ecmaVm_, tester.GetEcmaStringTableTest(),
158 dumpOption, false, tester.GetEntryIdMapTest());
159 ObjectFactory *factory = ecmaVm_->GetFactory();
160 // create tree string
161 JSHandle<EcmaString> strLeft = factory->NewFromUtf8("leftString");
162 JSHandle<EcmaString> strRight = factory->NewFromUtf8("rightString");
163 EcmaString *treeString = EcmaStringAccessor::Concat(ecmaVm_, strLeft, strRight);
164 uintptr_t address = 0;
165 Node *node = Node::NewNode(heapSnapShotTest.GetChunkTest(), 0, 0,
166 heapSnapShotTest.GenerateNodeNameTest(reinterpret_cast<TaggedObject *>(treeString)),
167 heapSnapShotTest.GenerateNodeTypeTest(reinterpret_cast<TaggedObject *>(treeString)),
168 0, 0, address);
169 heapSnapShotTest.InsertEntryTest(node);
170 heapSnapShotTest.MoveNodeTest(address, reinterpret_cast<TaggedObject *>(treeString), 0);
171 HeapEntryMap &heapEntryMap = heapSnapShotTest.GetEntryMapTest();
172 Node *movedNode = heapEntryMap.FindEntry(reinterpret_cast<JSTaggedType>(treeString));
173 // treeString: 32
174 ASSERT_EQ(movedNode->GetSelfSize(), 32);
175 }
176 }