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