• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "pbreader_js_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