• 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 
19 #include "ecmascript/accessor_data.h"
20 #include "ecmascript/jspandafile/program_object-inl.h"
21 #include "ecmascript/ecma_module.h"
22 #include "ecmascript/ecma_vm.h"
23 #include "ecmascript/global_dictionary-inl.h"
24 #include "ecmascript/global_env.h"
25 #include "ecmascript/hprof/heap_profiler.h"
26 #include "ecmascript/hprof/heap_profiler_interface.h"
27 #include "ecmascript/hprof/heap_snapshot.h"
28 #include "ecmascript/hprof/heap_snapshot_json_serializer.h"
29 #include "ecmascript/hprof/string_hashmap.h"
30 #include "ecmascript/ic/ic_handler.h"
31 #include "ecmascript/ic/property_box.h"
32 #include "ecmascript/ic/proto_change_details.h"
33 #include "ecmascript/jobs/micro_job_queue.h"
34 #include "ecmascript/jobs/pending_job.h"
35 #include "ecmascript/js_arguments.h"
36 #include "ecmascript/js_array.h"
37 #include "ecmascript/js_array_iterator.h"
38 #include "ecmascript/js_arraybuffer.h"
39 #include "ecmascript/js_async_function.h"
40 #include "ecmascript/js_collator.h"
41 #include "ecmascript/js_dataview.h"
42 #include "ecmascript/js_date.h"
43 #include "ecmascript/js_date_time_format.h"
44 #include "ecmascript/js_for_in_iterator.h"
45 #include "ecmascript/js_function.h"
46 #include "ecmascript/js_generator_object.h"
47 #include "ecmascript/js_global_object.h"
48 #include "ecmascript/js_handle.h"
49 #include "ecmascript/js_intl.h"
50 #include "ecmascript/js_locale.h"
51 #include "ecmascript/js_map.h"
52 #include "ecmascript/js_map_iterator.h"
53 #include "ecmascript/js_number_format.h"
54 #include "ecmascript/js_object-inl.h"
55 #include "ecmascript/js_plural_rules.h"
56 #include "ecmascript/js_primitive_ref.h"
57 #include "ecmascript/js_promise.h"
58 #include "ecmascript/js_realm.h"
59 #include "ecmascript/js_regexp.h"
60 #include "ecmascript/js_relative_time_format.h"
61 #include "ecmascript/js_set.h"
62 #include "ecmascript/js_set_iterator.h"
63 #include "ecmascript/js_string_iterator.h"
64 #include "ecmascript/js_tagged_number.h"
65 #include "ecmascript/js_tagged_value-inl.h"
66 #include "ecmascript/js_thread.h"
67 #include "ecmascript/js_typed_array.h"
68 #include "ecmascript/js_weak_container.h"
69 #include "ecmascript/layout_info-inl.h"
70 #include "ecmascript/lexical_env.h"
71 #include "ecmascript/linked_hash_table-inl.h"
72 #include "ecmascript/mem/assert_scope-inl.h"
73 #include "ecmascript/mem/c_containers.h"
74 #include "ecmascript/mem/machine_code.h"
75 #include "ecmascript/object_factory.h"
76 #include "ecmascript/tagged_array.h"
77 #include "ecmascript/tagged_dictionary.h"
78 #include "ecmascript/template_map.h"
79 #include "ecmascript/tests/test_helper.h"
80 #include "ecmascript/transitions_dictionary.h"
81 
82 using namespace panda::ecmascript;
83 using namespace panda::ecmascript::base;
84 
85 namespace panda::test {
86 using MicroJobQueue = panda::ecmascript::job::MicroJobQueue;
87 using PendingJob = panda::ecmascript::job::PendingJob;
88 class HProfTest : public testing::Test {
89 public:
SetUpTestCase()90     static void SetUpTestCase()
91     {
92         GTEST_LOG_(INFO) << "SetUpTestCase";
93     }
94 
TearDownTestCase()95     static void TearDownTestCase()
96     {
97         GTEST_LOG_(INFO) << "TearDownCase";
98     }
99 
SetUp()100     void SetUp() override
101     {
102         TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
103     }
104 
TearDown()105     void TearDown() override
106     {
107         TestHelper::DestroyEcmaVMWithScope(instance, scope);
108     }
109     PandaVM *instance {nullptr};
110     EcmaHandleScope *scope {nullptr};
111     JSThread *thread {nullptr};
112 };
113 
114 class HProfTestHelper {
115 public:
HProfTestHelper(const CString & aFilePath)116     explicit HProfTestHelper(const CString &aFilePath) : filePath(aFilePath) {}
117     ~HProfTestHelper() = default;
118 
IsFileExist()119     bool IsFileExist()
120     {
121         bool exist = false;
122         exist = SafeOpenFile();
123         SafeCloseFile();
124         return exist;
125     }
126 
RemoveExistingFile()127     bool RemoveExistingFile()
128     {
129         int code = 0;
130         if (IsFileExist()) {
131             code = std::remove(filePath.c_str());
132         }
133         return code == 0 ? true : false;
134     }
135 
GenerateHeapDump(JSThread * thread)136     bool GenerateHeapDump(JSThread *thread)
137     {
138         int retry = 2;
139         RemoveExistingFile();
140         HeapProfilerInterface::DumpHeapSnapShot(thread, DumpFormat::JSON, filePath);
141         while (!IsFileExist() && retry > 0) {
142             retry--;
143             HeapProfilerInterface::DumpHeapSnapShot(thread, DumpFormat::JSON, filePath);
144         }
145         return IsFileExist();
146     }
147 
ContrastJSONLineHeader(int lineId,CString lineHeader)148     bool ContrastJSONLineHeader(int lineId, CString lineHeader)
149     {
150         bool allSame = false;
151         if (!SafeOpenFile()) {  // No JSON File
152             allSame = false;
153             SafeCloseFile();
154         } else {
155             CString line;
156             int i = 1;
157             while (getline(inputFile, line)) {
158                 if (i == lineId && line.find(lineHeader) != line.npos) {
159                     allSame = true;
160                     break;
161                 }
162                 i++;
163             }
164             SafeCloseFile();
165         }
166 
167         return allSame;
168     }
169 
ContrastJSONSectionPayload(CString dataLable,int fieldNum)170     bool ContrastJSONSectionPayload(CString dataLable, int fieldNum)
171     {
172         if (!SafeOpenFile()) {  // No JSON File
173             SafeCloseFile();
174             return false;
175         } else {
176             CString line;
177             int i = 1;
178             while (getline(inputFile, line)) {
179                 if (i > 10 && line.find(dataLable) != line.npos) {  // 10 : Hit the line
180                     CString::size_type pos = 0;
181                     int loop = 0;
182                     while ((pos = line.find(",", pos)) != line.npos) {
183                         pos++;
184                         loop++;  // "," count
185                     }
186                     SafeCloseFile();
187                     return loop == fieldNum - 1;
188                     break;
189                 }
190                 i++;  // Search the Next Line
191             }
192             SafeCloseFile();
193         }
194         return false;  // Lost the Line
195     }
196 
ContrastJSONClousure()197     bool ContrastJSONClousure()
198     {
199         if (!SafeOpenFile()) {  // No JSON File
200             SafeCloseFile();
201             return false;
202         }
203         CString lineBk;  // The Last Line
204         CString line;
205         while (getline(inputFile, line)) {
206             lineBk = line;
207         }
208         SafeCloseFile();
209         return lineBk.compare("}") == 0;
210     }
211 
ExtractCountFromMeta(CString typeLable)212     int ExtractCountFromMeta(CString typeLable)
213     {
214         if (!SafeOpenFile()) {  // No JSON File
215             SafeCloseFile();
216             return -1;
217         } else {
218             CString line;
219             int i = 1;
220             while (getline(inputFile, line)) {
221                 int length = line.length() - typeLable.length() - 1;
222                 if (line.find(typeLable) != line.npos) {  // Get
223                     if (line.find(",") == line.npos) {    // "trace_function_count" end without ","
224                         length = line.length() - typeLable.length();
225                     }
226                     line = line.substr(typeLable.length(), length);
227                     SafeCloseFile();
228                     return std::stoi(line.c_str());
229                 }
230                 i++;
231             }
232             SafeCloseFile();
233         }
234         return -1;
235     }
236 
ExtractCountFromPayload(CString dataLabel)237     int ExtractCountFromPayload(CString dataLabel)
238     {
239         if (!SafeOpenFile()) {  // No JSON File
240             SafeCloseFile();
241             return -1;
242         } else {
243             CString line;
244             bool hit = false;
245             int loop = 0;
246             while (getline(inputFile, line)) {
247                 if (!hit && line.find(dataLabel) != line.npos) {  // Get
248                     loop += 1;                                    // First Line
249                     hit = true;
250                     if (line.find("[]") != line.npos) {  // Empty
251                         loop = 0;
252                         SafeCloseFile();
253                         return loop;
254                     } else {
255                         continue;
256                     }
257                 }
258                 if (hit) {
259                     if (line.find("],") != line.npos) {  // Reach End
260                         loop += 1;                       // End Line
261                         SafeCloseFile();
262                         return loop;
263                     } else {
264                         loop++;
265                         continue;
266                     }
267                 }
268             }
269             SafeCloseFile();
270         }
271         return -1;
272     }
273 
274 private:
SafeOpenFile()275     bool SafeOpenFile()
276     {
277         inputFile.clear();
278         inputFile.open(filePath.c_str(), std::ios::in);
279         int retry = 2;
280         while (!inputFile.good() && retry > 0) {
281             inputFile.open(filePath.c_str(), std::ios::in);
282             retry--;
283         }
284         return inputFile.good();
285     }
286 
SafeCloseFile()287     void SafeCloseFile()
288     {
289         inputFile.close();
290         inputFile.clear();  // Reset File status
291     }
292     CString filePath;
293     std::fstream inputFile {};
294 };
295 
HWTEST_F_L0(HProfTest,GenerateFileForManualCheck)296 HWTEST_F_L0(HProfTest, GenerateFileForManualCheck)
297 {
298     HProfTestHelper tester("hprof_json_test.heapsnapshot");
299     ASSERT_TRUE(tester.GenerateHeapDump(thread));
300 }
301 
HWTEST_F_L0(HProfTest,GenerateFile)302 HWTEST_F_L0(HProfTest, GenerateFile)
303 {
304     HProfTestHelper tester("GenerateFile.heapsnapshot");
305     ASSERT_TRUE(tester.GenerateHeapDump(thread));
306     ASSERT_TRUE(tester.RemoveExistingFile());
307 }
308 
HWTEST_F_L0(HProfTest,ParseJSONHeader)309 HWTEST_F_L0(HProfTest, ParseJSONHeader)
310 {
311     HProfTestHelper tester("ParseJSONHeader.heapsnapshot");
312     ASSERT_TRUE(tester.GenerateHeapDump(thread));
313     ASSERT_TRUE(tester.ContrastJSONLineHeader(1, "{\"snapshot\":"));
314     ASSERT_TRUE(tester.ContrastJSONLineHeader(2, "{\"meta\":"));
315     ASSERT_TRUE(tester.ContrastJSONLineHeader(3, "{\"node_fields\":"));
316     ASSERT_TRUE(tester.ContrastJSONLineHeader(4, "\"node_types\":"));
317     ASSERT_TRUE(tester.ContrastJSONLineHeader(5, "\"edge_fields\":"));
318     ASSERT_TRUE(tester.ContrastJSONLineHeader(6, "\"edge_types\":"));
319     ASSERT_TRUE(tester.ContrastJSONLineHeader(7, "\"trace_function_info_fields\":"));
320     ASSERT_TRUE(tester.ContrastJSONLineHeader(8, "\"trace_node_fields\":"));
321     ASSERT_TRUE(tester.ContrastJSONLineHeader(9, "\"sample_fields\":"));
322     ASSERT_TRUE(tester.ContrastJSONLineHeader(10, "\"location_fields\":"));
323     ASSERT_TRUE(tester.RemoveExistingFile());
324 }
325 
HWTEST_F_L0(HProfTest,ContrastTraceFunctionInfo)326 HWTEST_F_L0(HProfTest, ContrastTraceFunctionInfo)
327 {
328     HProfTestHelper tester("ContrastTraceFunctionInfo.heapsnapshot");
329     ASSERT_TRUE(tester.GenerateHeapDump(thread));
330     ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"trace_function_infos\":", 2));  // Empty
331     ASSERT_TRUE(tester.RemoveExistingFile());
332 }
333 
HWTEST_F_L0(HProfTest,ContrastTraceTree)334 HWTEST_F_L0(HProfTest, ContrastTraceTree)
335 {
336     HProfTestHelper tester("ContrastTraceTree.heapsnapshot");
337     ASSERT_TRUE(tester.GenerateHeapDump(thread));
338     ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"trace_tree\":", 2));  // Empty
339     ASSERT_TRUE(tester.RemoveExistingFile());
340 }
341 
HWTEST_F_L0(HProfTest,ContrastSamples)342 HWTEST_F_L0(HProfTest, ContrastSamples)
343 {
344     HProfTestHelper tester("ContrastSamples.heapsnapshot");
345     ASSERT_TRUE(tester.GenerateHeapDump(thread));
346     ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"samples\":", 2));  // Empty
347     ASSERT_TRUE(tester.RemoveExistingFile());
348 }
349 
HWTEST_F_L0(HProfTest,ContrastLocations)350 HWTEST_F_L0(HProfTest, ContrastLocations)
351 {
352     HProfTestHelper tester("ContrastLocations.heapsnapshot");
353     ASSERT_TRUE(tester.GenerateHeapDump(thread));
354     ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"locations\":", 2));  // Empty
355     ASSERT_TRUE(tester.RemoveExistingFile());
356 }
357 
HWTEST_F_L0(HProfTest,ContrastString)358 HWTEST_F_L0(HProfTest, ContrastString)
359 {
360     HProfTestHelper tester("ContrastString.heapsnapshot");
361     ASSERT_TRUE(tester.GenerateHeapDump(thread));
362     ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"strings\":[", 1 + 1));
363     ASSERT_TRUE(tester.RemoveExistingFile());
364 }
365 
HWTEST_F_L0(HProfTest,ContrastClosure)366 HWTEST_F_L0(HProfTest, ContrastClosure)
367 {
368     HProfTestHelper tester("ContrastClosure.heapsnapshot");
369     ASSERT_TRUE(tester.GenerateHeapDump(thread));
370     ASSERT_TRUE(tester.ContrastJSONClousure());
371     ASSERT_TRUE(tester.RemoveExistingFile());
372 }
373 
HWTEST_F_L0(HProfTest,ContrastEdgeCount)374 HWTEST_F_L0(HProfTest, ContrastEdgeCount)
375 {
376     HProfTestHelper tester("ContrastEdgeCount.heapsnapshot");
377     ASSERT_TRUE(tester.GenerateHeapDump(thread));
378     ASSERT_TRUE(tester.ExtractCountFromMeta("\"edge_count\":") == tester.ExtractCountFromPayload("\"edges\":["));
379     ASSERT_TRUE(tester.RemoveExistingFile());
380 }
381 
HWTEST_F_L0(HProfTest,ContrastTraceFunctionInfoCount)382 HWTEST_F_L0(HProfTest, ContrastTraceFunctionInfoCount)
383 {
384     HProfTestHelper tester("ContrastTraceFunctionInfoCount.heapsnapshot");
385     ASSERT_TRUE(tester.GenerateHeapDump(thread));
386     ASSERT_TRUE(tester.ExtractCountFromMeta("\"trace_function_count\":") ==
387                 tester.ExtractCountFromPayload("\"trace_function_infos\":"));
388     ASSERT_TRUE(tester.RemoveExistingFile());
389 }
390 }  // namespace panda::test
391