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