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