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