• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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