• 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/dfx/hprof/heap_snapshot_json_serializer.h"
17 
18 #include "ecmascript/dfx/hprof/heap_snapshot.h"
19 #include "ecmascript/dfx/hprof/string_hashmap.h"
20 
21 namespace panda::ecmascript {
22 
~HeapSnapshotJSONSerializer()23 HeapSnapshotJSONSerializer::~HeapSnapshotJSONSerializer()
24 {
25     if (!writer_) {
26         delete writer_;
27     }
28 }
29 
Serialize(HeapSnapshot * snapshot,Stream * stream)30 bool HeapSnapshotJSONSerializer::Serialize(HeapSnapshot *snapshot, Stream *stream)
31 {
32     // Serialize Node/Edge/String-Table
33     LOG_ECMA(ERROR) << "HeapSnapshotJSONSerializer::Serialize begin";
34     snapshot_ = snapshot;
35     ASSERT(snapshot_->GetNodes() != nullptr && snapshot_->GetEdges() != nullptr &&
36            snapshot_->GetEcmaStringTable() != nullptr);
37     writer_ = new StreamWriter(stream);
38 
39     SerializeSnapshotHeader();     // 1.
40     SerializeNodes();              // 2.
41     SerializeEdges();              // 3.
42     SerializeTraceFunctionInfo();  // 4.
43     SerializeTraceTree();          // 5.
44     SerializeSamples();            // 6.
45     SerializeLocations();          // 7.
46     SerializeStringTable();        // 8.
47     SerializerSnapshotClosure();   // 9.
48     writer_->End();
49 
50     LOG_ECMA(ERROR) << "HeapSnapshotJSONSerializer::Serialize exit";
51     return true;
52 }
53 
SerializeSnapshotHeader()54 void HeapSnapshotJSONSerializer::SerializeSnapshotHeader()
55 {
56     writer_->Write("{\"snapshot\":\n");  // 1.
57     writer_->Write("{\"meta\":\n");      // 2.
58     // NOLINTNEXTLINE(modernize-raw-string-literal)
59     writer_->Write("{\"node_fields\":[\"type\",\"name\",\"id\",\"self_size\",\"edge_count\",\"trace_node_id\",");
60     writer_->Write("\"detachedness\"],\n");  // 3.
61     // NOLINTNEXTLINE(modernize-raw-string-literal)
62     writer_->Write("\"node_types\":[[\"hidden\",\"array\",\"string\",\"object\",\"code\",\"closure\",\"regexp\",");
63     // NOLINTNEXTLINE(modernize-raw-string-literal)
64     writer_->Write("\"number\",\"native\",\"synthetic\",\"concatenated string\",\"slicedstring\",\"symbol\",");
65     // NOLINTNEXTLINE(modernize-raw-string-literal)
66     writer_->Write("\"bigint\"],\"string\",\"number\",\"number\",\"number\",\"number\",\"number\"],\n");  // 4.
67     // NOLINTNEXTLINE(modernize-raw-string-literal)
68     writer_->Write("\"edge_fields\":[\"type\",\"name_or_index\",\"to_node\"],\n");  // 5.
69     // NOLINTNEXTLINE(modernize-raw-string-literal)
70     writer_->Write("\"edge_types\":[[\"context\",\"element\",\"property\",\"internal\",\"hidden\",\"shortcut\",");
71     // NOLINTNEXTLINE(modernize-raw-string-literal)
72     writer_->Write("\"weak\"],\"string_or_number\",\"node\"],\n");  // 6.
73     // NOLINTNEXTLINE(modernize-raw-string-literal)
74     writer_->Write("\"trace_function_info_fields\":[\"function_id\",\"name\",\"script_name\",\"script_id\",");
75     // NOLINTNEXTLINE(modernize-raw-string-literal)
76     writer_->Write("\"line\",\"column\"],\n");  // 7.
77     // NOLINTNEXTLINE(modernize-raw-string-literal)
78     writer_->Write("\"trace_node_fields\":[\"id\",\"function_info_index\",\"count\",\"size\",\"children\"],\n");
79     // NOLINTNEXTLINE(modernize-raw-string-literal)
80     writer_->Write("\"sample_fields\":[\"timestamp_us\",\"last_assigned_id\"],\n");  // 9.
81     // NOLINTNEXTLINE(modernize-raw-string-literal)
82     // 10.
83     writer_->Write("\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]},\n\"node_count\":");
84     writer_->Write(snapshot_->GetNodeCount());                         // 11.
85     writer_->Write(",\n\"edge_count\":");
86     writer_->Write(snapshot_->GetEdgeCount());                         // 12.
87     writer_->Write(",\n\"trace_function_count\":");
88     writer_->Write(snapshot_->GetTrackAllocationsStack().size());   // 13.
89     writer_->Write("\n},\n");  // 14.
90 }
91 
SerializeNodes()92 void HeapSnapshotJSONSerializer::SerializeNodes()
93 {
94     const CList<Node *> *nodes = snapshot_->GetNodes();
95     const StringHashMap *stringTable = snapshot_->GetEcmaStringTable();
96     ASSERT(nodes != nullptr);
97     writer_->Write("\"nodes\":[");  // Section Header
98     size_t i = 0;
99     for (auto *node : *nodes) {
100         if (i > 0) {
101             writer_->Write(",");  // add comma except first line
102         }
103         writer_->Write(static_cast<int>(NodeTypeConverter::Convert(node->GetType())));  // 1.
104         writer_->Write(",");
105         writer_->Write(stringTable->GetStringId(node->GetName()));                      // 2.
106         writer_->Write(",");
107         writer_->Write(node->GetId());                                                  // 3.
108         writer_->Write(",");
109         writer_->Write(node->GetSelfSize());                                            // 4.
110         writer_->Write(",");
111         writer_->Write(node->GetEdgeCount());                                           // 5.
112         writer_->Write(",");
113         writer_->Write(node->GetStackTraceId());                                        // 6.
114         writer_->Write(",");
115         if (i == nodes->size() - 1) {  // add comma at last the line
116             writer_->Write("0],\n"); // 7. detachedness default
117         } else {
118             writer_->Write("0\n");  // 7.
119         }
120         i++;
121     }
122 }
123 
SerializeEdges()124 void HeapSnapshotJSONSerializer::SerializeEdges()
125 {
126     const CList<Edge *> *edges = snapshot_->GetEdges();
127     const StringHashMap *stringTable = snapshot_->GetEcmaStringTable();
128     ASSERT(edges != nullptr);
129     writer_->Write("\"edges\":[");
130     size_t i = 0;
131     for (auto *edge : *edges) {
132         if (i > 0) {  // add comma except the first line
133             writer_->Write(",");
134         }
135         writer_->Write(static_cast<int>(edge->GetType()));          // 1.
136         writer_->Write(",");
137         writer_->Write(stringTable->GetStringId(edge->GetName()));  // 2. Use StringId
138         writer_->Write(",");
139 
140         if (i == edges->size() - 1) {  // add comma at last the line
141             writer_->Write(edge->GetTo()->GetIndex() * Node::NODE_FIELD_COUNT);  // 3.
142             writer_->Write("],\n");
143         } else {
144             writer_->Write(edge->GetTo()->GetIndex() * Node::NODE_FIELD_COUNT);    // 3.
145             writer_->Write("\n");
146         }
147         i++;
148     }
149 }
150 
SerializeTraceFunctionInfo()151 void HeapSnapshotJSONSerializer::SerializeTraceFunctionInfo()
152 {
153     const CVector<FunctionInfo> trackAllocationsStack = snapshot_->GetTrackAllocationsStack();
154     const StringHashMap *stringTable = snapshot_->GetEcmaStringTable();
155 
156     writer_->Write("\"trace_function_infos\":[");  // Empty
157     size_t i = 0;
158 
159     for (const auto &info : trackAllocationsStack) {
160         if (i > 0) {  // add comma except the first line
161             writer_->Write(",");
162         }
163         writer_->Write(info.functionId);
164         writer_->Write(",");
165         CString functionName(info.functionName.c_str());
166         writer_->Write(stringTable->GetStringId(&functionName));
167         writer_->Write(",");
168         CString scriptName(info.scriptName.c_str());
169         writer_->Write(stringTable->GetStringId(&scriptName));
170         writer_->Write(",");
171         writer_->Write(info.scriptId);
172         writer_->Write(",");
173         writer_->Write(info.columnNumber);
174         writer_->Write(",");
175         writer_->Write(info.lineNumber);
176         writer_->Write("\n");
177         i++;
178     }
179     writer_->Write("],\n");
180 }
181 
SerializeTraceTree()182 void HeapSnapshotJSONSerializer::SerializeTraceTree()
183 {
184     writer_->Write("\"trace_tree\":[");
185     TraceTree* tree = snapshot_->GetTraceTree();
186     if ((tree != nullptr) && (snapshot_->trackAllocations())) {
187         SerializeTraceNode(tree->GetRoot());
188     }
189     writer_->Write("],\n");
190 }
191 
SerializeTraceNode(TraceNode * node)192 void HeapSnapshotJSONSerializer::SerializeTraceNode(TraceNode* node)
193 {
194     if (node == nullptr) {
195         return;
196     }
197 
198     writer_->Write(node->GetId());
199     writer_->Write(",");
200     writer_->Write(node->GetNodeIndex());
201     writer_->Write(",");
202     writer_->Write(node->GetTotalCount());
203     writer_->Write(",");
204     writer_->Write(node->GetTotalSize());
205     writer_->Write(",[");
206 
207     int i = 0;
208     for (TraceNode* child : node->GetChildren()) {
209         if (i > 0) {
210             writer_->Write(",");
211         }
212         SerializeTraceNode(child);
213         i++;
214     }
215     writer_->Write("]");
216 }
217 
SerializeSamples()218 void HeapSnapshotJSONSerializer::SerializeSamples()
219 {
220     writer_->Write("\"samples\":[");
221     const CVector<TimeStamp> &timeStamps = snapshot_->GetTimeStamps();
222     if (!timeStamps.empty()) {
223         auto firstTimeStamp = timeStamps[0];
224         bool isFirst = true;
225         for (auto timeStamp : timeStamps) {
226             if (!isFirst) {
227                 writer_->Write("\n, ");
228             } else {
229                 isFirst = false;
230             }
231             writer_->Write(timeStamp.GetTimeStamp() - firstTimeStamp.GetTimeStamp());
232             writer_->Write(", ");
233             writer_->Write(timeStamp.GetLastSequenceId());
234         }
235     }
236     writer_->Write("],\n");
237 }
238 
SerializeLocations()239 void HeapSnapshotJSONSerializer::SerializeLocations()
240 {
241     writer_->Write("\"locations\":[],\n");
242 }
243 
SerializeStringTable()244 void HeapSnapshotJSONSerializer::SerializeStringTable()
245 {
246     const StringHashMap *stringTable = snapshot_->GetEcmaStringTable();
247     ASSERT(stringTable != nullptr);
248     writer_->Write("\"strings\":[\"<dummy>\",\n");
249     writer_->Write("\"\",\n");
250     writer_->Write("\"GC roots\",\n");
251     // StringId Range from 3
252     size_t capcity = stringTable->GetCapcity();
253     size_t i = 0;
254     for (auto key : stringTable->GetOrderedKeyStorage()) {
255         if (i == capcity - 1) {
256             writer_->Write("\"");
257             writer_->Write(*(stringTable->GetStringByKey(key)));  // No Comma for the last line
258             writer_->Write("\"\n");
259         } else {
260             writer_->Write("\"");
261             writer_->Write(*(stringTable->GetStringByKey(key)));
262             writer_->Write("\",\n");
263         }
264         i++;
265     }
266     writer_->Write("]\n");
267 }
268 
SerializerSnapshotClosure()269 void HeapSnapshotJSONSerializer::SerializerSnapshotClosure()
270 {
271     writer_->Write("}\n");
272 }
273 }  // namespace panda::ecmascript
274