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