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
16 #include "bytrace_parser.h"
17 #include <cmath>
18 #include <sstream>
19 #include <unistd.h>
20 #include "app_start_filter.h"
21 #include "binder_filter.h"
22 #include "cpu_filter.h"
23 #include "hi_sysevent_measure_filter.h"
24 #include "parting_string.h"
25 #include "stat_filter.h"
26 #include "system_event_measure_filter.h"
27 namespace SysTuning {
28 namespace TraceStreamer {
BytraceParser(TraceDataCache * dataCache,const TraceStreamerFilters * filters)29 BytraceParser::BytraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters)
30 : ParserBase(filters),
31 eventParser_(std::make_unique<BytraceEventParser>(dataCache, filters)),
32 #ifdef SUPPORTTHREAD
33 dataSegArray_(std::make_unique<DataSegment[]>(MAX_SEG_ARRAY_SIZE)),
34 supportThread_(true)
35 #else
36 dataSegArray_(std::make_unique<DataSegment[]>(1))
37 #endif
38 {
39 }
40
41 BytraceParser::~BytraceParser() = default;
42
WaitForParserEnd()43 void BytraceParser::WaitForParserEnd()
44 {
45 if (parseThreadStarted_ || filterThreadStarted_) {
46 toExit_ = true;
47 while (!exited_) {
48 usleep(sleepDur_ * sleepDur_);
49 }
50 }
51 eventParser_->FilterAllEvents();
52 eventParser_->Clear();
53 dataSegArray_.reset();
54 }
ParseTraceDataSegment(std::unique_ptr<uint8_t[]> bufferStr,size_t size)55 void BytraceParser::ParseTraceDataSegment(std::unique_ptr<uint8_t[]> bufferStr, size_t size)
56 {
57 if (isParsingOver_) {
58 return;
59 }
60 packagesBuffer_.insert(packagesBuffer_.end(), &bufferStr[0], &bufferStr[size]);
61 auto packagesBegin = packagesBuffer_.begin();
62 while (1) {
63 auto packagesLine = std::find(packagesBegin, packagesBuffer_.end(), '\n');
64 if (packagesLine == packagesBuffer_.end()) {
65 break;
66 }
67 if (packagesLine == packagesBuffer_.begin()) {
68 packagesLine++;
69 packagesBegin = packagesLine;
70 continue;
71 }
72 // Support parsing windows file format(ff=dos)
73 auto extra = *(packagesLine - 1) == '\r' ? 1 : 0;
74 std::string bufferLine(packagesBegin, packagesLine - extra);
75
76 if (isFirstLine) {
77 isFirstLine = false;
78 if (IsHtmlTrace(bufferLine)) {
79 isHtmlTrace_ = true;
80 goto NEXT_LINE;
81 }
82 }
83 if (isHtmlTrace_) {
84 if (!isHtmlTraceContent_) {
85 if (IsHtmlTraceBegin(bufferLine)) {
86 isHtmlTraceContent_ = true;
87 }
88 goto NEXT_LINE;
89 }
90 auto pos = bufferLine.find(script_.c_str());
91 if (pos != std::string::npos) {
92 isHtmlTraceContent_ = false;
93 bufferLine = bufferLine.substr(0, pos);
94 if (std::all_of(bufferLine.begin(), bufferLine.end(), isspace)) {
95 goto NEXT_LINE;
96 }
97 }
98 }
99
100 if (IsTraceComment(bufferLine)) {
101 traceCommentLines_++;
102 goto NEXT_LINE;
103 }
104 if (bufferLine.empty()) {
105 parsedTraceInvalidLines_++;
106 goto NEXT_LINE;
107 }
108
109 if (isBytrace_) {
110 if (!traceBegan_) {
111 traceBegan_ = true;
112 }
113 ParseTraceDataItem(bufferLine);
114 } else {
115 ParseJsonData(bufferLine);
116 }
117
118 NEXT_LINE:
119 packagesBegin = packagesLine + 1;
120 continue;
121 }
122
123 if (isParsingOver_) {
124 packagesBuffer_.clear();
125 } else {
126 packagesBuffer_.erase(packagesBuffer_.begin(), packagesBegin);
127 }
128 return;
129 }
130
AppendJsonDataToHiSysEventNewValue(JsonData jData,int32_t jIndex,DataIndex eventSourceIndex)131 inline void BytraceParser::AppendJsonDataToHiSysEventNewValue(JsonData jData,
132 int32_t jIndex,
133 DataIndex eventSourceIndex)
134 {
135 auto value = jData.value[jIndex];
136 std::string key = jData.key[jIndex];
137 streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex);
138 DataIndex keyIndex = eventParser_->traceDataCache_->GetDataIndex(key);
139 if (value.is_string()) {
140 std::string strValue = value;
141 DataIndex valueIndex = eventParser_->traceDataCache_->GetDataIndex(strValue);
142 streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex, 1, 0,
143 valueIndex);
144 } else {
145 DataIndex valueIndex = value;
146 streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex, 0,
147 valueIndex, 0);
148 }
149 }
150
NoArrayDataParse(JsonData jData,std::vector<size_t> noArrayIndex,DataIndex eventSourceIndex)151 inline void BytraceParser::NoArrayDataParse(JsonData jData,
152 std::vector<size_t> noArrayIndex,
153 DataIndex eventSourceIndex)
154 {
155 for (auto itor = noArrayIndex.begin(); itor != noArrayIndex.end(); itor++) {
156 AppendJsonDataToHiSysEventNewValue(jData, *itor, eventSourceIndex);
157 }
158 }
ArrayDataParse(JsonData jData,std::vector<size_t> arrayIndex,DataIndex eventSourceIndex,size_t maxArraySize)159 void BytraceParser::ArrayDataParse(JsonData jData,
160 std::vector<size_t> arrayIndex,
161 DataIndex eventSourceIndex,
162 size_t maxArraySize)
163 {
164 for (int32_t j = 0; j < maxArraySize; j++) {
165 for (auto itor = arrayIndex.begin(); itor != arrayIndex.end(); itor++) {
166 auto value = jData.value[*itor][j];
167 std::string key = jData.key[*itor];
168 DataIndex keyIndex = eventParser_->traceDataCache_->GetDataIndex(key);
169 streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex);
170 if (value.is_number()) {
171 DataIndex valueIndex = value;
172 streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex,
173 0, valueIndex, 0);
174 } else if (value.is_string()) {
175 std::string strValue = value;
176 DataIndex valueIndex = eventParser_->traceDataCache_->GetDataIndex(strValue);
177 streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex,
178 1, 0, valueIndex);
179 }
180 }
181 }
182 }
183
CommonDataParser(JsonData jData,DataIndex eventSourceIndex)184 inline void BytraceParser::CommonDataParser(JsonData jData, DataIndex eventSourceIndex)
185 {
186 for (int32_t j = 0; j < jData.key.size(); j++) {
187 AppendJsonDataToHiSysEventNewValue(jData, j, eventSourceIndex);
188 }
189 }
190
ParseJsonData(const std::string & buffer)191 void BytraceParser::ParseJsonData(const std::string& buffer)
192 {
193 std::stringstream ss;
194 json jMessage;
195 ss << buffer;
196 ss >> jMessage;
197 JsonData jData;
198 size_t maxArraySize = 0;
199 std::vector<size_t> noArrayIndex = {};
200 std::vector<size_t> arrayIndex = {};
201 if (!streamFilters_->hiSysEventMeasureFilter_->JGetData(jMessage, jData, maxArraySize, noArrayIndex, arrayIndex)) {
202 return;
203 }
204 DataIndex eventSourceIndex = eventParser_->traceDataCache_->GetDataIndex(jData.eventSource);
205 if (maxArraySize) {
206 NoArrayDataParse(jData, noArrayIndex, eventSourceIndex);
207 ArrayDataParse(jData, arrayIndex, eventSourceIndex, maxArraySize);
208 } else {
209 CommonDataParser(jData, eventSourceIndex);
210 }
211 return;
212 }
ParseTraceDataItem(const std::string & buffer)213 void BytraceParser::ParseTraceDataItem(const std::string& buffer)
214 {
215 if (!supportThread_) {
216 dataSegArray_[rawDataHead_].seg = std::move(buffer);
217 ParserData(dataSegArray_[rawDataHead_]);
218 return;
219 }
220 int32_t head = rawDataHead_;
221 while (!toExit_) {
222 if (dataSegArray_[head].status.load() != TS_PARSE_STATUS_INIT) {
223 TS_LOGD("rawDataHead_:\t%d, parseHead_:\t%d, filterHead_:\t%d status:\t%d\n", rawDataHead_, parseHead_,
224 filterHead_, dataSegArray_[head].status.load());
225 usleep(sleepDur_);
226 continue;
227 }
228 dataSegArray_[head].seg = std::move(buffer);
229 dataSegArray_[head].status = TS_PARSE_STATUS_SEPRATED;
230 rawDataHead_ = (rawDataHead_ + 1) % MAX_SEG_ARRAY_SIZE;
231 break;
232 }
233 if (!parseThreadStarted_) {
234 parseThreadStarted_ = true;
235 int32_t tmp = maxThread_;
236 while (tmp--) {
237 parserThreadCount_++;
238 std::thread MatchLineThread(&BytraceParser::ParseThread, this);
239 MatchLineThread.detach();
240 TS_LOGI("parser Thread:%d/%d start working ...\n", maxThread_ - tmp, maxThread_);
241 }
242 }
243 return;
244 }
GetNextSegment()245 int32_t BytraceParser::GetNextSegment()
246 {
247 int32_t head;
248 dataSegMux_.lock();
249 head = parseHead_;
250 DataSegment& seg = dataSegArray_[head];
251 if (seg.status.load() != TS_PARSE_STATUS_SEPRATED) {
252 if (toExit_) {
253 parserThreadCount_--;
254 TS_LOGI("exiting parser, parserThread Count:%d\n", parserThreadCount_);
255 dataSegMux_.unlock();
256 if (!parserThreadCount_ && !filterThreadStarted_) {
257 exited_ = true;
258 }
259 return ERROR_CODE_EXIT;
260 }
261 if (seg.status.load() == TS_PARSE_STATUS_PARSING) {
262 dataSegMux_.unlock();
263 usleep(sleepDur_);
264 return ERROR_CODE_NODATA;
265 }
266 dataSegMux_.unlock();
267 TS_LOGD("ParseThread watting:\t%d, parseHead_:\t%d, filterHead_:\t%d status:\t%d\n", rawDataHead_, parseHead_,
268 filterHead_, seg.status.load());
269 usleep(sleepDur_);
270 return ERROR_CODE_NODATA;
271 }
272 parseHead_ = (parseHead_ + 1) % MAX_SEG_ARRAY_SIZE;
273 seg.status = TS_PARSE_STATUS_PARSING;
274 dataSegMux_.unlock();
275 return head;
276 }
277
GetDataSegAttr(DataSegment & seg,const std::smatch & matcheLine) const278 void BytraceParser::GetDataSegAttr(DataSegment& seg, const std::smatch& matcheLine) const
279 {
280 const uint64_t S_TO_NS = 1e9;
281 size_t index = 0;
282 std::string pidStr = matcheLine[++index].str();
283 std::optional<uint32_t> optionalPid = base::StrToInt<uint32_t>(pidStr);
284 if (!optionalPid.has_value()) {
285 TS_LOGD("Illegal pid: %s", pidStr.c_str());
286 seg.status = TS_PARSE_STATUS_INVALID;
287 return;
288 }
289
290 std::string tGidStr = matcheLine[++index].str();
291 std::string cpuStr = matcheLine[++index].str();
292 std::optional<uint32_t> optionalCpu = base::StrToInt<uint32_t>(cpuStr);
293 if (!optionalCpu.has_value()) {
294 TS_LOGD("Illegal cpu %s", cpuStr.c_str());
295 seg.status = TS_PARSE_STATUS_INVALID;
296 return;
297 }
298 std::string timeStr = matcheLine[++index].str();
299 // Directly parsing double may result in accuracy loss issues
300 std::optional<double> optionalTime = base::StrToDouble(timeStr);
301 if (!optionalTime.has_value()) {
302 TS_LOGD("Illegal ts %s", timeStr.c_str());
303 seg.status = TS_PARSE_STATUS_INVALID;
304 return;
305 }
306 std::string eventName = matcheLine[++index].str();
307 seg.bufLine.task = StrTrim(matcheLine.prefix());
308 if (seg.bufLine.task == "<...>") {
309 seg.bufLine.task = "";
310 }
311 seg.bufLine.argsStr = StrTrim(matcheLine.suffix());
312 seg.bufLine.pid = optionalPid.value();
313 seg.bufLine.cpu = optionalCpu.value();
314 seg.bufLine.ts = optionalTime.value() * S_TO_NS;
315 seg.bufLine.tGidStr = tGidStr;
316 seg.bufLine.eventName = eventName;
317 seg.status = TS_PARSE_STATUS_PARSED;
318 }
ParseThread()319 void BytraceParser::ParseThread()
320 {
321 while (1) {
322 int32_t head = GetNextSegment();
323 if (head < 0) {
324 if (head == ERROR_CODE_NODATA) {
325 continue;
326 }
327 if (!filterThreadStarted_) {
328 exited_ = true;
329 }
330 return;
331 }
332 DataSegment& seg = dataSegArray_[head];
333 ParserData(seg);
334 }
335 }
336
ParserData(DataSegment & seg)337 void BytraceParser::ParserData(DataSegment& seg)
338 {
339 std::smatch matcheLine;
340 if (!std::regex_search(seg.seg, matcheLine, bytraceMatcher_)) {
341 TS_LOGD("Not support this event (line: %s)", seg.seg.c_str());
342 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID);
343 seg.status = TS_PARSE_STATUS_INVALID;
344 parsedTraceInvalidLines_++;
345 return;
346 } else {
347 parsedTraceValidLines_++;
348 }
349 GetDataSegAttr(seg, matcheLine);
350 if (!supportThread_) {
351 FilterData(seg);
352 return;
353 }
354 if (!filterThreadStarted_) {
355 filterThreadStarted_ = true;
356 std::thread ParserThread(&BytraceParser::FilterThread, this);
357 ParserThread.detach();
358 }
359 }
FilterThread()360 void BytraceParser::FilterThread()
361 {
362 while (1) {
363 DataSegment& seg = dataSegArray_[filterHead_];
364 if (!FilterData(seg)) {
365 return;
366 }
367 }
368 }
FilterData(DataSegment & seg)369 bool BytraceParser::FilterData(DataSegment& seg)
370 {
371 if (!supportThread_) {
372 if (seg.status.load() != TS_PARSE_STATUS_INVALID) {
373 eventParser_->ParseDataItem(seg.bufLine);
374 seg.status = TS_PARSE_STATUS_INIT;
375 return true;
376 }
377 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID);
378 return false;
379 }
380 if (seg.status.load() == TS_PARSE_STATUS_INVALID) {
381 filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE;
382 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID);
383 seg.status = TS_PARSE_STATUS_INIT;
384 return true;
385 }
386 if (seg.status.load() != TS_PARSE_STATUS_PARSED) {
387 if (toExit_ && !parserThreadCount_) {
388 TS_LOGI("exiting FilterThread Thread\n");
389 exited_ = true;
390 filterThreadStarted_ = false;
391 return false;
392 }
393 usleep(sleepDur_);
394 return true;
395 }
396 eventParser_->ParseDataItem(seg.bufLine);
397 filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE;
398 seg.status = TS_PARSE_STATUS_INIT;
399 return true;
400 }
401 // Remove space at the beginning and end of the string
StrTrim(const std::string & input) const402 std::string BytraceParser::StrTrim(const std::string& input) const
403 {
404 std::string str = input;
405 if (str.empty()) {
406 return str;
407 }
408 str.erase(0, str.find_first_not_of(" "));
409 str.erase(str.find_last_not_of(" ") + 1);
410 return str;
411 }
412 } // namespace TraceStreamer
413 } // namespace SysTuning
414