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