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 #include "print_event_parser.h"
16 #include "stat_filter.h"
17 #include "string_to_numerical.h"
18 namespace SysTuning {
19 namespace TraceStreamer {
PrintEventParser(TraceDataCache * dataCache,const TraceStreamerFilters * filter)20 PrintEventParser::PrintEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter)
21 : EventParserBase(dataCache, filter),
22 pointLength_(1),
23 maxPointLength_(2)
24 {
25 }
26
ParsePrintEvent(const std::string & comm,uint64_t ts,uint32_t pid,std::string_view event)27 bool PrintEventParser::ParsePrintEvent(const std::string& comm, uint64_t ts, uint32_t pid, std::string_view event)
28 {
29 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_RECEIVED);
30 TracePoint point;
31 if (GetTracePoint(event, point) != SUCCESS) {
32 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_DATA_INVALID);
33 return false;
34 }
35 if (point.tgid_) {
36 streamFilters_->processFilter_->GetOrCreateInternalPid(ts, point.tgid_);
37 }
38 uint32_t index = 0;
39 switch (point.phase_) {
40 case 'B': {
41 index = streamFilters_->sliceFilter_->BeginSlice(comm, ts, pid, point.tgid_, INVALID_DATAINDEX,
42 traceDataCache_->GetDataIndex(point.name_));
43 if (index != INVALID_UINT32) {
44 // add distributed data
45 traceDataCache_->GetInternalSlicesData()->SetDistributeInfo(
46 index, point.chainId_, point.spanId_, point.parentSpanId_, point.flag_, point.args_);
47 } else {
48 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_DATA_LOST);
49 }
50 break;
51 }
52 case 'E': {
53 streamFilters_->sliceFilter_->EndSlice(ts, pid, point.tgid_);
54 break;
55 }
56 case 'S': {
57 auto cookie = static_cast<uint64_t>(point.value_);
58 streamFilters_->sliceFilter_->StartAsyncSlice(ts, pid, point.tgid_, cookie,
59 traceDataCache_->GetDataIndex(point.name_));
60 break;
61 }
62 case 'F': {
63 auto cookie = static_cast<uint64_t>(point.value_);
64 streamFilters_->sliceFilter_->FinishAsyncSlice(ts, pid, point.tgid_, cookie,
65 traceDataCache_->GetDataIndex(point.name_));
66 break;
67 }
68 case 'C': {
69 DataIndex nameIndex = traceDataCache_->GetDataIndex(point.name_);
70 uint32_t internalPid = streamFilters_->processFilter_->GetInternalPid(point.tgid_);
71 if (internalPid != INVALID_ID) {
72 streamFilters_->processMeasureFilter_->AppendNewMeasureData(internalPid, nameIndex, ts, point.value_);
73 } else {
74 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_DATA_INVALID);
75 }
76 break;
77 }
78 default:
79 TS_LOGD("point missing!");
80 return false;
81 }
82 return true;
83 }
84
CheckTracePoint(std::string_view pointStr) const85 ParseResult PrintEventParser::CheckTracePoint(std::string_view pointStr) const
86 {
87 if (pointStr.size() == 0) {
88 TS_LOGD("get trace point data size is 0!");
89 return ERROR;
90 }
91
92 std::string clockSyncSts = "trace_event_clock_sync";
93 if (pointStr.compare(0, clockSyncSts.length(), clockSyncSts.c_str()) == 0) {
94 TS_LOGD("skip trace point :%s!", clockSyncSts.c_str());
95 return ERROR;
96 }
97
98 if (pointStr.find_first_of('B') != 0 && pointStr.find_first_of('E') != 0 && pointStr.find_first_of('C') != 0 &&
99 pointStr.find_first_of('S') != 0 && pointStr.find_first_of('F') != 0) {
100 TS_LOGD("trace point not supported : [%c] !", pointStr[0]);
101 return ERROR;
102 }
103
104 if (pointStr.find_first_of('E') != 0 && pointStr.size() == 1) {
105 TS_LOGD("point string size error!");
106 return ERROR;
107 }
108
109 if (pointStr.size() >= maxPointLength_) {
110 if ((pointStr[1] != '|') && (pointStr[1] != '\n')) {
111 TS_LOGD("not support data formart!");
112 return ERROR;
113 }
114 }
115
116 return SUCCESS;
117 }
118
GetPointNameForBegin(std::string_view pointStr,size_t tGidlength) const119 std::string_view PrintEventParser::GetPointNameForBegin(std::string_view pointStr, size_t tGidlength) const
120 {
121 size_t index = maxPointLength_ + tGidlength + pointLength_;
122
123 size_t length = pointStr.size() - index - ((pointStr.back() == '\n') ? 1 : 0);
124 std::string_view name = std::string_view(pointStr.data() + index, length);
125 return name;
126 }
127
HandlerB(std::string_view pointStr,TracePoint & outPoint,size_t tGidlength) const128 ParseResult PrintEventParser::HandlerB(std::string_view pointStr, TracePoint& outPoint, size_t tGidlength) const
129 {
130 outPoint.name_ = GetPointNameForBegin(pointStr, tGidlength);
131 if (outPoint.name_.empty()) {
132 TS_LOGD("point name is empty!");
133 return ERROR;
134 }
135 // Use $# to differentiate distributed data
136 if (outPoint.name_.find("$#") == std::string::npos) {
137 return SUCCESS;
138 }
139 // Resolve distributed calls
140 // the normal data mybe like:
141 // system-1298 ( 1298) [001] ...1 174330.287420: tracing_mark_write: B|1298|[8b00e96b2,2,1]:C$#decodeFrame$#"
142 // "{\"Process\":\"DecodeVideoFrame\",\"frameTimestamp\":37313484466} \
143 // system - 1298(1298)[001]... 1 174330.287622 : tracing_mark_write : E | 1298 \n
144 const std::regex distributeMatcher =
145 std::regex(R"((?:^\[([a-z0-9]+),(\d+),(\d+)\]:?([CS]?)\$#)?(.*)\$#(.*)$)");
146 std::smatch matcheLine;
147 bool matched = std::regex_match(outPoint.name_, matcheLine, distributeMatcher);
148 if (matched) {
149 size_t index = 0;
150 outPoint.chainId_ = matcheLine[++index].str();
151 outPoint.spanId_ = matcheLine[++index].str();
152 outPoint.parentSpanId_ = matcheLine[++index].str();
153 outPoint.flag_ = matcheLine[++index].str();
154 outPoint.name_ = matcheLine[++index].str();
155 outPoint.args_ = matcheLine[++index].str();
156 }
157 return SUCCESS;
158 }
159
HandlerE(void)160 ParseResult PrintEventParser::HandlerE(void)
161 {
162 return SUCCESS;
163 }
164
GetNameLength(std::string_view pointStr,size_t nameIndex)165 size_t PrintEventParser::GetNameLength(std::string_view pointStr, size_t nameIndex)
166 {
167 size_t namelength = 0;
168 for (size_t i = nameIndex; i < pointStr.size(); i++) {
169 if (pointStr[i] == ' ') {
170 namelength = i - nameIndex;
171 }
172 if (pointStr[i] == '|') {
173 namelength = i - nameIndex;
174 break;
175 }
176 }
177 return namelength;
178 }
179
GetValueLength(std::string_view pointStr,size_t valueIndex) const180 size_t PrintEventParser::GetValueLength(std::string_view pointStr, size_t valueIndex) const
181 {
182 size_t valuePipe = pointStr.find('|', valueIndex);
183 size_t valueLen = pointStr.size() - valueIndex;
184 if (valuePipe != std::string_view::npos) {
185 valueLen = valuePipe - valueIndex;
186 }
187
188 if (valueLen == 0) {
189 return 0;
190 }
191
192 if (pointStr[valueIndex + valueLen - pointLength_] == '\n') {
193 valueLen--;
194 }
195
196 return valueLen;
197 }
198
HandlerCSF(std::string_view pointStr,TracePoint & outPoint,size_t tGidlength) const199 ParseResult PrintEventParser::HandlerCSF(std::string_view pointStr, TracePoint& outPoint, size_t tGidlength) const
200 {
201 // point name
202 size_t nameIndex = maxPointLength_ + tGidlength + pointLength_;
203 size_t namelength = GetNameLength(pointStr, nameIndex);
204 if (namelength == 0) {
205 TS_LOGD("point name length is error!");
206 return ERROR;
207 }
208 outPoint.name_ = std::string_view(pointStr.data() + nameIndex, namelength);
209
210 // point value
211 size_t valueIndex = nameIndex + namelength + pointLength_;
212 size_t valueLen = GetValueLength(pointStr, valueIndex);
213 if (valueLen == 0) {
214 TS_LOGD("point value length is error!");
215 return ERROR;
216 }
217
218 std::string valueStr(pointStr.data() + valueIndex, valueLen);
219 if (!base::StrToUInt64(valueStr).has_value()) {
220 TS_LOGD("point value is error!");
221 return ERROR;
222 }
223 outPoint.value_ = base::StrToUInt64(valueStr).value();
224
225 size_t valuePipe = pointStr.find('|', valueIndex);
226 if (valuePipe != std::string_view::npos) {
227 size_t groupLen = pointStr.size() - valuePipe - pointLength_;
228 if (groupLen == 0) {
229 return ERROR;
230 }
231
232 if (pointStr[pointStr.size() - pointLength_] == '\n') {
233 groupLen--;
234 }
235
236 outPoint.categoryGroup_ = std::string_view(pointStr.data() + valuePipe + 1, groupLen);
237 }
238
239 return SUCCESS;
240 }
241
GetTracePoint(std::string_view pointStr,TracePoint & outPoint) const242 ParseResult PrintEventParser::GetTracePoint(std::string_view pointStr, TracePoint& outPoint) const
243 {
244 if (CheckTracePoint(pointStr) != SUCCESS) {
245 return ERROR;
246 }
247
248 size_t tGidlength = 0;
249 // we may get wrong format data like tracing_mark_write: E
250 // while the format data must be E|call-tid
251 // please use a regular-format to get all the data
252 outPoint.phase_ = pointStr.front();
253 outPoint.tgid_ = GetThreadGroupId(pointStr, tGidlength);
254
255 ParseResult ret = ERROR;
256 switch (outPoint.phase_) {
257 case 'B': {
258 ret = HandlerB(pointStr, outPoint, tGidlength);
259 break;
260 }
261 case 'E': {
262 ret = HandlerE();
263 break;
264 }
265 case 'S':
266 case 'F':
267 case 'C': {
268 ret = HandlerCSF(pointStr, outPoint, tGidlength);
269 break;
270 }
271 default:
272 return ERROR;
273 }
274 return ret;
275 }
276
GetThreadGroupId(std::string_view pointStr,size_t & length) const277 uint32_t PrintEventParser::GetThreadGroupId(std::string_view pointStr, size_t& length) const
278 {
279 for (size_t i = maxPointLength_; i < pointStr.size(); i++) {
280 if (pointStr[i] == '|' || pointStr[i] == '\n') {
281 break;
282 }
283
284 if (pointStr[i] < '0' || pointStr[i] > '9') {
285 return ERROR;
286 }
287
288 length++;
289 }
290
291 std::string str(pointStr.data() + maxPointLength_, length);
292 return base::StrToUInt32(str).value_or(0);
293 }
294 } // namespace TraceStreamer
295 } // namespace SysTuning
296