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 }
Good()59 bool Good() override
60 {
61 return testStream_.good();
62 }
63
UpdateHeapStats(HeapStat * updateData,int32_t count)64 void UpdateHeapStats([[maybe_unused]] HeapStat* updateData, [[maybe_unused]] int32_t count) override
65 {
66 }
67
UpdateLastSeenObjectId(int32_t lastSeenObjectId,int64_t timeStampUs)68 void UpdateLastSeenObjectId([[maybe_unused]] int32_t lastSeenObjectId, [[maybe_unused]]int64_t timeStampUs) override
69 {
70 }
71
Clear()72 void Clear()
73 {
74 testStream_.clear(std::ios::badbit);
75 }
76
77 private:
78 std::fstream testStream_;
79 };
80 }
81
82 namespace panda::test {
83 class HeapTrackerTest : public testing::Test {
84 public:
SetUpTestCase()85 static void SetUpTestCase()
86 {
87 GTEST_LOG_(INFO) << "SetUpTestCase";
88 }
89
TearDownTestCase()90 static void TearDownTestCase()
91 {
92 GTEST_LOG_(INFO) << "TearDownCase";
93 }
94
SetUp()95 void SetUp() override
96 {
97 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
98 instance->SetEnableForceGC(false);
99 }
100
TearDown()101 void TearDown() override
102 {
103 TestHelper::DestroyEcmaVMWithScope(instance, scope);
104 }
105
106 EcmaVM *instance {nullptr};
107 EcmaHandleScope *scope {nullptr};
108 JSThread *thread {nullptr};
109 };
110
HWTEST_F_L0(HeapTrackerTest,GenDumpFileName_001)111 HWTEST_F_L0(HeapTrackerTest, GenDumpFileName_001)
112 {
113 [[maybe_unused]] EcmaHandleScope handleScope(thread);
114 HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
115
116 sleep(1);
117 int count = 100;
118 while (count-- > 0) {
119 instance->GetFactory()->NewJSAsyncFuncObject();
120 }
121 sleep(1);
122 count = 100;
123 while (count-- > 0) {
124 instance->GetFactory()->NewJSSymbol();
125 }
126 sleep(1);
127 count = 100;
128 while (count-- > 0) {
129 JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
130 JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
131 instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
132 }
133
134 TestStream stream;
135 stream.Clear();
136 EXPECT_TRUE(!stream.Good());
137 TestProgress testProgress;
138 heapProfile->DumpHeapSnapshot(DumpFormat::JSON, &stream, &testProgress, true, true, false);
139 HeapProfilerInterface::Destroy(instance);
140 }
141
HWTEST_F_L0(HeapTrackerTest,GenDumpFileName_002)142 HWTEST_F_L0(HeapTrackerTest, GenDumpFileName_002)
143 {
144 [[maybe_unused]] EcmaHandleScope handleScope(thread);
145 HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
146
147 sleep(1);
148 int count = 100;
149 while (count-- > 0) {
150 instance->GetFactory()->NewJSAsyncFuncObject();
151 }
152 sleep(1);
153 count = 100;
154 while (count-- > 0) {
155 instance->GetFactory()->NewJSSymbol();
156 }
157 sleep(1);
158 count = 100;
159 while (count-- > 0) {
160 JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
161 JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
162 instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
163 }
164
165 TestStream stream;
166 stream.Clear();
167 EXPECT_TRUE(!stream.Good());
168 TestProgress testProgress;
169 heapProfile->DumpHeapSnapshot(DumpFormat::BINARY, &stream, &testProgress, true, true, false);
170 HeapProfilerInterface::Destroy(instance);
171 }
172
HWTEST_F_L0(HeapTrackerTest,GenDumpFileName_003)173 HWTEST_F_L0(HeapTrackerTest, GenDumpFileName_003)
174 {
175 [[maybe_unused]] EcmaHandleScope handleScope(thread);
176 HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
177
178 sleep(1);
179 int count = 100;
180 while (count-- > 0) {
181 instance->GetFactory()->NewJSAsyncFuncObject();
182 }
183 sleep(1);
184 count = 100;
185 while (count-- > 0) {
186 instance->GetFactory()->NewJSSymbol();
187 }
188 sleep(1);
189 count = 100;
190 while (count-- > 0) {
191 JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
192 JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
193 instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
194 }
195
196 TestStream stream;
197 stream.Clear();
198 EXPECT_TRUE(!stream.Good());
199 TestProgress testProgress;
200 heapProfile->DumpHeapSnapshot(DumpFormat::OTHER, &stream, &testProgress, true, true, false);
201 HeapProfilerInterface::Destroy(instance);
202 }
203
HWTEST_F_L0(HeapTrackerTest,GenDumpFileName_004)204 HWTEST_F_L0(HeapTrackerTest, GenDumpFileName_004)
205 {
206 [[maybe_unused]] EcmaHandleScope handleScope(thread);
207 HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
208
209 sleep(1);
210 int count = 100;
211 while (count-- > 0) {
212 instance->GetFactory()->NewJSAsyncFuncObject();
213 }
214 sleep(1);
215 count = 100;
216 while (count-- > 0) {
217 instance->GetFactory()->NewJSSymbol();
218 }
219 sleep(1);
220 count = 100;
221 while (count-- > 0) {
222 JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
223 JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
224 instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
225 }
226
227 TestStream stream;
228 stream.Clear();
229 EXPECT_TRUE(!stream.Good());
230 TestProgress testProgress;
231 DumpFormat dumFormat = static_cast<DumpFormat>(5);
232 heapProfile->DumpHeapSnapshot(dumFormat, &stream, &testProgress, true, true, false);
233 HeapProfilerInterface::Destroy(instance);
234 }
235
HWTEST_F_L0(HeapTrackerTest,FileDescriptorStreamEndOfStream)236 HWTEST_F_L0(HeapTrackerTest, FileDescriptorStreamEndOfStream)
237 {
238 int fd = 3;
239 FileDescriptorStream fileStream(fd);
240 EXPECT_TRUE(fileStream.Good());
241 fileStream.EndOfStream();
242 }
243 } // namespace panda::test