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