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_cpu_profiler_parser.h"
16 #include "clock_filter_ex.h"
17
18 namespace SysTuning {
19 namespace TraceStreamer {
20 const uint32_t TIME_SECOND_COVER = 1000;
21 namespace jsonns {
22
23 struct CallFrame {
24 std::string functionName;
25 std::string scriptId;
26 std::string url;
27 int32_t lineNumber;
28 int32_t columnNumber;
29 };
30 struct Node {
31 uint32_t id;
32 CallFrame callFrame;
33 uint32_t hitCount;
34 std::string children;
35 };
from_json(const json & j,CallFrame & callFrame)36 void from_json(const json &j, CallFrame &callFrame)
37 {
38 j.at("functionName").get_to(callFrame.functionName);
39 j.at("scriptId").get_to(callFrame.scriptId);
40 j.at("url").get_to(callFrame.url);
41 j.at("lineNumber").get_to(callFrame.lineNumber);
42 j.at("columnNumber").get_to(callFrame.columnNumber);
43 return;
44 }
45 std::map<int, int> nodes_;
from_json(const json & j,Node & node)46 void from_json(const json &j, Node &node)
47 {
48 j.at("id").get_to(node.id);
49 j.at("callFrame").get_to(node.callFrame);
50 j.at("hitCount").get_to(node.hitCount);
51 for (size_t i = 0; i < j["children"].size(); i++) {
52 int child = j["children"][i];
53 nodes_.emplace(child, node.id);
54 auto children = std::to_string(child);
55 node.children += children + ",";
56 }
57 return;
58 }
59 } // namespace jsonns
60
HtraceJsCpuProfilerParser(TraceDataCache * dataCache,const TraceStreamerFilters * ctx)61 HtraceJsCpuProfilerParser::HtraceJsCpuProfilerParser(TraceDataCache *dataCache, const TraceStreamerFilters *ctx)
62 : EventParserBase(dataCache, ctx)
63 {
64 }
65
ParseNodeData(const json & jMessage)66 void HtraceJsCpuProfilerParser::ParseNodeData(const json &jMessage)
67 {
68 int nodeCount = jMessage.at("nodes").size();
69 JsCpuProfilerNodeRow row;
70 for (int i = 0; i < nodeCount; i++) {
71 jsonns::Node node = jMessage.at("nodes")[i];
72 row.functionId = node.id;
73 auto functionName = node.callFrame.functionName;
74 row.functionName = traceDataCache_->GetDataIndex(functionName);
75 row.scriptId = node.callFrame.scriptId;
76 auto url = node.callFrame.url;
77 row.url = traceDataCache_->GetDataIndex(url);
78 row.lineNumber = node.callFrame.lineNumber;
79 row.columnNumber = node.callFrame.columnNumber;
80 row.hitCount = node.hitCount;
81 auto children = node.children;
82 row.children = children.substr(0, children.size() - 1);
83 row.parent = 0;
84 if (jsonns::nodes_.find(node.id) != jsonns::nodes_.end()) {
85 row.parent = jsonns::nodes_.find(node.id)->second;
86 }
87 (void)traceDataCache_->GetJsCpuProfilerNodeData()->AppendNewData(row);
88 }
89 }
90
DataProcessing(const json & jMessage,uint64_t & sampleEndTime,uint64_t & startTime,uint64_t & dur,uint32_t & sample)91 void HtraceJsCpuProfilerParser::DataProcessing(const json &jMessage,
92 uint64_t &sampleEndTime,
93 uint64_t &startTime,
94 uint64_t &dur,
95 uint32_t &sample)
96 {
97 dur = (sampleEndTime * TIME_SECOND_COVER) - (startTime * TIME_SECOND_COVER);
98 auto startNewTime = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_MONOTONIC, startTime * TIME_SECOND_COVER);
99 UpdatePluginTimeRange(TS_MONOTONIC, startNewTime, startNewTime);
100 auto endNewTime = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_MONOTONIC, sampleEndTime * TIME_SECOND_COVER);
101 UpdatePluginTimeRange(TS_MONOTONIC, endNewTime, endNewTime);
102 if (!traceDataCache_->isSplitFile_) {
103 (void)traceDataCache_->GetJsCpuProfilerSampleData()->AppendNewData(sample, startNewTime, endNewTime, dur);
104 }
105 startTime = sampleEndTime;
106 }
107
ParseSampleData(const json & jMessage,uint64_t & sampleEndTime,uint64_t & startTime,uint64_t startTimeSnap,uint64_t endTimeSnap)108 uint32_t HtraceJsCpuProfilerParser::ParseSampleData(const json &jMessage,
109 uint64_t &sampleEndTime,
110 uint64_t &startTime,
111 uint64_t startTimeSnap,
112 uint64_t endTimeSnap)
113 {
114 uint64_t dur = 0;
115 uint64_t splitStartTime = startTime * TIME_SECOND_COVER;
116 uint32_t sample = std::numeric_limits<uint32_t>::max();
117 json filteredSamples = nlohmann::json::array();
118 json filteredTimeDeltas = nlohmann::json::array();
119 startTimeSnap = streamFilters_->clockFilter_->Convert(TS_CLOCK_BOOTTIME, startTimeSnap, TS_MONOTONIC);
120 endTimeSnap = streamFilters_->clockFilter_->Convert(TS_CLOCK_BOOTTIME, endTimeSnap, TS_MONOTONIC);
121 for (size_t i = 0; i < jMessage.at("samples").size(); i++) {
122 if (traceDataCache_->isSplitFile_ && i < jMessage.at("timeDeltas").size()) {
123 uint64_t splitTimeDeltas = jMessage.at("timeDeltas")[i];
124 splitTimeDeltas = splitTimeDeltas * TIME_SECOND_COVER;
125 uint64_t timeSnap = splitStartTime + splitTimeDeltas;
126 if (timeSnap >= startTimeSnap && timeSnap <= endTimeSnap) {
127 filteredSamples.push_back(jMessage.at("samples")[i]);
128 filteredTimeDeltas.push_back(jMessage.at("timeDeltas")[i]);
129 if (startTime_ == INVALID_UINT64) {
130 startTime_ = splitStartTime;
131 }
132 }
133 splitStartTime = timeSnap;
134 continue;
135 }
136 if (sample != std::numeric_limits<uint32_t>::max() && sample != jMessage.at("samples")[i]) {
137 // Process sample data, calculate duration and update time range based on conditions, and attach parsed data
138 // to JsCpuProfiler sample data
139 DataProcessing(jMessage, sampleEndTime, startTime, dur, sample);
140 sample = jMessage.at("samples")[i];
141 } else if (sample == std::numeric_limits<uint32_t>::max()) {
142 sample = jMessage.at("samples")[0];
143 }
144 if (i + 1 < jMessage.at("timeDeltas").size()) {
145 uint32_t timeDeltas = jMessage.at("timeDeltas")[i + 1];
146 sampleEndTime += timeDeltas;
147 }
148 }
149 updatedJson_["samples"] = filteredSamples;
150 updatedJson_["timeDeltas"] = filteredTimeDeltas;
151 updatedJson_["startTime"] = startTime_ / TIME_SECOND_COVER;
152 startTime_ = INVALID_UINT64;
153 return sample;
154 }
155
ParseJsCpuProfiler(std::string result,uint64_t startTimeSnap,uint64_t endTimeSnap)156 void HtraceJsCpuProfilerParser::ParseJsCpuProfiler(std::string result, uint64_t startTimeSnap, uint64_t endTimeSnap)
157 {
158 if (result.empty()) {
159 return;
160 }
161 json jMessage = json::parse(result);
162 if (traceDataCache_->isSplitFile_) {
163 for (auto item : jMessage.items()) {
164 if (item.key() != "samples" && item.key() != "timeDeltas") {
165 updatedJson_[item.key()] = item.value();
166 }
167 }
168 }
169 ParseNodeData(jMessage);
170 uint64_t startTime = jMessage.at("startTime");
171 uint64_t sampleEndTime = startTime;
172 uint32_t sample = ParseSampleData(jMessage, sampleEndTime, startTime, startTimeSnap, endTimeSnap);
173 uint64_t dur = (sampleEndTime * TIME_SECOND_COVER) - (startTime * TIME_SECOND_COVER);
174 auto startNewTime = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_MONOTONIC, startTime * TIME_SECOND_COVER);
175 UpdatePluginTimeRange(TS_MONOTONIC, startNewTime, startNewTime);
176 auto endNewTime = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_MONOTONIC, sampleEndTime * TIME_SECOND_COVER);
177 UpdatePluginTimeRange(TS_MONOTONIC, endNewTime, endNewTime);
178 if (!traceDataCache_->isSplitFile_) {
179 (void)traceDataCache_->GetJsCpuProfilerSampleData()->AppendNewData(sample, startNewTime, endNewTime, dur);
180 }
181 }
182 } // namespace TraceStreamer
183 } // namespace SysTuning
184