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,TraceFileType fileType)29 BytraceParser::BytraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters, TraceFileType fileType)
30 : ParserBase(filters),
31 fileType_(fileType),
32 traceDataCache_(dataCache),
33 eventParser_(std::make_unique<BytraceEventParser>(dataCache, filters)),
34 hilogParser_(std::make_unique<BytraceHilogParser>(dataCache, filters)),
35 hiSysEventParser_(std::make_unique<BytraceHiSysEventParser>(dataCache, filters))
36 {
37 if (traceDataCache_->supportThread_) {
38 dataSegArray_ = std::make_unique<DataSegment[]>(maxSegArraySize);
39 } else {
40 dataSegArray_ = std::make_unique<DataSegment[]>(1);
41 }
42 }
43
44 BytraceParser::~BytraceParser() = default;
45
WaitForParserEnd()46 void BytraceParser::WaitForParserEnd()
47 {
48 if (parseThreadStarted_ || filterThreadStarted_) {
49 toExit_ = true;
50 while (!exited_) {
51 usleep(sleepDur_ * sleepDur_);
52 }
53 }
54 eventParser_->FilterAllEvents();
55 eventParser_->Clear();
56 hilogParser_->FilterAllHilogData();
57 hiSysEventParser_->Finish();
58 traceDataCache_->MixTraceTime(traceDataCache_->traceStartTime_, traceDataCache_->traceEndTime_);
59 dataSegArray_.reset();
60 ClearByTraceData();
61 }
UpdateSplitPos()62 bool BytraceParser::UpdateSplitPos()
63 {
64 maxSplitPos_ = mTraceDataBytrace_.size() - 1;
65 TS_CHECK_TRUE_RET(minSplitPos_ == INVALID_INT32, true);
66 minSplitPos_ = mTraceDataBytrace_.size() - 1;
67 TS_LOGI("minSplitPos_=%d", minSplitPos_);
68 return true;
69 }
70
71 template <typename Iterator>
WhileDetermine(Iterator & packagesLine,Iterator & packagesBegin,bool & isParsingOver_,bool isFinish)72 int32_t BytraceParser::WhileDetermine(Iterator& packagesLine,
73 Iterator& packagesBegin,
74 bool& isParsingOver_,
75 bool isFinish)
76 {
77 // While loop break and continue
78 if (packagesLine == packagesBuffer_.end()) {
79 if (isFinish) {
80 isParsingOver_ = true;
81 } else {
82 return 1;
83 }
84 }
85 if (packagesLine == packagesBuffer_.begin()) {
86 packagesLine++;
87 curFileOffset_ += std::distance(packagesBegin, packagesLine);
88 packagesBegin = packagesLine;
89 return DETERMINE_CONTINUE;
90 }
91 return DETERMINE_RETURN;
92 }
93
GotoDetermine(std::string & bufferLine,bool & haveSplitSeg)94 int32_t BytraceParser::GotoDetermine(std::string& bufferLine, bool& haveSplitSeg)
95 {
96 if (traceDataCache_->isSplitFile_) {
97 mTraceDataBytrace_.emplace_back(curFileOffset_, curDataSize_);
98 }
99 if (isFirstLine_) {
100 isFirstLine_ = false;
101 if (IsHtmlTrace(bufferLine)) {
102 isHtmlTrace_ = true;
103 return 1;
104 }
105 }
106 if (isHtmlTrace_) {
107 if (!isHtmlTraceContent_) {
108 if (IsHtmlTraceBegin(bufferLine)) {
109 isHtmlTraceContent_ = true;
110 }
111 return 1;
112 }
113 auto pos = bufferLine.find(script_.c_str());
114 if (pos != std::string::npos) {
115 isHtmlTraceContent_ = false;
116 bufferLine = bufferLine.substr(0, pos);
117 if (std::all_of(bufferLine.begin(), bufferLine.end(), isspace)) {
118 return 1;
119 }
120 }
121 }
122 if (IsTraceComment(bufferLine)) {
123 traceCommentLines_++;
124 mTraceDataBytrace_.clear();
125 return 1;
126 }
127 if (bufferLine.empty()) {
128 parsedTraceInvalidLines_++;
129 return 1;
130 }
131 if (fileType_ == TRACE_FILETYPE_HILOG) {
132 hilogParser_->ParseHilogDataItem(bufferLine, seq_, haveSplitSeg);
133 } else if (fileType_ == TRACE_FILETYPE_HI_SYSEVENT) {
134 hiSysEventParser_->ParseHiSysEventDataItem(bufferLine, seq_, haveSplitSeg);
135 } else if (isBytrace_) {
136 if (!traceBegan_) {
137 traceBegan_ = true;
138 }
139 ParseTraceDataItem(bufferLine);
140 }
141 return DETERMINE_RETURN;
142 }
143
ParseTraceDataSegment(std::unique_ptr<uint8_t[]> bufferStr,size_t size,bool isFinish)144 void BytraceParser::ParseTraceDataSegment(std::unique_ptr<uint8_t[]> bufferStr, size_t size, bool isFinish)
145 {
146 if (isParsingOver_) {
147 return;
148 }
149 packagesBuffer_.insert(packagesBuffer_.end(), &bufferStr[0], &bufferStr[size]);
150 auto packagesBegin = packagesBuffer_.begin();
151 while (true) {
152 auto packagesLine = std::find(packagesBegin, packagesBuffer_.end(), '\n');
153 int32_t determine = WhileDetermine(packagesLine, packagesBegin, isParsingOver_, isFinish);
154 if (1 == determine) {
155 break;
156 } else if (DETERMINE_CONTINUE == determine) {
157 continue;
158 }
159 // Support parsing windows file format(ff=dos)
160 auto extra = 0;
161 if (packagesLine != packagesBuffer_.end() && *(packagesLine - 1) == '\r') {
162 extra = 1;
163 }
164 bool haveSplitSeg = false;
165 std::string bufferLine(packagesBegin, packagesLine - extra);
166 curDataSize_ = std::distance(packagesBegin, packagesLine) + 1;
167 int32_t op = GotoDetermine(bufferLine, haveSplitSeg);
168 if (1 == op) {
169 goto NEXT_LINE;
170 }
171 if (haveSplitSeg) {
172 UpdateSplitPos();
173 }
174 NEXT_LINE:
175 if (isParsingOver_) {
176 break;
177 }
178 curFileOffset_ += curDataSize_;
179 packagesBegin = packagesLine + 1;
180 seq_++;
181 continue;
182 }
183 if (isParsingOver_) {
184 packagesBuffer_.clear();
185 } else {
186 packagesBuffer_.erase(packagesBuffer_.begin(), packagesBegin);
187 }
188 return;
189 }
190
ParseTraceDataItem(const std::string & buffer)191 void BytraceParser::ParseTraceDataItem(const std::string& buffer)
192 {
193 if (!traceDataCache_->supportThread_ || traceDataCache_->isSplitFile_) {
194 dataSegArray_[rawDataHead_].seg = std::move(buffer);
195 ParserData(dataSegArray_[rawDataHead_]);
196 return;
197 }
198 int32_t head = rawDataHead_;
199 while (!toExit_) {
200 if (dataSegArray_[head].status.load() != TS_PARSE_STATUS_INIT) {
201 TS_LOGD("rawDataHead_:\t%d, parseHead_:\t%d, filterHead_:\t%d status:\t%d\n", rawDataHead_, parseHead_,
202 filterHead_, dataSegArray_[head].status.load());
203 usleep(sleepDur_);
204 continue;
205 }
206 dataSegArray_[head].seg = std::move(buffer);
207 dataSegArray_[head].status = TS_PARSE_STATUS_SEPRATED;
208 rawDataHead_ = (rawDataHead_ + 1) % maxSegArraySize;
209 break;
210 }
211 if (!parseThreadStarted_) {
212 parseThreadStarted_ = true;
213 int32_t tmp = traceDataCache_->parserThreadNum_;
214 while (tmp--) {
215 parserThreadCount_++;
216 std::thread MatchLineThread(&BytraceParser::ParseThread, this);
217 MatchLineThread.detach();
218 TS_LOGI("parser Thread:%d/%d start working ...\n", traceDataCache_->parserThreadNum_ - tmp,
219 traceDataCache_->parserThreadNum_);
220 }
221 }
222 if (!filterThreadStarted_) {
223 filterThreadStarted_ = true;
224 std::thread ParserThread(&BytraceParser::FilterThread, this);
225 ParserThread.detach();
226 }
227 return;
228 }
GetNextSegment()229 int32_t BytraceParser::GetNextSegment()
230 {
231 int32_t head;
232 std::lock_guard<std::mutex> muxLockGuard(dataSegMux_);
233 head = parseHead_;
234 DataSegment& seg = dataSegArray_[head];
235 if (seg.status.load() != TS_PARSE_STATUS_SEPRATED) {
236 if (toExit_) {
237 parserThreadCount_--;
238 TS_LOGI("exiting parser, parserThread Count:%d\n", parserThreadCount_);
239 if (!parserThreadCount_ && !filterThreadStarted_) {
240 exited_ = true;
241 }
242 return ERROR_CODE_EXIT;
243 }
244 TS_LOGD("ParseThread watting:\t%d, parseHead_:\t%d, filterHead_:\t%d status:\t%d\n", rawDataHead_, parseHead_,
245 filterHead_, seg.status.load());
246 usleep(sleepDur_);
247 return ERROR_CODE_NODATA;
248 }
249 parseHead_ = (parseHead_ + 1) % maxSegArraySize;
250 seg.status = TS_PARSE_STATUS_PARSING;
251 return head;
252 }
253
GetDataSegAttr(DataSegment & seg,const std::smatch & matcheLine) const254 void BytraceParser::GetDataSegAttr(DataSegment& seg, const std::smatch& matcheLine) const
255 {
256 const uint64_t S_TO_NS = 1e9;
257 size_t index = 0;
258 std::string pidStr = matcheLine[++index].str();
259 std::optional<uint32_t> optionalPid = base::StrToInt<uint32_t>(pidStr);
260 if (!optionalPid.has_value()) {
261 TS_LOGD("Illegal pid: %s", pidStr.c_str());
262 seg.status = TS_PARSE_STATUS_INVALID;
263 return;
264 }
265
266 std::string tGidStr = matcheLine[++index].str();
267 std::string cpuStr = matcheLine[++index].str();
268 std::optional<uint32_t> optionalCpu = base::StrToInt<uint32_t>(cpuStr);
269 if (!optionalCpu.has_value()) {
270 TS_LOGD("Illegal cpu %s", cpuStr.c_str());
271 seg.status = TS_PARSE_STATUS_INVALID;
272 return;
273 }
274 std::string timeStr = matcheLine[++index].str();
275 // Directly parsing double may result in accuracy loss issues
276 std::optional<double> optionalTime = base::StrToDouble(timeStr);
277 if (!optionalTime.has_value()) {
278 TS_LOGD("Illegal ts %s", timeStr.c_str());
279 seg.status = TS_PARSE_STATUS_INVALID;
280 return;
281 }
282 std::string eventName = matcheLine[++index].str();
283 seg.bufLine.task = StrTrim(matcheLine.prefix());
284 if (seg.bufLine.task == "<...>") {
285 seg.bufLine.task = "";
286 }
287 seg.bufLine.argsStr = StrTrim(matcheLine.suffix());
288 seg.bufLine.pid = optionalPid.value();
289 seg.bufLine.cpu = optionalCpu.value();
290 seg.bufLine.ts = optionalTime.value() * S_TO_NS;
291 seg.bufLine.tGidStr = tGidStr;
292 seg.bufLine.eventName = eventName;
293 seg.status = TS_PARSE_STATUS_PARSED;
294 }
ParseThread()295 void BytraceParser::ParseThread()
296 {
297 while (true) {
298 int32_t head = GetNextSegment();
299 if (head < 0) {
300 if (head == ERROR_CODE_NODATA) {
301 continue;
302 }
303 if (!filterThreadStarted_) {
304 exited_ = true;
305 }
306 return;
307 }
308 DataSegment& seg = dataSegArray_[head];
309 ParserData(seg);
310 }
311 }
312
ParserData(DataSegment & seg)313 void BytraceParser::ParserData(DataSegment& seg)
314 {
315 std::smatch matcheLine;
316 if (!std::regex_search(seg.seg, matcheLine, bytraceMatcher_)) {
317 TS_LOGD("Not support this event (line: %s)", seg.seg.c_str());
318 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID);
319 seg.status = TS_PARSE_STATUS_INVALID;
320 parsedTraceInvalidLines_++;
321 return;
322 } else {
323 parsedTraceValidLines_++;
324 }
325 GetDataSegAttr(seg, matcheLine);
326 if (traceDataCache_->isSplitFile_) {
327 if (seg.bufLine.ts >= traceDataCache_->SplitFileMinTime() &&
328 seg.bufLine.ts <= traceDataCache_->SplitFileMaxTime()) {
329 UpdateSplitPos();
330 }
331 return;
332 }
333
334 if (!traceDataCache_->supportThread_) {
335 FilterData(seg);
336 return;
337 }
338 }
FilterThread()339 void BytraceParser::FilterThread()
340 {
341 while (true) {
342 DataSegment& seg = dataSegArray_[filterHead_];
343 if (!FilterData(seg)) {
344 return;
345 }
346 }
347 }
FilterData(DataSegment & seg)348 bool BytraceParser::FilterData(DataSegment& seg)
349 {
350 if (!traceDataCache_->supportThread_ || traceDataCache_->isSplitFile_) {
351 if (seg.status.load() != TS_PARSE_STATUS_INVALID) {
352 eventParser_->ParseDataItem(seg.bufLine);
353 seg.status = TS_PARSE_STATUS_INIT;
354 return true;
355 }
356 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID);
357 return false;
358 }
359 if (seg.status.load() == TS_PARSE_STATUS_INVALID) {
360 filterHead_ = (filterHead_ + 1) % maxSegArraySize;
361 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID);
362 seg.status = TS_PARSE_STATUS_INIT;
363 return true;
364 }
365 if (seg.status.load() != TS_PARSE_STATUS_PARSED) {
366 if (toExit_ && !parserThreadCount_) {
367 TS_LOGI("exiting FilterThread Thread\n");
368 exited_ = true;
369 filterThreadStarted_ = false;
370 return false;
371 }
372 usleep(sleepDur_);
373 return true;
374 }
375 eventParser_->ParseDataItem(seg.bufLine);
376 filterHead_ = (filterHead_ + 1) % maxSegArraySize;
377 seg.status = TS_PARSE_STATUS_INIT;
378 return true;
379 }
380 // Remove space at the beginning and end of the string
StrTrim(const std::string & input) const381 std::string BytraceParser::StrTrim(const std::string& input) const
382 {
383 std::string str = input;
384 if (str.empty()) {
385 return str;
386 }
387 str.erase(0, str.find_first_not_of(" "));
388 str.erase(str.find_last_not_of(" ") + 1);
389 return str;
390 }
391 } // namespace TraceStreamer
392 } // namespace SysTuning
393