1 /*
2 * Copyright (c) 2021 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 <cstdio>
17 #include <fstream>
18 #include <fcntl.h>
19
20 #include "ecmascript/dfx/hprof/heap_profiler_interface.h"
21 #include "ecmascript/dfx/hprof/heap_profiler.h"
22 #include "ecmascript/dfx/hprof/heap_snapshot_json_serializer.h"
23 #include "ecmascript/dfx/hprof/heap_snapshot.h"
24 #include "ecmascript/ecma_string.h"
25 #include "ecmascript/global_env.h"
26
27 #include "ecmascript/js_tagged_value.h"
28 #include "ecmascript/js_thread.h"
29 #include "ecmascript/mem/heap.h"
30 #include "ecmascript/tests/test_helper.h"
31 #include "ecmascript/dfx/hprof/file_stream.h"
32
33 using namespace panda::ecmascript;
34
35 namespace panda::ecmascript {
36 class TestProgress : public Progress {
37 public:
38 TestProgress() = default;
39 ~TestProgress() = default;
40
ReportProgress(int32_t done,int32_t total)41 void ReportProgress([[maybe_unused]] int32_t done, [[maybe_unused]] int32_t total) override {}
42 };
43
44 class TestStream : public Stream {
45 public:
46 TestStream() = default;
47 ~TestStream() = default;
48
EndOfStream()49 void EndOfStream() override {}
GetSize()50 int GetSize() override
51 {
52 static const int HEAP_PROFILER_CHUNK_SIZE = 100_KB;
53 return HEAP_PROFILER_CHUNK_SIZE;
54 }
WriteChunk(char * data,int32_t size)55 bool WriteChunk([[maybe_unused]] char *data, [[maybe_unused]] int32_t size) override
56 {
57 return true;
58 }
WriteBinBlock(char * data,int32_t size)59 bool WriteBinBlock(char *data, int32_t size) override
60 {
61 return WriteChunk(data, size);
62 }
Good()63 bool Good() override
64 {
65 return testStream_.good();
66 }
67
UpdateHeapStats(HeapStat * updateData,int32_t count)68 void UpdateHeapStats([[maybe_unused]] HeapStat* updateData, [[maybe_unused]] int32_t count) override
69 {
70 }
71
UpdateLastSeenObjectId(int32_t lastSeenObjectId,int64_t timeStampUs)72 void UpdateLastSeenObjectId([[maybe_unused]] int32_t lastSeenObjectId, [[maybe_unused]]int64_t timeStampUs) override
73 {
74 }
75
Clear()76 void Clear()
77 {
78 testStream_.clear(std::ios::badbit);
79 }
80
81 private:
82 std::fstream testStream_;
83 };
84 }
85
86 namespace panda::test {
87 class HeapTrackerTest : public testing::Test {
88 public:
SetUpTestCase()89 static void SetUpTestCase()
90 {
91 GTEST_LOG_(INFO) << "SetUpTestCase";
92 }
93
TearDownTestCase()94 static void TearDownTestCase()
95 {
96 GTEST_LOG_(INFO) << "TearDownCase";
97 }
98
SetUp()99 void SetUp() override
100 {
101 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
102 instance->SetEnableForceGC(false);
103 }
104
TearDown()105 void TearDown() override
106 {
107 TestHelper::DestroyEcmaVMWithScope(instance, scope);
108 }
109
110 EcmaVM *instance {nullptr};
111 EcmaHandleScope *scope {nullptr};
112 JSThread *thread {nullptr};
113 };
114
HWTEST_F_L0(HeapTrackerTest,GenDumpFileName_001)115 HWTEST_F_L0(HeapTrackerTest, GenDumpFileName_001)
116 {
117 [[maybe_unused]] EcmaHandleScope handleScope(thread);
118 HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
119
120 sleep(1);
121 int count = 100;
122 while (count-- > 0) {
123 instance->GetFactory()->NewJSAsyncFuncObject();
124 }
125 sleep(1);
126 count = 100;
127 while (count-- > 0) {
128 instance->GetFactory()->NewJSSymbol();
129 }
130 sleep(1);
131 count = 100;
132 while (count-- > 0) {
133 JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
134 JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
135 instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
136 }
137
138 TestStream stream;
139 stream.Clear();
140 EXPECT_TRUE(!stream.Good());
141 TestProgress testProgress;
142 DumpSnapShotOption dumpOption;
143 dumpOption.dumpFormat = DumpFormat::JSON;
144 dumpOption.isVmMode = true;
145 dumpOption.isPrivate = true;
146 dumpOption.captureNumericValue = false;
147 heapProfile->DumpHeapSnapshot(&stream, dumpOption, &testProgress);
148 HeapProfilerInterface::Destroy(instance);
149 }
150
HWTEST_F_L0(HeapTrackerTest,GenDumpFileName_002)151 HWTEST_F_L0(HeapTrackerTest, GenDumpFileName_002)
152 {
153 [[maybe_unused]] EcmaHandleScope handleScope(thread);
154 HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
155
156 sleep(1);
157 int count = 100;
158 while (count-- > 0) {
159 instance->GetFactory()->NewJSAsyncFuncObject();
160 }
161 sleep(1);
162 count = 100;
163 while (count-- > 0) {
164 instance->GetFactory()->NewJSSymbol();
165 }
166 sleep(1);
167 count = 100;
168 while (count-- > 0) {
169 JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
170 JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
171 instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
172 }
173
174 TestStream stream;
175 stream.Clear();
176 EXPECT_TRUE(!stream.Good());
177 TestProgress testProgress;
178 DumpSnapShotOption dumpOption;
179 dumpOption.dumpFormat = DumpFormat::BINARY;
180 dumpOption.isDumpOOM = true;
181 dumpOption.isVmMode = true;
182 dumpOption.isPrivate = true;
183 dumpOption.captureNumericValue = false;
184 heapProfile->DumpHeapSnapshot(&stream, dumpOption, &testProgress);
185 HeapProfilerInterface::Destroy(instance);
186 }
187
HWTEST_F_L0(HeapTrackerTest,GenDumpFileName_003)188 HWTEST_F_L0(HeapTrackerTest, GenDumpFileName_003)
189 {
190 [[maybe_unused]] EcmaHandleScope handleScope(thread);
191 HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
192
193 sleep(1);
194 int count = 100;
195 while (count-- > 0) {
196 instance->GetFactory()->NewJSAsyncFuncObject();
197 }
198 sleep(1);
199 count = 100;
200 while (count-- > 0) {
201 instance->GetFactory()->NewJSSymbol();
202 }
203 sleep(1);
204 count = 100;
205 while (count-- > 0) {
206 JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
207 JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
208 instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
209 }
210
211 TestStream stream;
212 stream.Clear();
213 EXPECT_TRUE(!stream.Good());
214 TestProgress testProgress;
215 DumpSnapShotOption dumpOption;
216 dumpOption.dumpFormat = DumpFormat::OTHER;
217 dumpOption.isVmMode = true;
218 dumpOption.isPrivate = true;
219 dumpOption.captureNumericValue = false;
220 heapProfile->DumpHeapSnapshot(&stream, dumpOption, &testProgress);
221 HeapProfilerInterface::Destroy(instance);
222 }
223
HWTEST_F_L0(HeapTrackerTest,GenDumpFileName_004)224 HWTEST_F_L0(HeapTrackerTest, GenDumpFileName_004)
225 {
226 [[maybe_unused]] EcmaHandleScope handleScope(thread);
227 HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
228
229 sleep(1);
230 int count = 100;
231 while (count-- > 0) {
232 instance->GetFactory()->NewJSAsyncFuncObject();
233 }
234 sleep(1);
235 count = 100;
236 while (count-- > 0) {
237 instance->GetFactory()->NewJSSymbol();
238 }
239 sleep(1);
240 count = 100;
241 while (count-- > 0) {
242 JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
243 JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
244 instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
245 }
246
247 TestStream stream;
248 stream.Clear();
249 EXPECT_TRUE(!stream.Good());
250 TestProgress testProgress;
251 DumpSnapShotOption dumpOption;
252 dumpOption.dumpFormat = static_cast<DumpFormat>(5); // 5 is exception.
253 dumpOption.isVmMode = true;
254 dumpOption.isPrivate = true;
255 dumpOption.captureNumericValue = false;
256 heapProfile->DumpHeapSnapshot(&stream, dumpOption, &testProgress);
257 HeapProfilerInterface::Destroy(instance);
258 }
259
HWTEST_F_L0(HeapTrackerTest,FileDescriptorStreamEndOfStream)260 HWTEST_F_L0(HeapTrackerTest, FileDescriptorStreamEndOfStream)
261 {
262 int fd = 3;
263 FileDescriptorStream fileStream(fd);
264 EXPECT_TRUE(fileStream.Good());
265 fileStream.EndOfStream();
266 }
267 } // namespace panda::test