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 #include "ftrace_processor.h"
16
17 #include <algorithm>
18 #include <cerrno>
19 #include <cinttypes>
20 #include <cstring>
21 #include <fcntl.h>
22 #include <fstream>
23 #include <regex>
24 #include <sstream>
25 #include <unistd.h>
26
27 #include "log.h"
28 #include "printk_formats_processor.h"
29 #include "securec.h"
30 #include "string_to_numerical.h"
31
32 namespace {
33 constexpr unsigned RB_MISSED_EVENTS = (1uL << 31); // Flag when events were overwritten
34 constexpr unsigned RB_MISSED_STORED = (1 << 30); // Missed count stored at end
35 constexpr unsigned RB_MISSED_FLAGS = (RB_MISSED_EVENTS | RB_MISSED_STORED);
36
37 constexpr unsigned COL_IDX_NAME = 0;
38 constexpr unsigned COL_IDX_VALUE = 1;
39
40 constexpr unsigned TS_EXT_SHIFT = 27;
41
TimestampIncrements(uint64_t ext)42 inline uint64_t TimestampIncrements(uint64_t ext)
43 {
44 return ext << TS_EXT_SHIFT;
45 }
46
ReadInfo(uint8_t * startPtr[],uint8_t * endPtr,void * outData,size_t outSize)47 bool ReadInfo(uint8_t *startPtr[], uint8_t *endPtr, void *outData, size_t outSize)
48 {
49 if ((endPtr - *startPtr) < static_cast<ptrdiff_t>(outSize)) {
50 return false;
51 }
52 if (memcpy_s(outData, outSize, *startPtr, outSize) != EOK) {
53 TS_LOGE("read %zu bytes from memory region [%p, %p) FAILED", outSize, *startPtr, endPtr);
54 return false;
55 }
56 *startPtr += outSize;
57 return true;
58 }
59 } // namespace
60
61 namespace SysTuning {
62 namespace TraceStreamer {
FtraceProcessor(TraceDataCache * traceDataCache)63 FtraceProcessor::FtraceProcessor(TraceDataCache *traceDataCache)
64 : fixedCharArrayRegex_(std::regex(R"(char \w+\[\d+\])")),
65 flexDataLocArrayRegex_(std::regex(R"(__data_loc [a-zA-Z_0-9 ]+\[\] \w+)")),
66 traceDataCache_(traceDataCache)
67 {
68 }
69
~FtraceProcessor()70 FtraceProcessor::~FtraceProcessor()
71 {
72 TS_LOGI("FtraceProcessor destroy!");
73 }
74
SetupEvent(const std::string & desc)75 bool FtraceProcessor::SetupEvent(const std::string &desc)
76 {
77 EventFormat format;
78 TS_CHECK_TRUE(HandleEventFormat(desc.data(), format), false, "HandleEventFormat failed!");
79 TS_CHECK_TRUE(FtraceEventProcessor::GetInstance().SetupEvent(format), false, "setup %s failed!",
80 format.eventName.c_str());
81 eventFormatDict_[format.eventId] = format;
82 return true;
83 }
84
GetEventFormatById(uint32_t id,EventFormat & format)85 bool FtraceProcessor::GetEventFormatById(uint32_t id, EventFormat &format)
86 {
87 auto iter = eventFormatDict_.find(id);
88 if (iter != eventFormatDict_.end()) {
89 format = iter->second;
90 return true;
91 }
92 return false;
93 }
94
HandleHeaderPageFormat(const std::string & formatInfo)95 bool FtraceProcessor::HandleHeaderPageFormat(const std::string &formatInfo)
96 {
97 EventFormat format = {};
98 TS_CHECK_TRUE(HandleEventFormat(formatInfo, format), false, "handle events/header_page failed!");
99
100 bool commitExist = false;
101 for (const auto &curField : format.fields) {
102 if (curField.name == "timestamp") {
103 pageHeaderFormat_.timestamp = curField;
104 } else if (curField.name == "commit") {
105 pageHeaderFormat_.commit = curField;
106 commitExist = true;
107 } else if (curField.name == "overwrite") {
108 pageHeaderFormat_.overwrite = curField;
109 }
110 }
111
112 TS_LOGI("page header details:");
113 PrintedFieldDetails(pageHeaderFormat_.timestamp);
114 PrintedFieldDetails(pageHeaderFormat_.commit);
115 PrintedFieldDetails(pageHeaderFormat_.overwrite);
116 TS_CHECK_TRUE(commitExist, false, "commit field not exist!");
117 return true;
118 }
119
HeaderPageCommitSize(void)120 int FtraceProcessor::HeaderPageCommitSize(void)
121 {
122 // return the size value (8B on 64bit device, 4B on 32bit device) of commit field read from events/header_page
123 const uint16_t defaultSize = 8;
124 if (pageHeaderFormat_.commit.size == 0) {
125 TS_LOGW("haven't header_page infos, set defalut size is 8B");
126 pageHeaderFormat_.commit.size = defaultSize;
127 }
128 return pageHeaderFormat_.commit.size;
129 }
130
HandleEventFormat(const std::string & formatInfo,EventFormat & format)131 bool FtraceProcessor::HandleEventFormat(const std::string &formatInfo, EventFormat &format)
132 {
133 std::string curLine;
134 std::stringstream formatStream(formatInfo);
135 while (getline(formatStream, curLine)) {
136 curLine = Strip(curLine);
137 if (curLine.empty()) {
138 continue;
139 } else if (StartWith(curLine, fieldLinePrefix_)) {
140 HandleFieldFormat(curLine, format);
141 } else if (StartWith(curLine, idLinePrefix_)) {
142 auto idStr = curLine.substr(idLinePrefix_.size() + 1);
143 format.eventId = static_cast<uint32_t>(atoi(idStr.c_str()));
144 } else if (StartWith(curLine, nameLinePrefix_)) {
145 format.eventName = curLine.substr(nameLinePrefix_.size() + 1);
146 TS_CHECK_TRUE(FtraceEventProcessor::GetInstance().IsSupported(format.eventName), false,
147 "Isn't Supported %s event!", format.eventName.data());
148 }
149 }
150
151 TS_CHECK_TRUE(format.fields.size() > 0, false, "HandleEventFormat from %s failed!", formatInfo.c_str());
152 auto lastFiledIndex = format.fields.size() - 1;
153 format.eventSize = format.fields[lastFiledIndex].offset + format.fields[lastFiledIndex].size;
154 if (format.eventId >= HM_EVENT_ID_OFFSET) {
155 for (auto &fmt : format.commonFields) {
156 fmt.offset += offsetof(struct HmTraceHeader, commonType);
157 }
158 for (auto &fmt : format.fields) {
159 fmt.offset += offsetof(struct HmTraceHeader, commonType);
160 }
161 format.eventSize += offsetof(struct HmTraceHeader, commonType);
162 }
163 return true;
164 }
165
GetName(const std::map<int,std::string> & nameMap,int type)166 static std::string GetName(const std::map<int, std::string> &nameMap, int type)
167 {
168 auto it = nameMap.find(type);
169 if (it != nameMap.end()) {
170 return it->second;
171 }
172 return "";
173 }
174
GetFieldTypeName(EventFieldType type)175 static std::string GetFieldTypeName(EventFieldType type)
176 {
177 static std::map<int, std::string> toNames = {
178 #define VALUE_NAME(x) {x, #x}
179 VALUE_NAME(FIELD_TYPE_INVALID), VALUE_NAME(FIELD_TYPE_BOOL), VALUE_NAME(FIELD_TYPE_INT8),
180 VALUE_NAME(FIELD_TYPE_UINT8), VALUE_NAME(FIELD_TYPE_INT16), VALUE_NAME(FIELD_TYPE_UINT16),
181 VALUE_NAME(FIELD_TYPE_INT32), VALUE_NAME(FIELD_TYPE_UINT32), VALUE_NAME(FIELD_TYPE_INT64),
182 VALUE_NAME(FIELD_TYPE_UINT64), VALUE_NAME(FIELD_TYPE_FIXEDCSTRING), VALUE_NAME(FIELD_TYPE_CSTRING),
183 VALUE_NAME(FIELD_TYPE_STRINGPTR), VALUE_NAME(FIELD_TYPE_INODE32), VALUE_NAME(FIELD_TYPE_INODE64),
184 VALUE_NAME(FIELD_TYPE_PID32), VALUE_NAME(FIELD_TYPE_COMMONPID32), VALUE_NAME(FIELD_TYPE_DEVID32),
185 VALUE_NAME(FIELD_TYPE_DEVID64), VALUE_NAME(FIELD_TYPE_DATALOC), VALUE_NAME(FIELD_TYPE_SYMADDR32),
186 VALUE_NAME(FIELD_TYPE_SYMADDR64),
187 #undef VALUE_NAME
188 };
189 return GetName(toNames, type);
190 }
191
GetProtoTypeName(ProtoFieldType type)192 static std::string GetProtoTypeName(ProtoFieldType type)
193 {
194 static std::map<int, std::string> toNames = {
195 #define VALUE_NAME(x) {x, #x}
196 VALUE_NAME(PROTO_TYPE_UNKNOWN), VALUE_NAME(PROTO_TYPE_DOUBLE), VALUE_NAME(PROTO_TYPE_FLOAT),
197 VALUE_NAME(PROTO_TYPE_INT64), VALUE_NAME(PROTO_TYPE_UINT64), VALUE_NAME(PROTO_TYPE_INT32),
198 VALUE_NAME(PROTO_TYPE_FIXED64), VALUE_NAME(PROTO_TYPE_FIXED32), VALUE_NAME(PROTO_TYPE_BOOL),
199 VALUE_NAME(PROTO_TYPE_STRING), VALUE_NAME(PROTO_TYPE_GROUP), VALUE_NAME(PROTO_TYPE_MESSAGE),
200 VALUE_NAME(PROTO_TYPE_BYTES), VALUE_NAME(PROTO_TYPE_UINT32), VALUE_NAME(PROTO_TYPE_ENUM),
201 VALUE_NAME(PROTO_TYPE_SFIXED32), VALUE_NAME(PROTO_TYPE_SFIXED64), VALUE_NAME(PROTO_TYPE_SINT32),
202 VALUE_NAME(PROTO_TYPE_SINT64), VALUE_NAME(PROTO_TYPE_MAX),
203 #undef VALUE_NAME
204 };
205 return GetName(toNames, type);
206 }
207
PrintedFieldDetails(const FieldFormat & info)208 void FtraceProcessor::PrintedFieldDetails(const FieldFormat &info)
209 {
210 TS_LOGI(
211 "FieldFormat { offset: %u, size:%u, sign: %u fieldType: %s, "
212 "protoType:%s, typeName: %s, name: %s}",
213 info.offset, info.size, info.isSigned, GetFieldTypeName(info.filedType).c_str(),
214 GetProtoTypeName(info.protoType).c_str(), info.typeName.c_str(), info.name.c_str());
215 }
216
GetNameFromTypeName(const std::string & typeName)217 static std::string GetNameFromTypeName(const std::string &typeName)
218 {
219 if (typeName.empty()) {
220 return "";
221 }
222 std::string curName;
223 auto posT0 = typeName.rfind(" ");
224 std::string rightPart = typeName.substr(posT0 + 1);
225 if (rightPart[rightPart.size() - 1] != ']') {
226 curName = rightPart;
227 } else {
228 auto posT1 = rightPart.rfind('[');
229 TS_CHECK_TRUE(posT1 != std::string::npos, "", "GetNameFromTypeName Failed!");
230 curName = rightPart.substr(0, posT1);
231 }
232 return curName;
233 }
234
GetTypeFromTypeName(const std::string & typeName,const std::string & name)235 static std::string GetTypeFromTypeName(const std::string &typeName, const std::string &name)
236 {
237 std::string curType;
238 if (!name.empty()) {
239 curType = typeName;
240 auto pos = curType.find(name);
241 curType.replace(pos, name.size(), "");
242 curType = Strip(curType);
243 }
244 return curType;
245 }
246
ParseCommonFiledIndex(CommonFiledIndex & commonIndex,const std::string & name,int index)247 static void ParseCommonFiledIndex(CommonFiledIndex &commonIndex, const std::string &name, int index)
248 {
249 if (name == "common_type") {
250 commonIndex.type = index;
251 } else if (name == "common_flags") {
252 commonIndex.flags = index;
253 } else if (name == "common_preempt_count") {
254 commonIndex.preemt = index;
255 } else if (name == "common_pid") {
256 commonIndex.pid = index;
257 }
258 }
259
HandleFieldFormat(const std::string & fieldLine,EventFormat & format)260 bool FtraceProcessor::HandleFieldFormat(const std::string &fieldLine, EventFormat &format)
261 {
262 std::string typeName;
263 std::string offsetInfo;
264 std::string sizeInfo;
265 std::string signedInfo;
266 for (auto &partInfo : SplitStringToVec(fieldLine, ";")) {
267 auto fieldMap = SplitStringToVec(Strip(partInfo), ":");
268 if (fieldMap.size() < COL_IDX_VALUE) {
269 continue;
270 }
271 const auto &fieldName = fieldMap[COL_IDX_NAME];
272 if (fieldName == "field") {
273 typeName = fieldMap[COL_IDX_VALUE];
274 } else if (fieldName == "offset") {
275 offsetInfo = fieldMap[COL_IDX_VALUE];
276 } else if (fieldName == "size") {
277 sizeInfo = fieldMap[COL_IDX_VALUE];
278 } else if (fieldName == "signed") {
279 signedInfo = fieldMap[COL_IDX_VALUE];
280 }
281 }
282 std::string filedName = GetNameFromTypeName(typeName);
283 std::string filedType = GetTypeFromTypeName(typeName, filedName);
284 FieldFormat fieldFormat;
285 fieldFormat.name = filedName;
286 fieldFormat.typeName = typeName;
287 fieldFormat.offset = atoi(offsetInfo.c_str());
288 fieldFormat.size = atoi(sizeInfo.c_str());
289 fieldFormat.isSigned = atoi(signedInfo.c_str());
290
291 HandleFieldType(filedType, fieldFormat);
292 HandleProtoType(fieldFormat);
293
294 if (StartWith(filedName, "common_")) {
295 ParseCommonFiledIndex(format.commonIndex, filedName, static_cast<int>(format.commonFields.size()));
296 format.commonFields.push_back(fieldFormat);
297 } else {
298 format.fields.push_back(fieldFormat);
299 }
300 return true;
301 }
302
ParseSepcialIntType(FieldFormat & field,const std::string & type,const std::string & typeName)303 static bool ParseSepcialIntType(FieldFormat &field, const std::string &type, const std::string &typeName)
304 {
305 if (type == "bool") {
306 field.filedType = FIELD_TYPE_BOOL;
307 return true;
308 }
309
310 if (type == "ino_t" || type == "i_ino") {
311 if (field.size == sizeof(uint32_t)) {
312 field.filedType = FIELD_TYPE_INODE32;
313 return true;
314 } else if (field.size == sizeof(uint64_t)) {
315 field.filedType = FIELD_TYPE_INODE64;
316 return true;
317 }
318 }
319
320 if (type == "dev_t") {
321 if (field.size == sizeof(uint32_t)) {
322 field.filedType = FIELD_TYPE_DEVID32;
323 return true;
324 } else if (field.size == sizeof(uint64_t)) {
325 field.filedType = FIELD_TYPE_DEVID64;
326 return true;
327 }
328 }
329
330 // Pids (as in 'sched_switch').
331 if (type == "pid_t") {
332 field.filedType = FIELD_TYPE_PID32;
333 return true;
334 }
335
336 if ((typeName.find("common_pid") != std::string::npos)) {
337 field.filedType = FIELD_TYPE_COMMONPID32;
338 return true;
339 }
340 return false;
341 }
342
ParseCommonIntType(FieldFormat & field,bool sign)343 static bool ParseCommonIntType(FieldFormat &field, bool sign)
344 {
345 switch (field.size) {
346 case sizeof(int8_t):
347 field.filedType = sign ? FIELD_TYPE_INT8 : FIELD_TYPE_UINT8;
348 return true;
349 case sizeof(int16_t):
350 field.filedType = sign ? FIELD_TYPE_INT16 : FIELD_TYPE_UINT16;
351 return true;
352 case sizeof(int32_t):
353 field.filedType = sign ? FIELD_TYPE_INT32 : FIELD_TYPE_UINT32;
354 return true;
355 case sizeof(int64_t):
356 field.filedType = sign ? FIELD_TYPE_INT64 : FIELD_TYPE_UINT64;
357 return true;
358 default:
359 break;
360 }
361 return false;
362 }
363
ParseKernelAddrField(FieldFormat & field,const std::string & type)364 bool ParseKernelAddrField(FieldFormat &field, const std::string &type)
365 {
366 if (type == "void*" || type == "void *") {
367 if (field.size == sizeof(uint64_t)) { // 64-bit kernel addresses
368 field.filedType = FIELD_TYPE_SYMADDR64;
369 return true;
370 } else if (field.size == sizeof(uint32_t)) { // 32-bit kernel addresses
371 field.filedType = FIELD_TYPE_SYMADDR32;
372 return true;
373 }
374 }
375 return false;
376 }
377
HandleFieldType(const std::string & type,FieldFormat & field)378 bool FtraceProcessor::HandleFieldType(const std::string &type, FieldFormat &field)
379 {
380 const std::string &curTypeName = field.typeName;
381 // for fixed size C char arrary, likes "char a[LEN]"
382 if (std::regex_match(curTypeName, fixedCharArrayRegex_)) {
383 field.filedType = FIELD_TYPE_FIXEDCSTRING;
384 return true;
385 }
386
387 // for flex array with __data_loc mark, likes: __data_loc char[] name;
388 if (std::regex_match(curTypeName, flexDataLocArrayRegex_)) {
389 if (field.size != sizeof(uint32_t)) {
390 TS_LOGW("__data_loc: %s, size: %hu", curTypeName.c_str(), field.size);
391 return false;
392 }
393 field.filedType = FIELD_TYPE_DATALOC;
394 return true;
395 }
396
397 if ((curTypeName.find("char[]") != std::string::npos) || (curTypeName.find("char *") != std::string::npos)) {
398 field.filedType = FIELD_TYPE_STRINGPTR;
399 return true;
400 }
401
402 // for variable length strings: "char foo" + size: 0 (as in 'print').
403 if ((type == "char" || type == "char []") && field.size == 0) {
404 field.filedType = FIELD_TYPE_CSTRING;
405 return true;
406 }
407
408 // for 64-bit kernel addresses
409 TS_CHECK_TRUE_RET(!ParseKernelAddrField(field, type), true);
410 TS_CHECK_TRUE_RET(!ParseSepcialIntType(field, type, curTypeName), true);
411 // for int uint:
412 TS_CHECK_TRUE_RET(!ParseCommonIntType(field, field.isSigned), true);
413 return false;
414 }
415
HandleProtoType(FieldFormat & fieldFormat)416 void FtraceProcessor::HandleProtoType(FieldFormat &fieldFormat)
417 {
418 switch (fieldFormat.filedType) {
419 case FIELD_TYPE_INT8:
420 case FIELD_TYPE_INT16:
421 case FIELD_TYPE_INT32:
422 case FIELD_TYPE_PID32:
423 case FIELD_TYPE_COMMONPID32:
424 fieldFormat.protoType = PROTO_TYPE_INT32;
425 break;
426 case FIELD_TYPE_INT64:
427 fieldFormat.protoType = PROTO_TYPE_INT64;
428 break;
429 case FIELD_TYPE_UINT8:
430 case FIELD_TYPE_UINT16:
431 case FIELD_TYPE_UINT32:
432 case FIELD_TYPE_BOOL:
433 case FIELD_TYPE_DEVID32:
434 case FIELD_TYPE_SYMADDR32:
435 fieldFormat.protoType = PROTO_TYPE_UINT32;
436 break;
437 case FIELD_TYPE_DEVID64:
438 case FIELD_TYPE_UINT64:
439 case FIELD_TYPE_INODE32:
440 case FIELD_TYPE_INODE64:
441 case FIELD_TYPE_SYMADDR64:
442 fieldFormat.protoType = PROTO_TYPE_UINT64;
443 break;
444 case FIELD_TYPE_CSTRING:
445 case FIELD_TYPE_FIXEDCSTRING:
446 case FIELD_TYPE_STRINGPTR:
447 case FIELD_TYPE_DATALOC:
448 fieldFormat.protoType = PROTO_TYPE_STRING;
449 break;
450 case FIELD_TYPE_INVALID:
451 fieldFormat.protoType = PROTO_TYPE_UNKNOWN;
452 break;
453 default:
454 break;
455 }
456 }
457
HandlePageHeader()458 bool FtraceProcessor::HandlePageHeader()
459 {
460 (void)memset_s(&curPageHeader_, sizeof(curPageHeader_), 0, sizeof(PageHeader));
461
462 uint64_t curTimestamp = 0;
463 TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfPage_, &curTimestamp, sizeof(curTimestamp)), false,
464 "read timestamp from page failed!");
465 curPageHeader_.timestamp = curTimestamp;
466
467 uint64_t curCommit = 0;
468 TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfPage_, &curCommit, HeaderPageCommitSize()), false,
469 "read commit to page header failed!");
470
471 // for refers kernel function ring_buffer_page_len:
472 curPageHeader_.size = (curCommit & ~RB_MISSED_FLAGS);
473 curPageHeader_.overwrite = (curCommit & RB_MISSED_EVENTS);
474
475 curPageHeader_.startpos = curPos_;
476 curPageHeader_.endpos = curPos_ + curPageHeader_.size;
477 return true;
478 }
479
HandleTgids(const std::string & tgids)480 bool FtraceProcessor::HandleTgids(const std::string &tgids)
481 {
482 int32_t pid = 0;
483 int32_t tgid = 0;
484 bool state = false;
485 std::stringstream tgidsStream(tgids);
486 // format info for: "%d %d\n"
487 while (tgidsStream >> pid >> tgid) {
488 tgidDict_[pid] = tgid;
489 state = true;
490 }
491
492 TS_LOGI("tgidDict_.size = %zu", tgidDict_.size());
493 return state;
494 }
495
HandleCmdlines(const std::string & cmdlines)496 bool FtraceProcessor::HandleCmdlines(const std::string &cmdlines)
497 {
498 bool state = false;
499 int32_t pid;
500 std::string taskName;
501 std::string curLine;
502 std::stringstream cmdlinesStream(cmdlines);
503 // format info for: "%d %s\n"
504 while (std::getline(cmdlinesStream, curLine)) {
505 auto pos = curLine.find(' ');
506 if (pos != std::string::npos) {
507 pid = std::stoi(curLine.substr(0, pos));
508 taskName = curLine.substr(pos + 1);
509 taskNameDict_[pid] = taskName;
510 state = true;
511 }
512 }
513
514 TS_LOGI("taskNameDict_.size = %zu", taskNameDict_.size());
515 return state;
516 }
517
HandlePaddingData(const FtraceEventHeader & eventHeader)518 bool FtraceProcessor::HandlePaddingData(const FtraceEventHeader &eventHeader)
519 {
520 TS_CHECK_TRUE_RET(eventHeader.timeDelta != 0, false);
521 uint32_t paddingLength;
522 TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &paddingLength, sizeof(paddingLength)), false,
523 "read padding len failed!");
524 // for skip padding data
525 curPos_ += paddingLength;
526 return true;
527 }
528
HandleTimeExtend(const FtraceEventHeader & eventHeader)529 bool FtraceProcessor::HandleTimeExtend(const FtraceEventHeader &eventHeader)
530 {
531 uint32_t deltaExt = 0;
532 TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &deltaExt, sizeof(deltaExt)), false, "read time delta failed!");
533 curTimestamp_ += TimestampIncrements(deltaExt);
534 TS_LOGD("HandleTimeExtend: update ts with %u to %" PRIu64, deltaExt, curTimestamp_);
535 return true;
536 }
537
HandleTimeStamp(const FtraceEventHeader & eventHeader)538 bool FtraceProcessor::HandleTimeStamp(const FtraceEventHeader &eventHeader)
539 {
540 uint32_t deltaExt = 0;
541 TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &deltaExt, sizeof(deltaExt)), false, "read time delta failed!");
542
543 // refers kernel function rb_update_write_stamp in ring_buffer.c
544 curTimestamp_ = eventHeader.timeDelta + TimestampIncrements(deltaExt);
545 TS_LOGD("update ts with %u to %" PRIu64, deltaExt, curTimestamp_);
546 return true;
547 }
548
HandleDataRecord(const FtraceEventHeader & eventHeader,FtraceCpuDetailMsg & cpuMsg,CpuDetailParser & cpuDetailParser)549 bool FtraceProcessor::HandleDataRecord(const FtraceEventHeader &eventHeader,
550 FtraceCpuDetailMsg &cpuMsg,
551 CpuDetailParser &cpuDetailParser)
552 {
553 uint32_t eventSize = 0;
554 // refers comments of kernel function rb_event_data_length:
555 if (eventHeader.typeLen) {
556 eventSize = sizeof(eventHeader.array[0]) * eventHeader.typeLen;
557 } else {
558 TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &eventSize, sizeof(eventSize)), false,
559 "read event size failed!");
560 if (eventSize < sizeof(uint32_t)) {
561 return false;
562 }
563 eventSize -= sizeof(uint32_t); // array[0] is length, array[1...array[0]] is event data
564 }
565 TS_LOGD("HandleDataRecord: parse %u bytes of event data...", eventSize);
566
567 uint8_t *eventStart = curPos_;
568 uint8_t *eventEnd = curPos_ + eventSize;
569 uint16_t eventId = 0;
570 TS_CHECK_TRUE(ReadInfo(&curPos_, eventEnd, &eventId, sizeof(eventId)), false, "read event ID failed!");
571
572 EventFormat format = {};
573 if (!GetEventFormatById(eventId, format)) {
574 TS_LOGD("event with id %u we not interested!", eventId);
575 curPos_ = eventEnd;
576 return true;
577 }
578 TS_LOGD("HandleDataRecord: eventId = %u, name = %s", eventId, format.eventName.c_str());
579
580 if (traceDataCache_->isSplitFile_) {
581 curPos_ = eventEnd;
582 return true;
583 }
584 if (FtraceEventProcessor::GetInstance().IsSupported(format.eventId)) {
585 std::unique_ptr<FtraceEvent> ftraceEvent = std::make_unique<FtraceEvent>();
586 ftraceEvent->set_timestamp(curTimestamp_);
587 HandleFtraceEvent(*ftraceEvent, eventStart, eventSize, format);
588 std::unique_ptr<RawTraceEventInfo> event = std::make_unique<RawTraceEventInfo>();
589 event->cpuId = cpuMsg.cpu();
590 event->eventId = eventId;
591 event->msgPtr = std::move(ftraceEvent);
592 cpuDetailParser.EventAppend(std::move(event));
593 } else {
594 TS_LOGD("event %u %s not supported!", format.eventId, format.eventName.c_str());
595 }
596 curPos_ = eventEnd;
597 return true;
598 }
599
HandlePage(FtraceCpuDetailMsg & cpuMsg,CpuDetailParser & cpuDetailParser,uint8_t page[],bool & haveSplitSeg,size_t size)600 bool FtraceProcessor::HandlePage(FtraceCpuDetailMsg &cpuMsg,
601 CpuDetailParser &cpuDetailParser,
602 uint8_t page[],
603 bool &haveSplitSeg,
604 size_t size)
605 {
606 curPos_ = page;
607 curPage_ = page;
608 endPosOfPage_ = page + size;
609 HandlePageHeader();
610 TS_LOGD("HandlePage: %" PRIu64 " bytes event data in page!", curPageHeader_.size);
611 cpuMsg.set_overwrite(curPageHeader_.overwrite);
612 curTimestamp_ = curPageHeader_.timestamp;
613 endPosOfData_ = curPageHeader_.endpos;
614 while (curPos_ < curPageHeader_.endpos) {
615 FtraceEventHeader eventHeader = {};
616 TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &eventHeader, sizeof(FtraceEventHeader)), false,
617 "read EventHeader fail!");
618 curTimestamp_ += eventHeader.timeDelta;
619 bool retval = false;
620 switch (eventHeader.typeLen) {
621 case BUFFER_TYPE_PADDING:
622 retval = HandlePaddingData(eventHeader);
623 TS_CHECK_TRUE(retval, false, "parse PADDING data failed!");
624 break;
625 case BUFFER_TYPE_TIME_EXTEND:
626 retval = HandleTimeExtend(eventHeader);
627 TS_CHECK_TRUE(retval, false, "parse TIME_EXTEND failed!");
628 break;
629 case BUFFER_TYPE_TIME_STAMP:
630 retval = HandleTimeStamp(eventHeader);
631 TS_CHECK_TRUE(retval, false, "parse TIME_STAMP failed!");
632 break;
633 default:
634 retval = HandleDataRecord(eventHeader, cpuMsg, cpuDetailParser);
635 TS_CHECK_TRUE(retval, false, "parse record data failed!");
636 break;
637 }
638 if (traceDataCache_->isSplitFile_ && IsSplitCpuTimeStampData(curTimestamp_, haveSplitSeg)) {
639 return true;
640 }
641 TS_LOGD("parsed %ld bytes of page data.", static_cast<long>(curPos_ - curPage_));
642 }
643 return true;
644 }
645
RmqEntryTotalSize(unsigned int size)646 static inline int RmqEntryTotalSize(unsigned int size)
647 {
648 return sizeof(struct RmqEntry) + ((size + RMQ_ENTRY_ALIGN_MASK) & (~RMQ_ENTRY_ALIGN_MASK));
649 }
650
HmProcessPageTraceDataEvents(RmqConsumerData * rmqData,uint64_t timeStampBase,FtraceCpuDetailMsg & cpuMsg,CpuDetailParser & cpuDetailParser,bool & haveSplitSeg)651 void FtraceProcessor::HmProcessPageTraceDataEvents(RmqConsumerData *rmqData,
652 uint64_t timeStampBase,
653 FtraceCpuDetailMsg &cpuMsg,
654 CpuDetailParser &cpuDetailParser,
655 bool &haveSplitSeg)
656 {
657 RmqEntry *event;
658 HmTraceHeader *header;
659 EventFormat format = {};
660 auto curPtr = rmqData->data;
661 auto endPtr = rmqData->data + rmqData->length;
662 while (curPtr < endPtr) {
663 event = (struct RmqEntry *)curPtr;
664 auto evtSize = event->size;
665 if (evtSize == 0U) {
666 break;
667 }
668 header = reinterpret_cast<struct HmTraceHeader *>(event->data);
669 auto eventId = header->commonType;
670 curPtr += RmqEntryTotalSize(evtSize);
671 if (!GetEventFormatById(eventId, format)) {
672 TS_LOGD("mark.debug. evtId = %u evtSize = %u", eventId, evtSize);
673 continue;
674 }
675 if (traceDataCache_->isSplitFile_) {
676 if (IsSplitCpuTimeStampData(event->timeStampOffset + timeStampBase, haveSplitSeg)) {
677 return;
678 }
679 continue;
680 }
681 if (FtraceEventProcessor::GetInstance().IsSupported(format.eventId)) {
682 std::unique_ptr<FtraceEvent> ftraceEvent = std::make_unique<FtraceEvent>();
683 ftraceEvent->set_timestamp(event->timeStampOffset + timeStampBase);
684 HandleFtraceEvent(*ftraceEvent, reinterpret_cast<uint8_t *>(header), evtSize, format);
685 std::shared_ptr<RawTraceEventInfo> eventInfo = std::make_shared<RawTraceEventInfo>();
686 eventInfo->cpuId = cpuMsg.cpu();
687 eventInfo->eventId = eventId;
688 eventInfo->msgPtr = std::move(ftraceEvent);
689 cpuDetailParser.EventAppend(std::move(eventInfo));
690 } else {
691 TS_LOGD(
692 "mark.debug. evtId = %u evtSize = %u format.eventId = %u format.evtSize = %u"
693 "format.eventName = %s format.eventType = %s",
694 eventId, evtSize, format.eventId, format.eventSize, format.eventName.c_str(), format.eventType.c_str());
695 }
696 }
697 }
HmParsePageData(FtraceCpuDetailMsg & cpuMsg,CpuDetailParser & cpuDetailParser,uint8_t * & data,bool & haveSplitSeg)698 bool FtraceProcessor::HmParsePageData(FtraceCpuDetailMsg &cpuMsg,
699 CpuDetailParser &cpuDetailParser,
700 uint8_t *&data,
701 bool &haveSplitSeg)
702 {
703 RmqConsumerData *rmqData = reinterpret_cast<struct RmqConsumerData *>(data);
704 uint64_t timeStampBase = rmqData->timeStamp;
705 cpuMsg.set_cpu(rmqData->coreId);
706 cpuMsg.set_overwrite(0);
707 HmProcessPageTraceDataEvents(rmqData, timeStampBase, cpuMsg, cpuDetailParser, haveSplitSeg);
708 return true;
709 }
710
IsValidIndex(int index)711 static bool IsValidIndex(int index)
712 {
713 return index != CommonFiledIndex::INVALID_IDX;
714 }
715
HandleFtraceCommonFields(FtraceEvent & ftraceEvent,uint8_t data[],size_t dataSize,const EventFormat & format)716 bool FtraceProcessor::HandleFtraceCommonFields(FtraceEvent &ftraceEvent,
717 uint8_t data[],
718 size_t dataSize,
719 const EventFormat &format)
720 {
721 auto curIndex = format.commonIndex;
722
723 TS_CHECK_TRUE(IsValidIndex(curIndex.pid), false, "pid curIndex %d invalid!", curIndex.pid);
724 TS_CHECK_TRUE(IsValidIndex(curIndex.type), false, "type curIndex %d invalid!", curIndex.type);
725 TS_CHECK_TRUE(IsValidIndex(curIndex.flags), false, "flags curIndex %d invalid!", curIndex.flags);
726 TS_CHECK_TRUE(IsValidIndex(curIndex.preemt), false, "preemt curIndex %d invalid!", curIndex.preemt);
727
728 auto fields = format.commonFields;
729 auto eventCommonFields = ftraceEvent.mutable_common_fields();
730 eventCommonFields->set_pid(FtraceFieldProcessor::HandleIntField<int32_t>(fields, curIndex.pid, data, dataSize));
731 eventCommonFields->set_type(FtraceFieldProcessor::HandleIntField<uint32_t>(fields, curIndex.type, data, dataSize));
732 eventCommonFields->set_flags(
733 FtraceFieldProcessor::HandleIntField<uint32_t>(fields, curIndex.flags, data, dataSize));
734 eventCommonFields->set_preempt_count(
735 FtraceFieldProcessor::HandleIntField<uint32_t>(fields, curIndex.preemt, data, dataSize));
736 return true;
737 }
738
HandleFtraceEvent(FtraceEvent & ftraceEvent,uint8_t data[],size_t dataSize,const EventFormat & format)739 bool FtraceProcessor::HandleFtraceEvent(FtraceEvent &ftraceEvent,
740 uint8_t data[],
741 size_t dataSize,
742 const EventFormat &format)
743 {
744 TS_CHECK_TRUE(dataSize >= format.eventSize, false, "dataSize not enough!");
745 TS_CHECK_TRUE(HandleFtraceCommonFields(ftraceEvent, data, dataSize, format), false, "parse common fields failed!");
746
747 int pid = ftraceEvent.common_fields().pid();
748 if (pid != 0) {
749 auto tgidIter = tgidDict_.find(pid);
750 if (tgidIter != tgidDict_.end()) {
751 ftraceEvent.set_tgid(tgidIter->second);
752 } else {
753 TS_LOGD("pid = %d, tgid can't find.", pid);
754 }
755 auto commIter = taskNameDict_.find(pid);
756 if (commIter != taskNameDict_.end()) {
757 ftraceEvent.set_comm(commIter->second);
758 } else {
759 TS_LOGD("pid = %d, taskName can't find.taskName = %s", pid, std::to_string(pid).data());
760 }
761 TS_LOGD("pid = %5d, tgid = %5d, event = %s", pid, ftraceEvent.tgid(), format.eventName.c_str());
762 }
763 FtraceEventProcessor::GetInstance().HandleEvent(ftraceEvent, data, dataSize, format);
764 return true;
765 }
766 } // namespace TraceStreamer
767 } // namespace SysTuning
768