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