• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,HeapTracker)111 HWTEST_F_L0(HeapTrackerTest, HeapTracker)
112 {
113     [[maybe_unused]] EcmaHandleScope handleScope(thread);
114     HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
115     heapProfile->StartHeapTracking(50);
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     // Create file test.heaptimeline
135     std::string fileName = "test.heaptimeline";
136     fstream outputString(fileName, std::ios::out);
137     outputString.close();
138     outputString.clear();
139 
140     FileStream stream(fileName.c_str());
141     heapProfile->StopHeapTracking(&stream, nullptr);
142     HeapProfilerInterface::Destroy(instance);
143 
144     // Check
145     fstream inputStream(fileName, std::ios::in);
146     std::string line;
147     std::string emptySample = "\"samples\":";
148     std::string firstSample = "\"samples\":[0, ";
149     uint32_t emptySize = emptySample.size();
150     bool isFind = false;
151     while (getline(inputStream, line)) {
152         if (line.substr(0U, emptySize) == emptySample) {
153             ASSERT_TRUE(line.substr(0, firstSample.size()) == firstSample);
154             isFind = true;
155         }
156     }
157     ASSERT_TRUE(isFind);
158 
159     inputStream.close();
160     inputStream.clear();
161     std::remove(fileName.c_str());
162 }
163 
HWTEST_F_L0(HeapTrackerTest,HeapTrackerTraceAllocation)164 HWTEST_F_L0(HeapTrackerTest, HeapTrackerTraceAllocation)
165 {
166     [[maybe_unused]] EcmaHandleScope handleScope(thread);
167     HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
168     TestStream testStream;
169     heapProfile->StartHeapTracking(50, true, &testStream, true);
170     sleep(1);
171     int count = 100;
172     while (count-- > 0) {
173         instance->GetFactory()->NewJSAsyncFuncObject();
174     }
175     sleep(1);
176     count = 100;
177     while (count-- > 0) {
178         instance->GetFactory()->NewJSSymbol();
179     }
180     sleep(1);
181     count = 100;
182     while (count-- > 0) {
183         JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
184         JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
185         instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
186     }
187 
188     // Create file test.heaptimeline
189     std::string fileName = "test.heaptimeline";
190     fstream outputString(fileName, std::ios::out);
191     outputString.close();
192     outputString.clear();
193 
194     FileStream stream(fileName.c_str());
195     TestProgress testProgress;
196     heapProfile->StopHeapTracking(&stream, &testProgress);
197     HeapProfilerInterface::Destroy(instance);
198 
199     // Check
200     fstream inputStream(fileName, std::ios::in);
201     std::string line;
202     std::string emptyTraceFunctionInfo = "\"trace_function_infos\":[";
203     std::string firstTraceFunctionInfo = "\"trace_function_infos\":[0,";
204     uint32_t emptyTraceFunctionInfoSize = emptyTraceFunctionInfo.size();
205     bool traceFunctionInfoIsFind = false;
206     while (getline(inputStream, line)) {
207         if (line.substr(0U, emptyTraceFunctionInfoSize) == emptyTraceFunctionInfo) {
208             ASSERT_TRUE(line.substr(0, firstTraceFunctionInfo.size()) == firstTraceFunctionInfo);
209             traceFunctionInfoIsFind = true;
210             break;
211         }
212     }
213     ASSERT_TRUE(traceFunctionInfoIsFind);
214 
215     inputStream.close();
216     inputStream.clear();
217     std::remove(fileName.c_str());
218 }
219 
HWTEST_F_L0(HeapTrackerTest,DumpHeapSnapshot)220 HWTEST_F_L0(HeapTrackerTest, DumpHeapSnapshot)
221 {
222     [[maybe_unused]] EcmaHandleScope handleScope(thread);
223     HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance);
224 
225     sleep(1);
226     int count = 100;
227     while (count-- > 0) {
228         instance->GetFactory()->NewJSAsyncFuncObject();
229     }
230     sleep(1);
231     count = 100;
232     while (count-- > 0) {
233         instance->GetFactory()->NewJSSymbol();
234     }
235     sleep(1);
236     count = 100;
237     while (count-- > 0) {
238         JSHandle<JSTaggedValue> undefined = instance->GetJSThread()->GlobalConstants()->GetHandledUndefined();
239         JSHandle<EcmaString> string = instance->GetFactory()->NewFromASCII("Hello World");
240         instance->GetFactory()->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
241     }
242 
243     // Create file test.heaptimeline
244     std::string fileName = "HeapTrackerTest1.heapsnapshot";
245     fstream outputString(fileName, std::ios::out);
246     outputString.close();
247     outputString.clear();
248 
249     FileStream stream(fileName.c_str());
250     TestProgress testProgress;
251     heapProfile->DumpHeapSnapshot(DumpFormat::JSON, &stream, &testProgress, true, true, false);
252     HeapProfilerInterface::Destroy(instance);
253 
254     // Check
255     fstream inputStream(fileName, std::ios::in);
256     std::string line;
257     std::string nodes = "\"nodes\":[";
258     std::string sample = "\"samples\":[]";
259     uint32_t nodesSize = nodes.size();
260     uint32_t sampleSize = sample.size();
261     bool isNodesFind = false;
262     bool isSampleFind = false;
263     while (getline(inputStream, line)) {
264         if (line.substr(0U, nodesSize) == nodes) {
265             isNodesFind = true;
266         }
267 
268         if (line.substr(0U, sampleSize) == sample) {
269             isSampleFind = true;
270         }
271     }
272     ASSERT_TRUE(isNodesFind);
273     ASSERT_TRUE(isSampleFind);
274 
275     inputStream.close();
276     inputStream.clear();
277     std::remove(fileName.c_str());
278 }
279 
HWTEST_F_L0(HeapTrackerTest,HeapSnapshotBuildUp)280 HWTEST_F_L0(HeapTrackerTest, HeapSnapshotBuildUp)
281 {
282     bool isVmMode = true;
283     bool isPrivate = false;
284     bool traceAllocation = false;
285     bool captureNumericValue = false;
286     HeapProfiler heapProfiler(instance);
287     HeapSnapshot heapSnapshot(instance, heapProfiler.GetEcmaStringTable(), isVmMode,
288                               isPrivate, captureNumericValue, traceAllocation,
289                               heapProfiler.GetEntryIdMap(), instance->GetChunk());
290     EXPECT_TRUE(heapSnapshot.BuildUp());
291 }
292 
HWTEST_F_L0(HeapTrackerTest,HeapSnapshotUpdateNode)293 HWTEST_F_L0(HeapTrackerTest, HeapSnapshotUpdateNode)
294 {
295     bool isVmMode = true;
296     bool isPrivate = false;
297     bool traceAllocation = false;
298     bool captureNumericValue = false;
299     HeapProfiler heapProfiler(instance);
300     HeapSnapshot heapSnapshot(instance, heapProfiler.GetEcmaStringTable(), isVmMode,
301                               isPrivate, captureNumericValue, traceAllocation,
302                               heapProfiler.GetEntryIdMap(), instance->GetChunk());
303     size_t beginNode = heapSnapshot.GetNodeCount();
304     heapSnapshot.UpdateNodes();
305     size_t endNode = heapSnapshot.GetNodeCount();
306     EXPECT_TRUE(beginNode != endNode);
307 }
308 }  // namespace panda::test
309