• 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) \
179     {                 \
180         x, #x         \
181     }
182         VALUE_NAME(FIELD_TYPE_INVALID),   VALUE_NAME(FIELD_TYPE_BOOL),         VALUE_NAME(FIELD_TYPE_INT8),
183         VALUE_NAME(FIELD_TYPE_UINT8),     VALUE_NAME(FIELD_TYPE_INT16),        VALUE_NAME(FIELD_TYPE_UINT16),
184         VALUE_NAME(FIELD_TYPE_INT32),     VALUE_NAME(FIELD_TYPE_UINT32),       VALUE_NAME(FIELD_TYPE_INT64),
185         VALUE_NAME(FIELD_TYPE_UINT64),    VALUE_NAME(FIELD_TYPE_FIXEDCSTRING), VALUE_NAME(FIELD_TYPE_CSTRING),
186         VALUE_NAME(FIELD_TYPE_STRINGPTR), VALUE_NAME(FIELD_TYPE_INODE32),      VALUE_NAME(FIELD_TYPE_INODE64),
187         VALUE_NAME(FIELD_TYPE_PID32),     VALUE_NAME(FIELD_TYPE_COMMONPID32),  VALUE_NAME(FIELD_TYPE_DEVID32),
188         VALUE_NAME(FIELD_TYPE_DEVID64),   VALUE_NAME(FIELD_TYPE_DATALOC),      VALUE_NAME(FIELD_TYPE_SYMADDR32),
189         VALUE_NAME(FIELD_TYPE_SYMADDR64),
190 #undef VALUE_NAME
191     };
192     return GetName(toNames, type);
193 }
194 
GetProtoTypeName(ProtoFieldType type)195 static std::string GetProtoTypeName(ProtoFieldType type)
196 {
197     static std::map<int, std::string> toNames = {
198 #define VALUE_NAME(x) \
199     {                 \
200         x, #x         \
201     }
202         VALUE_NAME(PROTO_TYPE_UNKNOWN),  VALUE_NAME(PROTO_TYPE_DOUBLE),   VALUE_NAME(PROTO_TYPE_FLOAT),
203         VALUE_NAME(PROTO_TYPE_INT64),    VALUE_NAME(PROTO_TYPE_UINT64),   VALUE_NAME(PROTO_TYPE_INT32),
204         VALUE_NAME(PROTO_TYPE_FIXED64),  VALUE_NAME(PROTO_TYPE_FIXED32),  VALUE_NAME(PROTO_TYPE_BOOL),
205         VALUE_NAME(PROTO_TYPE_STRING),   VALUE_NAME(PROTO_TYPE_GROUP),    VALUE_NAME(PROTO_TYPE_MESSAGE),
206         VALUE_NAME(PROTO_TYPE_BYTES),    VALUE_NAME(PROTO_TYPE_UINT32),   VALUE_NAME(PROTO_TYPE_ENUM),
207         VALUE_NAME(PROTO_TYPE_SFIXED32), VALUE_NAME(PROTO_TYPE_SFIXED64), VALUE_NAME(PROTO_TYPE_SINT32),
208         VALUE_NAME(PROTO_TYPE_SINT64),   VALUE_NAME(PROTO_TYPE_MAX),
209 #undef VALUE_NAME
210     };
211     return GetName(toNames, type);
212 }
213 
PrintedFieldDetails(const FieldFormat & info)214 void FtraceProcessor::PrintedFieldDetails(const FieldFormat &info)
215 {
216     TS_LOGI(
217         "FieldFormat { offset: %u, size:%u, sign: %u fieldType: %s, "
218         "protoType:%s, typeName: %s, name: %s}",
219         info.offset, info.size, info.isSigned, GetFieldTypeName(info.filedType).c_str(),
220         GetProtoTypeName(info.protoType).c_str(), info.typeName.c_str(), info.name.c_str());
221 }
222 
GetNameFromTypeName(const std::string & typeName)223 static std::string GetNameFromTypeName(const std::string &typeName)
224 {
225     if (typeName.empty()) {
226         return "";
227     }
228     std::string curName;
229     auto posT0 = typeName.rfind(" ");
230     std::string rightPart = typeName.substr(posT0 + 1);
231     if (rightPart[rightPart.size() - 1] != ']') {
232         curName = rightPart;
233     } else {
234         auto posT1 = rightPart.rfind('[');
235         TS_CHECK_TRUE(posT1 != std::string::npos, "", "GetNameFromTypeName Failed!");
236         curName = rightPart.substr(0, posT1);
237     }
238     return curName;
239 }
240 
GetTypeFromTypeName(const std::string & typeName,const std::string & name)241 static std::string GetTypeFromTypeName(const std::string &typeName, const std::string &name)
242 {
243     std::string curType;
244     if (!name.empty()) {
245         curType = typeName;
246         auto pos = curType.find(name);
247         curType.replace(pos, name.size(), "");
248         curType = Strip(curType);
249     }
250     return curType;
251 }
252 
ParseCommonFiledIndex(CommonFiledIndex & commonIndex,const std::string & name,int index)253 static void ParseCommonFiledIndex(CommonFiledIndex &commonIndex, const std::string &name, int index)
254 {
255     if (name == "common_type") {
256         commonIndex.type = index;
257     } else if (name == "common_flags") {
258         commonIndex.flags = index;
259     } else if (name == "common_preempt_count") {
260         commonIndex.preemt = index;
261     } else if (name == "common_pid") {
262         commonIndex.pid = index;
263     }
264 }
265 
HandleFieldFormat(const std::string & fieldLine,EventFormat & format)266 bool FtraceProcessor::HandleFieldFormat(const std::string &fieldLine, EventFormat &format)
267 {
268     std::string typeName;
269     std::string offsetInfo;
270     std::string sizeInfo;
271     std::string signedInfo;
272     for (auto &partInfo : SplitStringToVec(fieldLine, ";")) {
273         auto fieldMap = SplitStringToVec(Strip(partInfo), ":");
274         if (fieldMap.size() < COL_IDX_VALUE) {
275             continue;
276         }
277         const auto &fieldName = fieldMap[COL_IDX_NAME];
278         if (fieldName == "field") {
279             typeName = fieldMap[COL_IDX_VALUE];
280         } else if (fieldName == "offset") {
281             offsetInfo = fieldMap[COL_IDX_VALUE];
282         } else if (fieldName == "size") {
283             sizeInfo = fieldMap[COL_IDX_VALUE];
284         } else if (fieldName == "signed") {
285             signedInfo = fieldMap[COL_IDX_VALUE];
286         }
287     }
288     std::string filedName = GetNameFromTypeName(typeName);
289     std::string filedType = GetTypeFromTypeName(typeName, filedName);
290     FieldFormat fieldFormat;
291     fieldFormat.name = filedName;
292     fieldFormat.typeName = typeName;
293     fieldFormat.offset = atoi(offsetInfo.c_str());
294     fieldFormat.size = atoi(sizeInfo.c_str());
295     fieldFormat.isSigned = atoi(signedInfo.c_str());
296 
297     HandleFieldType(filedType, fieldFormat);
298     HandleProtoType(fieldFormat);
299 
300     if (StartWith(filedName, "common_")) {
301         ParseCommonFiledIndex(format.commonIndex, filedName, static_cast<int>(format.commonFields.size()));
302         format.commonFields.push_back(fieldFormat);
303     } else {
304         format.fields.push_back(fieldFormat);
305     }
306     return true;
307 }
308 
ParseSepcialIntType(FieldFormat & field,const std::string & type,const std::string & typeName)309 static bool ParseSepcialIntType(FieldFormat &field, const std::string &type, const std::string &typeName)
310 {
311     if (type == "bool") {
312         field.filedType = FIELD_TYPE_BOOL;
313         return true;
314     }
315 
316     if (type == "ino_t" || type == "i_ino") {
317         if (field.size == sizeof(uint32_t)) {
318             field.filedType = FIELD_TYPE_INODE32;
319             return true;
320         } else if (field.size == sizeof(uint64_t)) {
321             field.filedType = FIELD_TYPE_INODE64;
322             return true;
323         }
324     }
325 
326     if (type == "dev_t") {
327         if (field.size == sizeof(uint32_t)) {
328             field.filedType = FIELD_TYPE_DEVID32;
329             return true;
330         } else if (field.size == sizeof(uint64_t)) {
331             field.filedType = FIELD_TYPE_DEVID64;
332             return true;
333         }
334     }
335 
336     // Pids (as in 'sched_switch').
337     if (type == "pid_t") {
338         field.filedType = FIELD_TYPE_PID32;
339         return true;
340     }
341 
342     if ((typeName.find("common_pid") != std::string::npos)) {
343         field.filedType = FIELD_TYPE_COMMONPID32;
344         return true;
345     }
346     return false;
347 }
348 
ParseCommonIntType(FieldFormat & field,bool sign)349 static bool ParseCommonIntType(FieldFormat &field, bool sign)
350 {
351     switch (field.size) {
352         case sizeof(int8_t):
353             field.filedType = sign ? FIELD_TYPE_INT8 : FIELD_TYPE_UINT8;
354             return true;
355         case sizeof(int16_t):
356             field.filedType = sign ? FIELD_TYPE_INT16 : FIELD_TYPE_UINT16;
357             return true;
358         case sizeof(int32_t):
359             field.filedType = sign ? FIELD_TYPE_INT32 : FIELD_TYPE_UINT32;
360             return true;
361         case sizeof(int64_t):
362             field.filedType = sign ? FIELD_TYPE_INT64 : FIELD_TYPE_UINT64;
363             return true;
364         default:
365             break;
366     }
367     return false;
368 }
369 
ParseKernelAddrField(FieldFormat & field,const std::string & type)370 bool ParseKernelAddrField(FieldFormat &field, const std::string &type)
371 {
372     if (type == "void*" || type == "void *") {
373         if (field.size == sizeof(uint64_t)) { // 64-bit kernel addresses
374             field.filedType = FIELD_TYPE_SYMADDR64;
375             return true;
376         } else if (field.size == sizeof(uint32_t)) { // 32-bit kernel addresses
377             field.filedType = FIELD_TYPE_SYMADDR32;
378             return true;
379         }
380     }
381     return false;
382 }
383 
HandleFieldType(const std::string & type,FieldFormat & field)384 bool FtraceProcessor::HandleFieldType(const std::string &type, FieldFormat &field)
385 {
386     const std::string &curTypeName = field.typeName;
387     // for fixed size C char arrary, likes "char a[LEN]"
388     if (std::regex_match(curTypeName, fixedCharArrayRegex_)) {
389         field.filedType = FIELD_TYPE_FIXEDCSTRING;
390         return true;
391     }
392 
393     // for flex array with __data_loc mark, likes: __data_loc char[] name;
394     if (std::regex_match(curTypeName, flexDataLocArrayRegex_)) {
395         if (field.size != sizeof(uint32_t)) {
396             TS_LOGW("__data_loc: %s, size: %hu", curTypeName.c_str(), field.size);
397             return false;
398         }
399         field.filedType = FIELD_TYPE_DATALOC;
400         return true;
401     }
402 
403     if ((curTypeName.find("char[]") != std::string::npos) || (curTypeName.find("char *") != std::string::npos)) {
404         field.filedType = FIELD_TYPE_STRINGPTR;
405         return true;
406     }
407 
408     // for variable length strings: "char foo" + size: 0 (as in 'print').
409     if ((type == "char" || type == "char []") && field.size == 0) {
410         field.filedType = FIELD_TYPE_CSTRING;
411         return true;
412     }
413 
414     // for 64-bit kernel addresses
415     TS_CHECK_TRUE_RET(!ParseKernelAddrField(field, type), true);
416     TS_CHECK_TRUE_RET(!ParseSepcialIntType(field, type, curTypeName), true);
417     // for int uint:
418     TS_CHECK_TRUE_RET(!ParseCommonIntType(field, field.isSigned), true);
419     return false;
420 }
421 
HandleProtoType(FieldFormat & fieldFormat)422 void FtraceProcessor::HandleProtoType(FieldFormat &fieldFormat)
423 {
424     switch (fieldFormat.filedType) {
425         case FIELD_TYPE_INT8:
426         case FIELD_TYPE_INT16:
427         case FIELD_TYPE_INT32:
428         case FIELD_TYPE_PID32:
429         case FIELD_TYPE_COMMONPID32:
430             fieldFormat.protoType = PROTO_TYPE_INT32;
431             break;
432         case FIELD_TYPE_INT64:
433             fieldFormat.protoType = PROTO_TYPE_INT64;
434             break;
435         case FIELD_TYPE_UINT8:
436         case FIELD_TYPE_UINT16:
437         case FIELD_TYPE_UINT32:
438         case FIELD_TYPE_BOOL:
439         case FIELD_TYPE_DEVID32:
440         case FIELD_TYPE_SYMADDR32:
441             fieldFormat.protoType = PROTO_TYPE_UINT32;
442             break;
443         case FIELD_TYPE_DEVID64:
444         case FIELD_TYPE_UINT64:
445         case FIELD_TYPE_INODE32:
446         case FIELD_TYPE_INODE64:
447         case FIELD_TYPE_SYMADDR64:
448             fieldFormat.protoType = PROTO_TYPE_UINT64;
449             break;
450         case FIELD_TYPE_CSTRING:
451         case FIELD_TYPE_FIXEDCSTRING:
452         case FIELD_TYPE_STRINGPTR:
453         case FIELD_TYPE_DATALOC:
454             fieldFormat.protoType = PROTO_TYPE_STRING;
455             break;
456         case FIELD_TYPE_INVALID:
457             fieldFormat.protoType = PROTO_TYPE_UNKNOWN;
458             break;
459         default:
460             break;
461     }
462 }
463 
HandlePageHeader()464 bool FtraceProcessor::HandlePageHeader()
465 {
466     (void)memset_s(&curPageHeader_, sizeof(curPageHeader_), 0, sizeof(PageHeader));
467 
468     uint64_t curTimestamp = 0;
469     TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfPage_, &curTimestamp, sizeof(curTimestamp)), false,
470                   "read timestamp from page failed!");
471     curPageHeader_.timestamp = curTimestamp;
472 
473     uint64_t curCommit = 0;
474     TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfPage_, &curCommit, HeaderPageCommitSize()), false,
475                   "read commit to page header failed!");
476 
477     // for refers kernel function ring_buffer_page_len:
478     curPageHeader_.size = (curCommit & ~RB_MISSED_FLAGS);
479     curPageHeader_.overwrite = (curCommit & RB_MISSED_EVENTS);
480 
481     curPageHeader_.startpos = curPos_;
482     curPageHeader_.endpos = curPos_ + curPageHeader_.size;
483     return true;
484 }
485 
HandleTgids(const std::string & tgids)486 bool FtraceProcessor::HandleTgids(const std::string &tgids)
487 {
488     int32_t pid = 0;
489     int32_t tgid = 0;
490     bool state = false;
491     std::stringstream tgidsStream(tgids);
492     // format info for: "%d %d\n"
493     while (tgidsStream >> pid >> tgid) {
494         tgidDict_[pid] = tgid;
495         state = true;
496     }
497 
498     TS_LOGI("tgidDict_.size = %zu", tgidDict_.size());
499     return state;
500 }
501 
HandleCmdlines(const std::string & cmdlines)502 bool FtraceProcessor::HandleCmdlines(const std::string &cmdlines)
503 {
504     bool state = false;
505     int32_t pid;
506     std::string taskName;
507     std::string curLine;
508     std::stringstream cmdlinesStream(cmdlines);
509     // format info for: "%d %s\n"
510     while (std::getline(cmdlinesStream, curLine)) {
511         auto pos = curLine.find(' ');
512         if (pos != std::string::npos) {
513             pid = std::stoi(curLine.substr(0, pos));
514             taskName = curLine.substr(pos + 1);
515             taskNameDict_[pid] = taskName;
516             state = true;
517         }
518     }
519 
520     TS_LOGI("taskNameDict_.size = %zu", taskNameDict_.size());
521     return state;
522 }
523 
HandlePaddingData(const FtraceEventHeader & eventHeader)524 bool FtraceProcessor::HandlePaddingData(const FtraceEventHeader &eventHeader)
525 {
526     TS_CHECK_TRUE_RET(eventHeader.timeDelta != 0, false);
527     uint32_t paddingLength;
528     TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &paddingLength, sizeof(paddingLength)), false,
529                   "read padding len failed!");
530     // for skip padding data
531     curPos_ += paddingLength;
532     return true;
533 }
534 
HandleTimeExtend(const FtraceEventHeader & eventHeader)535 bool FtraceProcessor::HandleTimeExtend(const FtraceEventHeader &eventHeader)
536 {
537     uint32_t deltaExt = 0;
538     TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &deltaExt, sizeof(deltaExt)), false, "read time delta failed!");
539     curTimestamp_ += TimestampIncrements(deltaExt);
540     TS_LOGD("HandleTimeExtend: update ts with %u to %" PRIu64, deltaExt, curTimestamp_);
541     return true;
542 }
543 
HandleTimeStamp(const FtraceEventHeader & eventHeader)544 bool FtraceProcessor::HandleTimeStamp(const FtraceEventHeader &eventHeader)
545 {
546     uint32_t deltaExt = 0;
547     TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &deltaExt, sizeof(deltaExt)), false, "read time delta failed!");
548 
549     // refers kernel function rb_update_write_stamp in ring_buffer.c
550     curTimestamp_ = eventHeader.timeDelta + TimestampIncrements(deltaExt);
551     TS_LOGD("update ts with %u to %" PRIu64, deltaExt, curTimestamp_);
552     return true;
553 }
554 
HandleDataRecord(const FtraceEventHeader & eventHeader,FtraceCpuDetailMsg & cpuMsg,CpuDetailParser & cpuDetailParser)555 bool FtraceProcessor::HandleDataRecord(const FtraceEventHeader &eventHeader,
556                                        FtraceCpuDetailMsg &cpuMsg,
557                                        CpuDetailParser &cpuDetailParser)
558 {
559     uint32_t eventSize = 0;
560     // refers comments of kernel function rb_event_data_length:
561     if (eventHeader.typeLen) {
562         eventSize = sizeof(eventHeader.array[0]) * eventHeader.typeLen;
563     } else {
564         TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &eventSize, sizeof(eventSize)), false,
565                       "read event size failed!");
566         if (eventSize < sizeof(uint32_t)) {
567             return false;
568         }
569         eventSize -= sizeof(uint32_t); // array[0] is length, array[1...array[0]] is event data
570     }
571     TS_LOGD("HandleDataRecord: parse %u bytes of event data...", eventSize);
572 
573     uint8_t *eventStart = curPos_;
574     uint8_t *eventEnd = curPos_ + eventSize;
575     uint16_t eventId = 0;
576     TS_CHECK_TRUE(ReadInfo(&curPos_, eventEnd, &eventId, sizeof(eventId)), false, "read event ID failed!");
577 
578     EventFormat format = {};
579     if (!GetEventFormatById(eventId, format)) {
580         TS_LOGD("event with id %u we not interested!", eventId);
581         curPos_ = eventEnd;
582         return true;
583     }
584     TS_LOGD("HandleDataRecord: eventId = %u, name = %s", eventId, format.eventName.c_str());
585 
586     if (traceDataCache_->isSplitFile_) {
587         curPos_ = eventEnd;
588         return true;
589     }
590     if (FtraceEventProcessor::GetInstance().IsSupported(format.eventId)) {
591         std::unique_ptr<FtraceEvent> ftraceEvent = std::make_unique<FtraceEvent>();
592         ftraceEvent->set_timestamp(curTimestamp_);
593         HandleFtraceEvent(*ftraceEvent, eventStart, eventSize, format);
594         std::unique_ptr<RawTraceEventInfo> event = std::make_unique<RawTraceEventInfo>();
595         event->cpuId = cpuMsg.cpu();
596         event->eventId = eventId;
597         event->msgPtr = std::move(ftraceEvent);
598         cpuDetailParser.EventAppend(std::move(event));
599     } else {
600         TS_LOGD("event %u %s not supported!", format.eventId, format.eventName.c_str());
601     }
602     curPos_ = eventEnd;
603     return true;
604 }
605 
HandlePage(FtraceCpuDetailMsg & cpuMsg,CpuDetailParser & cpuDetailParser,uint8_t page[],bool & haveSplitSeg,size_t size)606 bool FtraceProcessor::HandlePage(FtraceCpuDetailMsg &cpuMsg,
607                                  CpuDetailParser &cpuDetailParser,
608                                  uint8_t page[],
609                                  bool &haveSplitSeg,
610                                  size_t size)
611 {
612     curPos_ = page;
613     curPage_ = page;
614     endPosOfPage_ = page + size;
615     HandlePageHeader();
616     TS_LOGD("HandlePage: %" PRIu64 " bytes event data in page!", curPageHeader_.size);
617     cpuMsg.set_overwrite(curPageHeader_.overwrite);
618     curTimestamp_ = curPageHeader_.timestamp;
619     endPosOfData_ = curPageHeader_.endpos;
620     while (curPos_ < curPageHeader_.endpos) {
621         FtraceEventHeader eventHeader = {};
622         TS_CHECK_TRUE(ReadInfo(&curPos_, endPosOfData_, &eventHeader, sizeof(FtraceEventHeader)), false,
623                       "read EventHeader fail!");
624         curTimestamp_ += eventHeader.timeDelta;
625         bool retval = false;
626         switch (eventHeader.typeLen) {
627             case BUFFER_TYPE_PADDING:
628                 retval = HandlePaddingData(eventHeader);
629                 TS_CHECK_TRUE(retval, false, "parse PADDING data failed!");
630                 break;
631             case BUFFER_TYPE_TIME_EXTEND:
632                 retval = HandleTimeExtend(eventHeader);
633                 TS_CHECK_TRUE(retval, false, "parse TIME_EXTEND failed!");
634                 break;
635             case BUFFER_TYPE_TIME_STAMP:
636                 retval = HandleTimeStamp(eventHeader);
637                 TS_CHECK_TRUE(retval, false, "parse TIME_STAMP failed!");
638                 break;
639             default:
640                 retval = HandleDataRecord(eventHeader, cpuMsg, cpuDetailParser);
641                 TS_CHECK_TRUE(retval, false, "parse record data failed!");
642                 break;
643         }
644         if (traceDataCache_->isSplitFile_ && IsSplitCpuTimeStampData(curTimestamp_, haveSplitSeg)) {
645             return true;
646         }
647         TS_LOGD("parsed %ld bytes of page data.", static_cast<long>(curPos_ - curPage_));
648     }
649     return true;
650 }
651 
RmqEntryTotalSize(unsigned int size)652 static inline int RmqEntryTotalSize(unsigned int size)
653 {
654     return sizeof(struct RmqEntry) + ((size + RMQ_ENTRY_ALIGN_MASK) & (~RMQ_ENTRY_ALIGN_MASK));
655 }
656 
HmProcessPageTraceDataEvents(RmqConsumerData * rmqData,uint64_t timeStampBase,FtraceCpuDetailMsg & cpuMsg,CpuDetailParser & cpuDetailParser,bool & haveSplitSeg)657 void FtraceProcessor::HmProcessPageTraceDataEvents(RmqConsumerData *rmqData,
658                                                    uint64_t timeStampBase,
659                                                    FtraceCpuDetailMsg &cpuMsg,
660                                                    CpuDetailParser &cpuDetailParser,
661                                                    bool &haveSplitSeg)
662 {
663     RmqEntry *event;
664     HmTraceHeader *header;
665     EventFormat format = {};
666     auto curPtr = rmqData->data;
667     auto endPtr = rmqData->data + rmqData->length;
668     while (curPtr < endPtr) {
669         event = (struct RmqEntry *)curPtr;
670         auto evtSize = event->size;
671         if (evtSize == 0U) {
672             break;
673         }
674         header = reinterpret_cast<struct HmTraceHeader *>(event->data);
675         auto eventId = header->commonType;
676         curPtr += RmqEntryTotalSize(evtSize);
677         if (!GetEventFormatById(eventId, format)) {
678             TS_LOGD("mark.debug. evtId = %u evtSize = %u", eventId, evtSize);
679             continue;
680         }
681         if (traceDataCache_->isSplitFile_) {
682             if (IsSplitCpuTimeStampData(event->timeStampOffset + timeStampBase, haveSplitSeg)) {
683                 return;
684             }
685             continue;
686         }
687         if (FtraceEventProcessor::GetInstance().IsSupported(format.eventId)) {
688             std::unique_ptr<FtraceEvent> ftraceEvent = std::make_unique<FtraceEvent>();
689             ftraceEvent->set_timestamp(event->timeStampOffset + timeStampBase);
690             HandleFtraceEvent(*ftraceEvent, reinterpret_cast<uint8_t *>(header), evtSize, format);
691             std::shared_ptr<RawTraceEventInfo> eventInfo = std::make_shared<RawTraceEventInfo>();
692             eventInfo->cpuId = cpuMsg.cpu();
693             eventInfo->eventId = eventId;
694             eventInfo->msgPtr = std::move(ftraceEvent);
695             cpuDetailParser.EventAppend(std::move(eventInfo));
696         } else {
697             TS_LOGD(
698                 "mark.debug. evtId = %u evtSize = %u format.eventId = %u format.evtSize = %u"
699                 "format.eventName = %s format.eventType = %s",
700                 eventId, evtSize, format.eventId, format.eventSize, format.eventName.c_str(), format.eventType.c_str());
701         }
702     }
703 }
HmParsePageData(FtraceCpuDetailMsg & cpuMsg,CpuDetailParser & cpuDetailParser,uint8_t * & data,bool & haveSplitSeg)704 bool FtraceProcessor::HmParsePageData(FtraceCpuDetailMsg &cpuMsg,
705                                       CpuDetailParser &cpuDetailParser,
706                                       uint8_t *&data,
707                                       bool &haveSplitSeg)
708 {
709     RmqConsumerData *rmqData = reinterpret_cast<struct RmqConsumerData *>(data);
710     uint64_t timeStampBase = rmqData->timeStamp;
711     cpuMsg.set_cpu(rmqData->coreId);
712     cpuMsg.set_overwrite(0);
713     HmProcessPageTraceDataEvents(rmqData, timeStampBase, cpuMsg, cpuDetailParser, haveSplitSeg);
714     return true;
715 }
716 
IsValidIndex(int index)717 static bool IsValidIndex(int index)
718 {
719     return index != CommonFiledIndex::INVALID_IDX;
720 }
721 
HandleFtraceCommonFields(FtraceEvent & ftraceEvent,uint8_t data[],size_t dataSize,const EventFormat & format)722 bool FtraceProcessor::HandleFtraceCommonFields(FtraceEvent &ftraceEvent,
723                                                uint8_t data[],
724                                                size_t dataSize,
725                                                const EventFormat &format)
726 {
727     auto curIndex = format.commonIndex;
728 
729     TS_CHECK_TRUE(IsValidIndex(curIndex.pid), false, "pid curIndex %d invalid!", curIndex.pid);
730     TS_CHECK_TRUE(IsValidIndex(curIndex.type), false, "type curIndex %d invalid!", curIndex.type);
731     TS_CHECK_TRUE(IsValidIndex(curIndex.flags), false, "flags curIndex %d invalid!", curIndex.flags);
732     TS_CHECK_TRUE(IsValidIndex(curIndex.preemt), false, "preemt curIndex %d invalid!", curIndex.preemt);
733 
734     auto fields = format.commonFields;
735     auto eventCommonFields = ftraceEvent.mutable_common_fields();
736     eventCommonFields->set_pid(FtraceFieldProcessor::HandleIntField<int32_t>(fields, curIndex.pid, data, dataSize));
737     eventCommonFields->set_type(FtraceFieldProcessor::HandleIntField<uint32_t>(fields, curIndex.type, data, dataSize));
738     eventCommonFields->set_flags(
739         FtraceFieldProcessor::HandleIntField<uint32_t>(fields, curIndex.flags, data, dataSize));
740     eventCommonFields->set_preempt_count(
741         FtraceFieldProcessor::HandleIntField<uint32_t>(fields, curIndex.preemt, data, dataSize));
742     return true;
743 }
744 
HandleFtraceEvent(FtraceEvent & ftraceEvent,uint8_t data[],size_t dataSize,const EventFormat & format)745 bool FtraceProcessor::HandleFtraceEvent(FtraceEvent &ftraceEvent,
746                                         uint8_t data[],
747                                         size_t dataSize,
748                                         const EventFormat &format)
749 {
750     TS_CHECK_TRUE(dataSize >= format.eventSize, false, "dataSize not enough!");
751     TS_CHECK_TRUE(HandleFtraceCommonFields(ftraceEvent, data, dataSize, format), false, "parse common fields failed!");
752 
753     int pid = ftraceEvent.common_fields().pid();
754     if (pid != 0) {
755         auto tgidIter = tgidDict_.find(pid);
756         if (tgidIter != tgidDict_.end()) {
757             ftraceEvent.set_tgid(tgidIter->second);
758         } else {
759             TS_LOGD("pid = %d, tgid can't find.", pid);
760         }
761         auto commIter = taskNameDict_.find(pid);
762         if (commIter != taskNameDict_.end()) {
763             ftraceEvent.set_comm(commIter->second);
764         } else {
765             TS_LOGD("pid = %d, taskName can't find.taskName = %s", pid, std::to_string(pid).data());
766         }
767         TS_LOGD("pid = %5d, tgid = %5d, event = %s", pid, ftraceEvent.tgid(), format.eventName.c_str());
768     }
769     FtraceEventProcessor::GetInstance().HandleEvent(ftraceEvent, data, dataSize, format);
770     return true;
771 }
GetTidToName()772 std::unordered_map<int32_t, std::string> &FtraceProcessor::GetTidToName()
773 {
774     return taskNameDict_;
775 }
776 } // namespace TraceStreamer
777 } // namespace SysTuning
778