• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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 #include "pbreader_js_memory_parser.h"
16 #include <dirent.h>
17 #include <memory>
18 #include <regex>
19 #include "clock_filter_ex.h"
20 #include "fcntl.h"
21 #include "file.h"
22 #include "js_heap_config.pbreader.h"
23 #include "js_heap_result.pbreader.h"
24 #include "process_filter.h"
25 #include "stat_filter.h"
26 #include "unistd.h"
27 namespace SysTuning {
28 namespace TraceStreamer {
29 namespace jsonns {
30 const int32_t OFFSET_FIRST = 1;
31 const int32_t OFFSET_SECOND = 2;
32 const int32_t OFFSET_THIRD = 3;
33 const int32_t OFFSET_FOURTH = 4;
34 const int32_t OFFSET_FIFTH = 5;
35 const int32_t OFFSET_SIXTH = 6;
36 struct Meta {
37     std::vector<std::string> nodeFields;
38     std::vector<std::vector<std::string>> nodeTypes;
39     std::vector<std::string> edgeFields;
40     std::vector<std::vector<std::string>> edgeTypes;
41     std::vector<std::string> traceFunctionInfoFields;
42     std::vector<std::string> traceNodeFields;
43     std::vector<std::string> sampleFields;
44     std::vector<std::string> locationFields;
45 };
46 struct Snapshot {
47     Meta meta;
48     int32_t nodeCount;
49     int32_t edgeCount;
50     int32_t traceFunctionCount;
51 };
52 int32_t g_nodesSingleLength = 0;
from_json(const json & j,Meta & v)53 void from_json(const json &j, Meta &v)
54 {
55     for (size_t i = 0; i < j["node_fields"].size(); i++) {
56         v.nodeFields.emplace_back(j["node_fields"][i]);
57     }
58     g_nodesSingleLength = j["node_fields"].size();
59     for (size_t i = 0; i < j["node_types"].size(); i++) {
60         std::vector<std::string> nodeTypes;
61         if (j["node_types"][i].is_array()) {
62             for (size_t m = 0; m < j["node_types"][i].size(); m++) {
63                 nodeTypes.emplace_back(j["node_types"][i][m]);
64             }
65             v.nodeTypes.emplace_back(nodeTypes);
66         } else {
67             nodeTypes.emplace_back(j["node_types"][i]);
68             v.nodeTypes.emplace_back(nodeTypes);
69         }
70     }
71     for (size_t i = 0; i < j["edge_fields"].size(); i++) {
72         v.edgeFields.emplace_back(j["edge_fields"][i]);
73     }
74     for (size_t i = 0; i < j["edge_types"].size(); i++) {
75         std::vector<std::string> edgeTypes;
76         if (j["edge_types"][i].is_array()) {
77             for (size_t m = 0; m < j["edge_types"][i].size(); m++) {
78                 edgeTypes.emplace_back(j["edge_types"][i][m]);
79             }
80             v.edgeTypes.emplace_back(edgeTypes);
81         } else {
82             edgeTypes.emplace_back(j["edge_types"][i]);
83             v.edgeTypes.emplace_back(edgeTypes);
84         }
85     }
86     for (size_t i = 0; i < j["trace_function_info_fields"].size(); i++) {
87         v.traceFunctionInfoFields.emplace_back(j["trace_function_info_fields"][i]);
88     }
89     for (size_t i = 0; i < j["trace_node_fields"].size(); i++) {
90         v.traceNodeFields.emplace_back(j["trace_node_fields"][i]);
91     }
92     for (size_t i = 0; i < j["sample_fields"].size(); i++) {
93         v.sampleFields.emplace_back(j["sample_fields"][i]);
94     }
95     for (size_t i = 0; i < j["location_fields"].size(); i++) {
96         v.locationFields.emplace_back(j["location_fields"][i]);
97     }
98     return;
99 }
from_json(const json & j,Snapshot & v)100 void from_json(const json &j, Snapshot &v)
101 {
102     j.at("meta").get_to(v.meta);
103     j.at("node_count").get_to(v.nodeCount);
104     j.at("edge_count").get_to(v.edgeCount);
105     j.at("trace_function_count").get_to(v.traceFunctionCount);
106     return;
107 }
108 struct Nodes {
109     std::vector<uint32_t> types;
110     std::vector<uint32_t> names;
111     std::vector<uint32_t> ids;
112     std::vector<uint32_t> selfSizes;
113     std::vector<uint32_t> edgeCounts;
114     std::vector<uint32_t> traceNodeIds;
115     std::vector<uint32_t> detachedness;
116 };
117 std::vector<uint32_t> g_fromNodeIds;
118 std::vector<uint32_t> g_ids;
from_json(const json & j,Nodes & v)119 void from_json(const json &j, Nodes &v)
120 {
121     int32_t edgeIndex = 0;
122     for (size_t i = 0; i < j.size() / g_nodesSingleLength; i++) {
123         v.types.emplace_back(j[i * g_nodesSingleLength]);
124         v.names.emplace_back(j[i * g_nodesSingleLength + OFFSET_FIRST]);
125         v.ids.emplace_back(j[i * g_nodesSingleLength + OFFSET_SECOND]);
126         v.selfSizes.emplace_back(j[i * g_nodesSingleLength + OFFSET_THIRD]);
127         v.edgeCounts.emplace_back(j[i * g_nodesSingleLength + OFFSET_FOURTH]);
128         for (size_t m = edgeIndex; m < edgeIndex + v.edgeCounts.at(i); m++) {
129             g_fromNodeIds.emplace_back(j[i * g_nodesSingleLength + OFFSET_SECOND]);
130         }
131         edgeIndex += v.edgeCounts.at(i);
132         v.traceNodeIds.emplace_back(j[i * g_nodesSingleLength + OFFSET_FIFTH]);
133         v.detachedness.emplace_back(j[i * g_nodesSingleLength + OFFSET_SIXTH]);
134     }
135     for (size_t m = 0; m < j.size(); m++) {
136         g_ids.emplace_back(j[m]);
137     }
138 }
139 struct Edges {
140     std::vector<uint32_t> types;
141     std::vector<uint32_t> nameOrIndexes;
142     std::vector<uint32_t> toNodes;
143     std::vector<uint32_t> fromNodeIds;
144     std::vector<uint32_t> toNodeIds;
145 };
146 const int32_t EDGES_SINGLE_LENGTH = 3;
from_json(const json & j,Edges & v)147 void from_json(const json &j, Edges &v)
148 {
149     v.fromNodeIds = g_fromNodeIds;
150     for (size_t i = 0; i < j.size() / EDGES_SINGLE_LENGTH; i++) {
151         v.types.emplace_back(j[i * EDGES_SINGLE_LENGTH]);
152         v.nameOrIndexes.emplace_back(j[i * EDGES_SINGLE_LENGTH + OFFSET_FIRST]);
153         v.toNodes.emplace_back(j[i * EDGES_SINGLE_LENGTH + OFFSET_SECOND]);
154         v.toNodeIds.emplace_back(g_ids[v.toNodes[i] + OFFSET_SECOND]);
155     }
156     return;
157 }
158 struct Location {
159     std::vector<uint32_t> objectIndexes;
160     std::vector<uint32_t> scriptIds;
161     std::vector<uint32_t> lines;
162     std::vector<uint32_t> columns;
163 };
164 const int32_t LOCATION_SINGLE_LENGTH = 4;
from_json(const json & j,Location & v)165 void from_json(const json &j, Location &v)
166 {
167     for (size_t i = 0; i < j.size() / LOCATION_SINGLE_LENGTH; i++) {
168         v.objectIndexes.emplace_back(j[i * LOCATION_SINGLE_LENGTH]);
169         v.scriptIds.emplace_back(j[i * LOCATION_SINGLE_LENGTH + OFFSET_FIRST]);
170         v.lines.emplace_back(j[i * LOCATION_SINGLE_LENGTH + OFFSET_SECOND]);
171         v.columns.emplace_back(j[i * LOCATION_SINGLE_LENGTH + OFFSET_THIRD]);
172     }
173 }
174 struct Sample {
175     std::vector<uint32_t> timestampUs;
176     std::vector<uint32_t> lastAssignedIds;
177 };
178 const int32_t SAMPLE_SINGLE_LENGTH = 2;
from_json(const json & j,Sample & v)179 void from_json(const json &j, Sample &v)
180 {
181     for (size_t i = 0; i < j.size() / SAMPLE_SINGLE_LENGTH; i++) {
182         v.timestampUs.emplace_back(j[i * SAMPLE_SINGLE_LENGTH]);
183         v.lastAssignedIds.emplace_back(j[i * SAMPLE_SINGLE_LENGTH + OFFSET_FIRST]);
184     }
185 }
186 struct Strings {
187     std::vector<std::string> strings;
188 };
from_json(const json & j,Strings & v)189 void from_json(const json &j, Strings &v)
190 {
191     for (size_t i = 0; i < j.size(); i++) {
192         v.strings.emplace_back(j[i]);
193     }
194 }
195 struct TraceFuncInfo {
196     std::vector<uint32_t> functionIds;
197     std::vector<uint32_t> names;
198     std::vector<uint32_t> scriptNames;
199     std::vector<uint32_t> scriptIds;
200     std::vector<uint32_t> lines;
201     std::vector<uint32_t> columns;
202 };
203 const int32_t TRACE_FUNC_INFO_SINGLE_LENGTH = 6;
from_json(const json & j,TraceFuncInfo & v)204 void from_json(const json &j, TraceFuncInfo &v)
205 {
206     for (size_t i = 0; i < j.size() / TRACE_FUNC_INFO_SINGLE_LENGTH; i++) {
207         v.functionIds.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH]);
208         v.names.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_FIRST]);
209         v.scriptNames.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_SECOND]);
210         v.scriptIds.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_THIRD]);
211         v.lines.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_FOURTH]);
212         v.columns.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_FIFTH]);
213     }
214 }
215 struct TraceTree {
216     std::vector<uint32_t> ids;
217     std::vector<uint32_t> functionInfoIndexes;
218     std::vector<uint32_t> counts;
219     std::vector<uint32_t> sizes;
220     std::vector<uint32_t> parentIds;
221 };
222 struct ParentFunc {
223     uint32_t id;
224     uint32_t functionInfoIndex;
225     uint32_t count;
226     uint32_t size;
227     std::vector<std::unique_ptr<ParentFunc>> children;
228     ParentFunc *parent = nullptr;
ParentFuncSysTuning::TraceStreamer::jsonns::ParentFunc229     ParentFunc()
230     {
231         id = 0;
232         functionInfoIndex = 0;
233         count = 0;
234         size = 0;
235     }
236 };
237 class TraceParser {
238 public:
parse_trace_node(const json & array,std::vector<std::unique_ptr<ParentFunc>> & funcList,ParentFunc * parent=nullptr)239     void parse_trace_node(const json &array,
240                           std::vector<std::unique_ptr<ParentFunc>> &funcList,
241                           ParentFunc *parent = nullptr)
242     {
243         int32_t singleLength = 5;
244         int32_t functionCount = array.size() / singleLength;
245         for (int32_t i = 0; i < functionCount; ++i) {
246             auto item = std::make_unique<ParentFunc>();
247             if (parent != nullptr) {
248                 item->parent = parent;
249             }
250             item->id = array[i * singleLength];
251             item->functionInfoIndex = array[i * singleLength + OFFSET_FIRST];
252             item->count = array[i * singleLength + OFFSET_SECOND];
253             item->size = array[i * singleLength + OFFSET_THIRD];
254             auto childrenArray = array[i * singleLength + OFFSET_FOURTH];
255             funcList.push_back(std::move(item));
256             if (!childrenArray.empty()) {
257                 parse_trace_node(childrenArray, funcList, funcList.back().get());
258             }
259         }
260     }
261 };
from_json(const json & j,TraceTree & v)262 void from_json(const json &j, TraceTree &v)
263 {
264     std::vector<std::unique_ptr<ParentFunc>> funcList;
265     TraceParser parser;
266     parser.parse_trace_node(j, funcList);
267     for (auto &func : funcList) {
268         v.ids.emplace_back(func->id);
269         v.functionInfoIndexes.emplace_back(func->functionInfoIndex);
270         v.counts.emplace_back(func->count);
271         v.sizes.emplace_back(func->size);
272         v.parentIds.emplace_back(func->parent ? func->parent->id : std::numeric_limits<uint32_t>::max());
273     }
274 }
275 } // namespace jsonns
276 const int32_t END_POS = 3;
277 const int32_t CHUNK_POS = 8;
278 const int32_t PROFILE_POS = 9;
279 const int32_t END_PROFILE_POS = 2;
280 const int32_t TIME_MILLI_SECOND = 1000;
281 const int32_t TIME_MICRO_SECOND = 1000 * 1000;
282 const std::string JS_MEMORY_INDEX = "{\"params\":{\"chunk\":";
283 const std::string ARKTS_INDEX = "{\"id\":3, \"result\":{\"profile\":";
PbreaderJSMemoryParser(TraceDataCache * dataCache,const TraceStreamerFilters * ctx)284 PbreaderJSMemoryParser::PbreaderJSMemoryParser(TraceDataCache *dataCache, const TraceStreamerFilters *ctx)
285     : EventParserBase(dataCache, ctx), jsCpuProfilerParser_(std::make_unique<HtraceJsCpuProfilerParser>(dataCache, ctx))
286 {
287     // Delete files in the executable file path that fileName contain the string "ts_tmp. jsmemory_snapshot"
288     DIR *dir = opendir(".");
289     if (dir != nullptr) {
290         dirent *entry;
291         while ((entry = readdir(dir)) != nullptr) {
292             std::string filename(entry->d_name);
293             if (filename.find(tmpJsMemorySnapshotData_) != std::string::npos) {
294                 (void)std::remove(filename.c_str());
295             }
296         }
297         closedir(dir);
298     }
299 }
~PbreaderJSMemoryParser()300 PbreaderJSMemoryParser::~PbreaderJSMemoryParser()
301 {
302     TS_LOGI("arkts-plugin ts MIN:%llu, MAX:%llu", static_cast<unsigned long long>(GetPluginStartTime()),
303             static_cast<unsigned long long>(GetPluginEndTime()));
304 }
ParseJSMemoryConfig(ProtoReader::BytesView tracePacket)305 void PbreaderJSMemoryParser::ParseJSMemoryConfig(ProtoReader::BytesView tracePacket)
306 {
307     ProtoReader::ArkTSConfig_Reader jsHeapConfig(tracePacket.data_, tracePacket.size_);
308     JsConfigRow row;
309     row.pid = jsHeapConfig.pid();
310     type_ = jsHeapConfig.type();
311     row.type = jsHeapConfig.type();
312     row.interval = jsHeapConfig.interval();
313     row.captureNumericValue = jsHeapConfig.capture_numeric_value() ? 1 : 0;
314     row.trackAllocation = jsHeapConfig.track_allocations() ? 1 : 0;
315     row.cpuProfiler = jsHeapConfig.enable_cpu_profiler() ? 1 : 0;
316     hasCpuProfiler_ = row.cpuProfiler ? true : false;
317     row.cpuProfilerInterval = jsHeapConfig.cpu_profiler_interval();
318     (void)traceDataCache_->GetJsConfigData()->AppendNewData(row);
319 }
TimeToTimespec(uint64_t timeMs)320 struct timespec PbreaderJSMemoryParser::TimeToTimespec(uint64_t timeMs)
321 {
322     timeMs = timeMs / TIME_MILLI_SECOND;
323     timespec ts;
324     ts.tv_sec = timeMs / TIME_MICRO_SECOND;
325     ts.tv_nsec = (timeMs % TIME_MICRO_SECOND) * TIME_MILLI_SECOND;
326     return ts;
327 }
SerializeToString(const ProfilerPluginDataHeader & profilerPluginData,uint64_t startTime,uint64_t endTime)328 void PbreaderJSMemoryParser::SerializeToString(const ProfilerPluginDataHeader &profilerPluginData,
329                                                uint64_t startTime,
330                                                uint64_t endTime)
331 {
332     startTime = streamFilters_->clockFilter_->Convert(TS_CLOCK_BOOTTIME, startTime, TS_CLOCK_REALTIME);
333     endTime = streamFilters_->clockFilter_->Convert(TS_CLOCK_BOOTTIME, endTime, TS_CLOCK_REALTIME);
334     ProfilerPluginData profilerPluginDataResult;
335     ArkTSResult jsHeapResult;
336     profilerPluginDataResult.set_name("arkts-plugin");
337     profilerPluginDataResult.set_status(profilerPluginData.status);
338     profilerPluginDataResult.set_clock_id(::ProfilerPluginData_ClockId(profilerPluginData.clockId));
339     profilerPluginDataResult.set_version("1.01");
340     profilerPluginDataResult.set_sample_interval(profilerPluginData.sampleInterval);
341     if (!jsMemorySplitFileData_.size() && !cpuProfilerSplitFileData_.size()) {
342         return;
343     }
344     if (type_ == ProtoReader::ArkTSConfig_HeapType::ArkTSConfig_HeapType_SNAPSHOT) {
345         SerializeSnapshotData(profilerPluginDataResult, jsHeapResult);
346     } else if (type_ == ProtoReader::ArkTSConfig_HeapType::ArkTSConfig_HeapType_TIMELINE) {
347         SerializeTimelineData(startTime, endTime, profilerPluginDataResult, jsHeapResult);
348     }
349     if (hasCpuProfiler_) {
350         SerializeCpuProfilerData(startTime, endTime, profilerPluginDataResult, jsHeapResult);
351     }
352 }
SerializeSnapshotData(ProfilerPluginData & profilerPluginDataResult,ArkTSResult & jsHeapResult)353 void PbreaderJSMemoryParser::SerializeSnapshotData(ProfilerPluginData &profilerPluginDataResult,
354                                                    ArkTSResult &jsHeapResult)
355 {
356     if (curTypeIsCpuProfile_) {
357         curTypeIsCpuProfile_ = false;
358         return;
359     }
360     jsHeapResult.set_result(JS_MEMORY_INDEX + snapShotData_.snapshotData + "}}");
361     snapShotData_.startTime =
362         streamFilters_->clockFilter_->Convert(TS_CLOCK_BOOTTIME, snapShotData_.startTime, TS_CLOCK_REALTIME);
363     snapShotData_.endTime =
364         streamFilters_->clockFilter_->Convert(TS_CLOCK_BOOTTIME, snapShotData_.endTime, TS_CLOCK_REALTIME);
365     timespec startTs = TimeToTimespec(snapShotData_.startTime);
366     profilerPluginDataResult.set_tv_sec(startTs.tv_sec);
367     profilerPluginDataResult.set_tv_nsec(startTs.tv_nsec);
368     jsHeapResult.SerializeToString(&arkTsSplitFileDataResult_);
369     profilerPluginDataResult.set_data(arkTsSplitFileDataResult_);
370     std::string profilerArktsData = "";
371     profilerPluginDataResult.SerializeToString(&profilerArktsData);
372     std::string endString = "";
373     jsHeapResult.set_result(snapshotEnd_);
374     timespec endTs = TimeToTimespec(snapShotData_.endTime);
375     profilerPluginDataResult.set_tv_sec(endTs.tv_sec);
376     profilerPluginDataResult.set_tv_nsec(endTs.tv_nsec);
377     jsHeapResult.SerializeToString(&endString);
378     profilerPluginDataResult.set_data(endString);
379     std::string arkTsEndString = "";
380     profilerPluginDataResult.SerializeToString(&arkTsEndString);
381     std::string bufflen(sizeof(uint32_t), '\0');
382     uint32_t profilerArktsDataSize = profilerArktsData.size();
383     memcpy_s(&bufflen[0], sizeof(uint32_t), &profilerArktsDataSize, sizeof(uint32_t));
384     std::string endLen(sizeof(uint32_t), '\0');
385     profilerArktsDataSize = arkTsEndString.size();
386     memcpy_s(&endLen[0], sizeof(uint32_t), &profilerArktsDataSize, sizeof(uint32_t));
387     profilerArktsData_ += bufflen + profilerArktsData + endLen + arkTsEndString;
388 }
SerializeTimelineData(uint64_t startTime,uint64_t endTime,ProfilerPluginData & profilerPluginDataResult,ArkTSResult & jsHeapResult)389 void PbreaderJSMemoryParser::SerializeTimelineData(uint64_t startTime,
390                                                    uint64_t endTime,
391                                                    ProfilerPluginData &profilerPluginDataResult,
392                                                    ArkTSResult &jsHeapResult)
393 {
394     std::string startString = "";
395     jsHeapResult.set_result(snapshotEnd_);
396     timespec startTs = TimeToTimespec(startTime);
397     profilerPluginDataResult.set_tv_sec(startTs.tv_sec);
398     profilerPluginDataResult.set_tv_nsec(startTs.tv_nsec);
399     jsHeapResult.SerializeToString(&startString);
400     profilerPluginDataResult.set_data(startString);
401     std::string timelineStartString = "";
402     profilerPluginDataResult.SerializeToString(&timelineStartString);
403     jsHeapResult.set_result(JS_MEMORY_INDEX + jsMemorySplitFileData_ + "}}");
404     jsHeapResult.SerializeToString(&arkTsSplitFileDataResult_);
405     profilerPluginDataResult.set_data(arkTsSplitFileDataResult_);
406     std::string profilerArktsData = "";
407     profilerPluginDataResult.SerializeToString(&profilerArktsData);
408     std::string endString = "";
409     jsHeapResult.set_result(timeLineEnd_);
410     timespec endTs = TimeToTimespec(endTime);
411     profilerPluginDataResult.set_tv_sec(endTs.tv_sec);
412     profilerPluginDataResult.set_tv_nsec(endTs.tv_nsec);
413     jsHeapResult.SerializeToString(&endString);
414     profilerPluginDataResult.set_data(endString);
415     std::string timelineEndString = "";
416     profilerPluginDataResult.SerializeToString(&timelineEndString);
417     std::string startLen(sizeof(uint32_t), '\0');
418     uint32_t size = timelineStartString.size();
419     memcpy_s(&startLen[0], sizeof(uint32_t), &size, sizeof(uint32_t));
420     std::string bufflen(sizeof(uint32_t), '\0');
421     size = profilerArktsData.size();
422     memcpy_s(&bufflen[0], sizeof(uint32_t), &size, sizeof(uint32_t));
423     std::string endLen(sizeof(uint32_t), '\0');
424     size = timelineEndString.size();
425     memcpy_s(&endLen[0], sizeof(uint32_t), &size, sizeof(uint32_t));
426     profilerArktsData_ = startLen + timelineStartString + bufflen + profilerArktsData + endLen + timelineEndString;
427 }
SerializeCpuProfilerData(uint64_t startTime,uint64_t endTime,ProfilerPluginData & profilerPluginDataResult,ArkTSResult & jsHeapResult)428 void PbreaderJSMemoryParser::SerializeCpuProfilerData(uint64_t startTime,
429                                                       uint64_t endTime,
430                                                       ProfilerPluginData &profilerPluginDataResult,
431                                                       ArkTSResult &jsHeapResult)
432 {
433     std::string startString = "";
434     jsHeapResult.set_result(jsCpuProfilerStart_);
435     timespec startTs = TimeToTimespec(startTime);
436     profilerPluginDataResult.set_tv_sec(startTs.tv_sec);
437     profilerPluginDataResult.set_tv_nsec(startTs.tv_nsec);
438     jsHeapResult.SerializeToString(&startString);
439     profilerPluginDataResult.set_data(startString);
440     std::string arkTsStartString = "";
441     profilerPluginDataResult.SerializeToString(&arkTsStartString);
442     jsHeapResult.set_result(ARKTS_INDEX + cpuProfilerSplitFileData_ + "}\"");
443     jsHeapResult.SerializeToString(&arkTsSplitFileDataResult_);
444     profilerPluginDataResult.set_data(arkTsSplitFileDataResult_);
445     timespec endTs = TimeToTimespec(endTime);
446     profilerPluginDataResult.set_tv_sec(endTs.tv_sec);
447     profilerPluginDataResult.set_tv_nsec(endTs.tv_nsec);
448     std::string profilerArktsData = "";
449     profilerPluginDataResult.SerializeToString(&profilerArktsData);
450     std::string startLen(sizeof(uint32_t), '\0');
451     uint32_t size = arkTsStartString.size();
452     memcpy_s(&startLen[0], sizeof(uint32_t), &size, sizeof(uint32_t));
453     std::string bufflen(sizeof(uint32_t), '\0');
454     size = profilerArktsData.size();
455     memcpy_s(&bufflen[0], sizeof(uint32_t), &size, sizeof(uint32_t));
456     profilerArktsData_ += startLen + arkTsStartString + bufflen + profilerArktsData;
457 }
ParseSnapshotOrTimeLineEnd(const std::string & result,ProtoReader::BytesView & tracePacket,ProfilerPluginDataHeader & profilerPluginData,uint64_t ts)458 void PbreaderJSMemoryParser::ParseSnapshotOrTimeLineEnd(const std::string &result,
459                                                         ProtoReader::BytesView &tracePacket,
460                                                         ProfilerPluginDataHeader &profilerPluginData,
461                                                         uint64_t ts)
462 {
463     std::string fileName = "";
464     if (type_ == ProtoReader::ArkTSConfig_HeapType::ArkTSConfig_HeapType_SNAPSHOT) {
465         fileName = "Snapshot" + std::to_string(fileId_);
466         ParseSnapshot(tracePacket, profilerPluginData, jsMemoryString_, ts);
467     } else if (type_ == ProtoReader::ArkTSConfig_HeapType::ArkTSConfig_HeapType_TIMELINE) {
468         if (result == snapshotEnd_) {
469             ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts);
470             UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts);
471             startTime_ = ts;
472             return;
473         }
474         fileName = "Timeline";
475         ParseTimeLine(profilerPluginData, jsMemoryString_);
476     }
477     ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts);
478     UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts);
479     if (traceDataCache_->isSplitFile_ && startTime_ >= traceDataCache_->SplitFileMinTime() &&
480         ts <= traceDataCache_->SplitFileMaxTime()) {
481         jsMemorySplitFileData_ = tracePacket.ToStdString();
482     }
483     if (!traceDataCache_->isSplitFile_) {
484         (void)traceDataCache_->GetJsHeapFilesData()->AppendNewData(fileId_, fileName, startTime_, ts, selfSizeCount_);
485     }
486     selfSizeCount_ = 0;
487     fileId_++;
488     isFirst_ = true;
489 }
ParseJsCpuProfiler(const std::string & result,ProfilerPluginDataHeader & profilerPluginData,uint64_t ts)490 void PbreaderJSMemoryParser::ParseJsCpuProfiler(const std::string &result,
491                                                 ProfilerPluginDataHeader &profilerPluginData,
492                                                 uint64_t ts)
493 {
494     auto jsCpuProfilerPos = result.find("profile");
495     if (jsCpuProfilerPos == std::string::npos) {
496         return;
497     }
498     curTypeIsCpuProfile_ = true;
499     auto jsCpuProfilerString =
500         result.substr(jsCpuProfilerPos + PROFILE_POS, result.size() - jsCpuProfilerPos - PROFILE_POS - END_PROFILE_POS);
501 
502     ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts);
503     UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts);
504     if (enableFileSave_) {
505         auto fd = base::OpenFile(tmpJsCpuProfilerData_ + jsCpuProFiler, O_CREAT | O_RDWR, TS_PERMISSION_RW);
506         if (!fd) {
507             fprintf(stdout, "Failed to create file: %s", jsCpuProFiler.c_str());
508             exit(-1);
509         }
510         (void)ftruncate(fd, 0);
511         (void)write(fd, jsCpuProfilerString.data(), jsCpuProfilerString.size());
512         close(fd);
513         fd = 0;
514     }
515     jsCpuProfilerParser_->ParseJsCpuProfiler(jsCpuProfilerString, traceDataCache_->SplitFileMinTime(),
516                                              traceDataCache_->SplitFileMaxTime());
517     if (traceDataCache_->isSplitFile_) {
518         cpuProfilerSplitFileData_ = jsCpuProfilerParser_->GetUpdateJson().dump();
519         SerializeToString(profilerPluginData, traceDataCache_->SplitFileMinTime(), traceDataCache_->SplitFileMaxTime());
520     }
521 }
Parse(ProtoReader::BytesView tracePacket,uint64_t ts,uint64_t startTime,uint64_t endTime,ProfilerPluginDataHeader profilerPluginData)522 void PbreaderJSMemoryParser::Parse(ProtoReader::BytesView tracePacket,
523                                    uint64_t ts,
524                                    uint64_t startTime,
525                                    uint64_t endTime,
526                                    ProfilerPluginDataHeader profilerPluginData)
527 {
528     ProtoReader::ArkTSResult_Reader jsHeapResult(tracePacket.data_, tracePacket.size_);
529     auto result = jsHeapResult.result().ToStdString();
530     if (result == snapshotEnd_ || result == timeLineEnd_) {
531         ParseSnapshotOrTimeLineEnd(result, tracePacket, profilerPluginData, ts);
532         return;
533     } else if (cpuTimeFirst_ && result == jsCpuProfilerStart_) {
534         ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts);
535         UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts);
536         startTime_ = ts;
537         cpuTimeFirst_ = false;
538     }
539     auto pos = result.find("chunk");
540     if (pos != std::string::npos) {
541         if (isFirst_ && type_ == ProtoReader::ArkTSConfig_HeapType::ArkTSConfig_HeapType_SNAPSHOT) {
542             ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts);
543             UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts);
544             startTime_ = ts;
545             isFirst_ = false;
546         }
547         auto jMessage = json::parse(result);
548         if (jMessage.contains("params") && jMessage["params"].contains("chunk")) {
549             if (jMessage["params"]["chunk"].is_string()) {
550                 jsMemoryString_ += jMessage["params"]["chunk"];
551             } else {
552                 jsMemoryString_ += jMessage["params"]["chunk"].dump();
553             }
554         }
555         curTypeIsCpuProfile_ = false;
556     } else {
557         ParseJsCpuProfiler(result, profilerPluginData, ts);
558     }
559 }
ParseTimeLine(ProfilerPluginDataHeader & profilerPluginData,const std::string & jsonString)560 void PbreaderJSMemoryParser::ParseTimeLine(ProfilerPluginDataHeader &profilerPluginData, const std::string &jsonString)
561 {
562     if (enableFileSave_) {
563         (void)write(jsFileId_, jsonString.data(), jsonString.size());
564     }
565     json jMessage = json::parse(jsonString);
566     if (traceDataCache_->isSplitFile_) {
567         for (auto &item : jMessage.items()) {
568             if (item.key() != "samples" && item.key() != "nodes") {
569                 updatedJson_[item.key()] = item.value();
570             }
571         }
572     }
573     ParserJSSnapInfo(fileId_, jMessage);
574     ParseSample(fileId_, jMessage, traceDataCache_->SplitFileMinTime(), traceDataCache_->SplitFileMaxTime(),
575                 traceDataCache_->isSplitFile_);
576     ParseNodes(fileId_, jMessage, traceDataCache_->SplitFileMinTime(), traceDataCache_->isSplitFile_);
577     ParseEdges(fileId_, jMessage);
578     ParseLocation(fileId_, jMessage);
579     ParseString(fileId_, jMessage);
580     ParseTraceFuncInfo(fileId_, jMessage);
581     ParseTraceNode(fileId_, jMessage);
582     if (traceDataCache_->isSplitFile_) {
583         updatedJson_["snapshot"]["node_count"] = nodeCount_;
584         jsMemorySplitFileData_ = updatedJson_.dump();
585         SerializeToString(profilerPluginData, traceDataCache_->SplitFileMinTime(), traceDataCache_->SplitFileMaxTime());
586         nodeCount_ = 0;
587     }
588     jsMemoryString_ = "";
589     streamFilters_->statFilter_->IncreaseStat(TRACE_JS_MEMORY, STAT_EVENT_RECEIVED);
590     return;
591 }
ParserSnapInfo(int32_t fileId,const std::string & key,const std::vector<std::vector<std::string>> & types)592 void PbreaderJSMemoryParser::ParserSnapInfo(int32_t fileId,
593                                             const std::string &key,
594                                             const std::vector<std::vector<std::string>> &types)
595 {
596     if (traceDataCache_->isSplitFile_) {
597         return;
598     }
599     for (size_t m = 0; m < types[0].size(); ++m) {
600         (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, key, 0, std::numeric_limits<uint32_t>::max(),
601                                                                   types[0][m]);
602     }
603     for (size_t i = 1; i < types.size(); ++i) {
604         (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, key, 1, std::numeric_limits<uint32_t>::max(),
605                                                                   types[i][0]);
606     }
607     return;
608 }
609 const std::string NODE_TYPES = "node_types";
610 const std::string EDGE_TYPES = "edge_types";
ParserJSSnapInfo(int32_t fileId,const json & jMessage)611 void PbreaderJSMemoryParser::ParserJSSnapInfo(int32_t fileId, const json &jMessage)
612 {
613     jsonns::Snapshot snapshot = jMessage.at("snapshot");
614     ParserSnapInfo(fileId, NODE_TYPES, snapshot.meta.nodeTypes);
615     ParserSnapInfo(fileId, EDGE_TYPES, snapshot.meta.edgeTypes);
616     // Ensure successful update of g_nodesSingleLength
617     if (traceDataCache_->isSplitFile_) {
618         return;
619     }
620     auto nodeCount = snapshot.nodeCount;
621     auto edgeCount = snapshot.edgeCount;
622     auto traceFuncCount = snapshot.traceFunctionCount;
623     (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, "node_count", 0, nodeCount, "");
624     (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, "edge_count", 0, edgeCount, "");
625     (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, "trace_function_count", 0, traceFuncCount, "");
626     return;
627 }
ParseNodes(int32_t fileId,const json & jMessage,uint64_t endTime,bool isSplitFile)628 void PbreaderJSMemoryParser::ParseNodes(int32_t fileId, const json &jMessage, uint64_t endTime, bool isSplitFile)
629 {
630     json filteredNodes = nlohmann::json::array();
631     jsonns::Nodes node = jMessage.at("nodes");
632     for (size_t i = 0; i < node.names.size(); ++i) {
633         if (!isSplitFile) {
634             JsHeapNodesRow row;
635             row.fileId = fileId;
636             row.nodeIndex = i;
637             row.type = node.types[i];
638             row.name = node.names[i];
639             row.id = node.ids[i];
640             row.selfSize = node.selfSizes[i];
641             row.edgeCount = node.edgeCounts[i];
642             row.traceNodeId = node.traceNodeIds[i];
643             row.detachedNess = node.detachedness[i];
644             (void)traceDataCache_->GetJsHeapNodesData()->AppendNewData(row);
645         }
646         selfSizeCount_ += node.selfSizes[i];
647         if (isSplitFile && nodeFileId_ != INVALID_UINT32 && node.ids[i] <= nodeFileId_) {
648             filteredNodes.push_back(node.types[i]);
649             filteredNodes.push_back(node.names[i]);
650             filteredNodes.push_back(node.ids[i]);
651             filteredNodes.push_back(node.selfSizes[i]);
652             filteredNodes.push_back(node.edgeCounts[i]);
653             filteredNodes.push_back(node.traceNodeIds[i]);
654             filteredNodes.push_back(node.detachedness[i]);
655             nodeCount_++;
656         }
657     }
658     if (isSplitFile) {
659         updatedJson_["nodes"] = filteredNodes;
660     }
661     return;
662 }
ParseEdges(int32_t fileId,const json & jMessage)663 void PbreaderJSMemoryParser::ParseEdges(int32_t fileId, const json &jMessage)
664 {
665     if (traceDataCache_->isSplitFile_) {
666         return;
667     }
668     jsonns::Edges edge = jMessage.at("edges");
669     JsHeapEdgesRow row;
670     row.fileId = fileId;
671     for (size_t i = 0; i < edge.types.size(); ++i) {
672         row.edgeIndex = i;
673         row.type = edge.types[i];
674         row.nameOrIndex = edge.nameOrIndexes[i];
675         row.toNode = edge.toNodes[i];
676         row.fromNodeId = edge.fromNodeIds[i];
677         row.toNodeId = edge.toNodeIds[i];
678         (void)traceDataCache_->GetJsHeapEdgesData()->AppendNewData(row);
679     }
680     return;
681 }
ParseLocation(int32_t fileId,const json & jMessage)682 void PbreaderJSMemoryParser::ParseLocation(int32_t fileId, const json &jMessage)
683 {
684     if (traceDataCache_->isSplitFile_) {
685         return;
686     }
687     jsonns::Location location = jMessage.at("locations");
688     for (size_t i = 0; i < location.columns.size(); ++i) {
689         auto objectIndex = location.objectIndexes[i];
690         auto scriptId = location.scriptIds[i];
691         auto line = location.lines[i];
692         auto column = location.columns[i];
693         (void)traceDataCache_->GetJsHeapLocationData()->AppendNewData(fileId, objectIndex, scriptId, line, column);
694     }
695     return;
696 }
ParseSample(int32_t fileId,const json & jMessage,uint64_t startTime,uint64_t endTime,bool isSplitFile)697 void PbreaderJSMemoryParser::ParseSample(int32_t fileId,
698                                          const json &jMessage,
699                                          uint64_t startTime,
700                                          uint64_t endTime,
701                                          bool isSplitFile)
702 {
703     json filteredSamples = nlohmann::json::array();
704     jsonns::Sample sample = jMessage.at("samples");
705     uint32_t firstTimeStamp = INVALID_UINT32;
706     for (size_t i = 0; i < sample.timestampUs.size(); ++i) {
707         auto timestampUs = sample.timestampUs[i];
708         auto lastAssignedId = sample.lastAssignedIds[i];
709         if (!isSplitFile) {
710             (void)traceDataCache_->GetJsHeapSampleData()->AppendNewData(fileId, timestampUs, lastAssignedId);
711         }
712         uint64_t timestampNs = (uint64_t)timestampUs * 1000;
713         if (isSplitFile && startTime <= (GetPluginStartTime() + timestampNs) &&
714             endTime >= (GetPluginStartTime() + timestampNs)) {
715             if (firstTimeStamp == INVALID_UINT32) {
716                 firstTimeStamp = timestampUs;
717             }
718             filteredSamples.push_back(timestampUs - firstTimeStamp);
719             filteredSamples.push_back(lastAssignedId);
720             nodeFileId_ = lastAssignedId;
721         }
722     }
723     if (isSplitFile) {
724         updatedJson_["samples"] = filteredSamples;
725     }
726     return;
727 }
ParseString(int32_t fileId,const json & jMessage)728 void PbreaderJSMemoryParser::ParseString(int32_t fileId, const json &jMessage)
729 {
730     if (traceDataCache_->isSplitFile_) {
731         return;
732     }
733     jsonns::Strings string = jMessage.at("strings");
734     for (size_t i = 0; i < string.strings.size(); ++i) {
735         (void)traceDataCache_->GetJsHeapStringData()->AppendNewData(fileId, i, string.strings[i]);
736     }
737     return;
738 }
ParseTraceFuncInfo(int32_t fileId,const json & jMessage)739 void PbreaderJSMemoryParser::ParseTraceFuncInfo(int32_t fileId, const json &jMessage)
740 {
741     if (traceDataCache_->isSplitFile_) {
742         return;
743     }
744     jsonns::TraceFuncInfo traceFuncInfo = jMessage.at("trace_function_infos");
745     JsHeapTraceFuncRow row;
746     row.fileId = fileId;
747     for (size_t i = 0; i < traceFuncInfo.functionIds.size(); ++i) {
748         row.functionIndex = i;
749         row.functionId = traceFuncInfo.functionIds[i];
750         row.name = traceFuncInfo.names[i];
751         row.scriptName = traceFuncInfo.scriptNames[i];
752         row.scriptId = traceFuncInfo.scriptIds[i];
753         row.line = traceFuncInfo.lines[i];
754         row.column = traceFuncInfo.columns[i];
755         (void)traceDataCache_->GetJsHeapTraceFuncInfoData()->AppendNewData(row);
756     }
757     return;
758 }
ParseTraceNode(int32_t fileId,const json & jMessage)759 void PbreaderJSMemoryParser::ParseTraceNode(int32_t fileId, const json &jMessage)
760 {
761     if (traceDataCache_->isSplitFile_) {
762         return;
763     }
764     JsHeapTraceNodeRow row;
765     row.fileId = fileId;
766     jsonns::TraceTree traceTree = jMessage.at("trace_tree");
767     for (size_t i = 0; i < traceTree.ids.size(); ++i) {
768         row.traceNodeId = traceTree.ids[i];
769         row.functionInfoIndex = traceTree.functionInfoIndexes[i];
770         row.count = traceTree.counts[i];
771         row.size = traceTree.sizes[i];
772         row.parentId = traceTree.parentIds[i];
773         (void)traceDataCache_->GetJsHeapTraceNodeData()->AppendNewData(row);
774     }
775     return;
776 }
ParseSnapshot(ProtoReader::BytesView & tracePacket,ProfilerPluginDataHeader & profilerPluginData,const std::string & jsonString,uint64_t & ts)777 void PbreaderJSMemoryParser::ParseSnapshot(ProtoReader::BytesView &tracePacket,
778                                            ProfilerPluginDataHeader &profilerPluginData,
779                                            const std::string &jsonString,
780                                            uint64_t &ts)
781 {
782     if (enableFileSave_) {
783         if (jsFileId_) {
784             close(jsFileId_);
785             jsFileId_ = 0;
786             if (access(tmpJsMemoryTimelineData_.c_str(), F_OK) == 0) {
787                 (void)remove(tmpJsMemoryTimelineData_.c_str());
788             }
789         }
790         jsFileId_ = base::OpenFile(tmpJsMemorySnapshotData_ + "_" + base::number(fileId_) + jsSnapshotFileTail,
791                                    O_CREAT | O_RDWR, TS_PERMISSION_RW);
792         if (!jsFileId_) {
793             fprintf(stdout, "Failed to create file: %s", jsSnapshotFileTail.c_str());
794             exit(-1);
795         }
796         (void)ftruncate(jsFileId_, 0);
797         (void)write(jsFileId_, jsonString.data(), jsonString.size());
798         close(jsFileId_);
799         jsFileId_ = 0;
800         return;
801     }
802     json jMessage = json::parse(jsonString);
803     ParserJSSnapInfo(fileId_, jMessage);
804     ParseNodes(fileId_, jMessage, INVALID_UINT64, false);
805     ParseEdges(fileId_, jMessage);
806     ParseLocation(fileId_, jMessage);
807     ParseSample(fileId_, jMessage, INVALID_UINT64, INVALID_UINT64, false);
808     ParseString(fileId_, jMessage);
809     ParseTraceFuncInfo(fileId_, jMessage);
810     ParseTraceNode(fileId_, jMessage);
811     if (traceDataCache_->isSplitFile_) {
812         ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts);
813         if (startTime_ >= traceDataCache_->SplitFileMinTime() && ts <= traceDataCache_->SplitFileMaxTime()) {
814             snapShotData_.startTime = startTime_;
815             snapShotData_.endTime = ts;
816             snapShotData_.snapshotData = jsonString;
817             jsMemorySplitFileData_ = tracePacket.ToStdString();
818             SerializeToString(profilerPluginData, traceDataCache_->SplitFileMinTime(),
819                               traceDataCache_->SplitFileMaxTime());
820         }
821     }
822     jsMemoryString_ = "";
823     streamFilters_->statFilter_->IncreaseStat(TRACE_JS_MEMORY, STAT_EVENT_RECEIVED);
824     return;
825 }
EnableSaveFile(bool enable)826 void PbreaderJSMemoryParser::EnableSaveFile(bool enable)
827 {
828     enableFileSave_ = enable;
829     if (enable) {
830         jsFileId_ = base::OpenFile(tmpJsMemoryTimelineData_, O_CREAT | O_RDWR, TS_PERMISSION_RW);
831         if (!jsFileId_) {
832             fprintf(stdout, "Failed to create file: %s", tmpJsMemoryTimelineData_.c_str());
833             exit(-1);
834         }
835         (void)ftruncate(jsFileId_, 0);
836     } else {
837         if (jsFileId_) {
838             close(jsFileId_);
839             jsFileId_ = 0;
840         }
841         if (access(tmpJsMemoryTimelineData_.c_str(), F_OK) == 0) {
842             (void)remove(tmpJsMemoryTimelineData_.c_str());
843         }
844     }
845 }
Finish()846 void PbreaderJSMemoryParser::Finish()
847 {
848     traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime());
849     // In the case of incomplete data at the end of the file, jsMemoryString_ has an initial value when cutting data.
850     // This part of the data should be discarded
851     jsMemoryString_ = "";
852     return;
853 }
854 } // namespace TraceStreamer
855 } // namespace SysTuning
856