• 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)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