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