• 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 "ecmascript/hprof/heap_snapshot_json_serializer.h"
17 #include "ecmascript/mem/c_containers.h"
18 #include "ecmascript/hprof/heap_snapshot.h"
19 #include "ecmascript/hprof/string_hashmap.h"
20 
21 namespace panda::ecmascript {
Serialize(HeapSnapShot * snapShot,const CString & fileName)22 bool HeapSnapShotJSONSerializer::Serialize(HeapSnapShot *snapShot, const CString &fileName)
23 {
24     // Serialize Node/Edge/String-Table
25     LOG(ERROR, RUNTIME) << "HeapSnapShotJSONSerializer::Serialize begin";
26     snapShot_ = snapShot;
27     ASSERT(snapShot_->GetNodes() != nullptr && snapShot_->GetEdges() != nullptr &&
28            snapShot_->GetEcmaStringTable() != nullptr);
29     stringBuffer_.str("");  // Clear Buffer
30 
31     SerializeSnapShotHeader();     // 1.
32     SerializeNodes();              // 2.
33     SerializeEdges();              // 3.
34     SerializeTraceFunctionInfo();  // 4.
35     SerializeTraceTree();          // 5.
36     SerializeSamples();            // 6.
37     SerializeLocations();          // 7.
38     SerializeStringTable();        // 8.
39     SerializerSnapShotClosure();   // 9.
40 
41     WriteJSON(fileName);           // 10.
42     LOG(ERROR, RUNTIME) << "HeapSnapShotJSONSerializer::Serialize exit";
43     return true;
44 }
45 
SerializeSnapShotHeader()46 void HeapSnapShotJSONSerializer::SerializeSnapShotHeader()
47 {
48     stringBuffer_ << "{\"snapshot\":\n";  // 1.
49     stringBuffer_ << "{\"meta\":\n";      // 2.
50     // NOLINTNEXTLINE(modernize-raw-string-literal)
51     stringBuffer_ << "{\"node_fields\":[\"type\",\"name\",\"id\",\"self_size\",\"edge_count\",\"trace_node_id\",";
52     stringBuffer_ << "\"detachedness\"],\n";  // 3.
53     // NOLINTNEXTLINE(modernize-raw-string-literal)
54     stringBuffer_ << "\"node_types\":[[\"hidden\",\"array\",\"string\",\"object\",\"code\",\"closure\",\"regexp\",";
55     // NOLINTNEXTLINE(modernize-raw-string-literal)
56     stringBuffer_ << "\"number\",\"native\",\"synthetic\",\"concatenated string\",\"slicedstring\",\"symbol\",";
57     // NOLINTNEXTLINE(modernize-raw-string-literal)
58     stringBuffer_ << "\"bigint\"],\"string\",\"number\",\"number\",\"number\",\"number\",\"number\"],\n";  // 4.
59     // NOLINTNEXTLINE(modernize-raw-string-literal)
60     stringBuffer_ << "\"edge_fields\":[\"type\",\"name_or_index\",\"to_node\"],\n";  // 5.
61     // NOLINTNEXTLINE(modernize-raw-string-literal)
62     stringBuffer_ << "\"edge_types\":[[\"context\",\"element\",\"property\",\"internal\",\"hidden\",\"shortcut\",";
63     // NOLINTNEXTLINE(modernize-raw-string-literal)
64     stringBuffer_ << "\"weak\"],\"string_or_number\",\"node\"],\n";  // 6.
65     // NOLINTNEXTLINE(modernize-raw-string-literal)
66     stringBuffer_ << "\"trace_function_info_fields\":[\"function_id\",\"name\",\"script_name\",\"script_id\",";
67     // NOLINTNEXTLINE(modernize-raw-string-literal)
68     stringBuffer_ << "\"line\",\"column\"],\n";  // 7.
69     // NOLINTNEXTLINE(modernize-raw-string-literal)
70     stringBuffer_ << "\"trace_node_fields\":[\"id\",\"function_info_index\",\"count\",\"size\",\"children\"],\n";
71     // NOLINTNEXTLINE(modernize-raw-string-literal)
72     stringBuffer_ << "\"sample_fields\":[\"timestamp_us\",\"last_assigned_id\"],\n";  // 9.
73     // NOLINTNEXTLINE(modernize-raw-string-literal)
74     stringBuffer_ << "\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]},\n";  // 10.
75     stringBuffer_ << "\"node_count\":" << snapShot_->GetNodeCount() << ",\n";                         // 11.
76     stringBuffer_ << "\"edge_count\":" << snapShot_->GetEdgeCount() << ",\n";                         // 12.
77     stringBuffer_ << "\"trace_function_count\":"
78                   << "0\n";   // 13.
79     stringBuffer_ << "},\n";  // 14.
80 }
81 
SerializeNodes()82 void HeapSnapShotJSONSerializer::SerializeNodes()
83 {
84     const CList<Node *> *nodes = snapShot_->GetNodes();
85     const StringHashMap *stringTable = snapShot_->GetEcmaStringTable();
86     ASSERT(nodes != nullptr);
87     stringBuffer_ << "\"nodes\":[";  // Section Header
88     size_t i = 0;
89     for (auto *node : *nodes) {
90         if (i > 0) {
91             stringBuffer_ << ",";  // add comma except first line
92         }
93         stringBuffer_ << static_cast<int>(NodeTypeConverter::Convert(node->GetType())) << ",";  // 1.
94         stringBuffer_ << stringTable->GetStringId(node->GetName()) << ",";                      // 2.
95         stringBuffer_ << node->GetId() << ",";                                                  // 3.
96         stringBuffer_ << node->GetSelfSize() << ",";                                            // 4.
97         stringBuffer_ << node->GetEdgeCount() << ",";                                           // 5.
98         stringBuffer_ << node->GetStackTraceId() << ",";                                        // 6.
99         if (i == nodes->size() - 1) {  // add comma at last the line
100             stringBuffer_ << "0"
101                           << "],\n";  // 7. detachedness default
102         } else {
103             stringBuffer_ << "0\n";  // 7.
104         }
105         i++;
106     }
107 }
108 
SerializeEdges()109 void HeapSnapShotJSONSerializer::SerializeEdges()
110 {
111     const CVector<Edge *> *edges = snapShot_->GetEdges();
112     const StringHashMap *stringTable = snapShot_->GetEcmaStringTable();
113     ASSERT(edges != nullptr);
114     stringBuffer_ << "\"edges\":[";
115     size_t i = 0;
116     for (auto *edge : *edges) {
117         if (i > 0) {  // add comma except the first line
118             stringBuffer_ << ",";
119         }
120         stringBuffer_ << static_cast<int>(edge->GetType()) << ",";          // 1.
121         stringBuffer_ << stringTable->GetStringId(edge->GetName()) << ",";  // 2. Use StringId
122 
123         if (i == edges->size() - 1) {  // add comma at last the line
124             stringBuffer_ << edge->GetTo()->GetIndex() * Node::NODE_FIELD_COUNT << "],\n";  // 3.
125         } else {
126             stringBuffer_ << edge->GetTo()->GetIndex() * Node::NODE_FIELD_COUNT << "\n";    // 3.
127         }
128         i++;
129     }
130 }
131 
SerializeTraceFunctionInfo()132 void HeapSnapShotJSONSerializer::SerializeTraceFunctionInfo()
133 {
134     stringBuffer_ << "\"trace_function_infos\":[],\n";  // Empty
135 }
136 
SerializeTraceTree()137 void HeapSnapShotJSONSerializer::SerializeTraceTree()
138 {
139     stringBuffer_ << "\"trace_tree\":[],\n";  // Empty
140 }
141 
SerializeSamples()142 void HeapSnapShotJSONSerializer::SerializeSamples()
143 {
144     stringBuffer_ << "\"samples\":[";
145     const CVector<TimeStamp> &timeStamps = snapShot_->GetTimeStamps();
146     if (!timeStamps.empty()) {
147         auto firstTimeStamp = timeStamps[0];
148         bool isFirst = true;
149         for (auto timeStamp : timeStamps) {
150             if (!isFirst) {
151                 stringBuffer_ << "\n, ";
152             } else {
153                 isFirst = false;
154             }
155             stringBuffer_ << timeStamp.GetTimeStamp() - firstTimeStamp.GetTimeStamp() << ", ";
156             stringBuffer_ << timeStamp.GetLastSequenceId();
157         }
158     }
159     stringBuffer_ << "],\n";
160 }
161 
SerializeLocations()162 void HeapSnapShotJSONSerializer::SerializeLocations()
163 {
164     stringBuffer_ << "\"locations\":[],\n";
165 }
166 
SerializeStringTable()167 void HeapSnapShotJSONSerializer::SerializeStringTable()
168 {
169     const StringHashMap *stringTable = snapShot_->GetEcmaStringTable();
170     ASSERT(stringTable != nullptr);
171     stringBuffer_ << "\"strings\":[\"<dummy>\",\n";
172     stringBuffer_ << "\"\",\n";
173     stringBuffer_ << "\"GC roots\",\n";
174     // StringId Range from 3
175     size_t capcity = stringTable->GetCapcity();
176     size_t i = 0;
177     for (auto key : stringTable->GetOrderedKeyStorage()) {
178         if (i == capcity - 1) {
179             stringBuffer_ << "\"" << *(stringTable->GetStringByKey(key)) << "\"\n";  // No Comma for the last line
180         } else {
181             stringBuffer_ << "\"" << *(stringTable->GetStringByKey(key)) << "\",\n";
182         }
183         i++;
184     }
185     stringBuffer_ << "]\n";
186 }
187 
SerializerSnapShotClosure()188 void HeapSnapShotJSONSerializer::SerializerSnapShotClosure()
189 {
190     stringBuffer_ << "}\n";
191 }
192 
WriteJSON(const CString & fileName)193 void HeapSnapShotJSONSerializer::WriteJSON(const CString &fileName)
194 {
195     std::string fName(fileName);
196     LOG(ERROR, RUNTIME) << "HeapSnapShotJSONSerializer::WriteJSON" << fName;
197     outputStream_.open(fName, std::ios::out);
198     if (!outputStream_.good()) {
199         LOG_ECMA(ERROR) << "open file failed";
200         return;
201     }
202     outputStream_ << stringBuffer_.str();
203     outputStream_.close();
204     outputStream_.clear();  // Make sure the next open operation success
205 }
206 }  // namespace panda::ecmascript
207