1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "perf_data_parser.h"
16 #include "clock_filter_ex.h"
17 #include "file.h"
18 #include "perf_data_filter.h"
19 #include "stat_filter.h"
20
21 namespace SysTuning {
22 namespace TraceStreamer {
PerfDataParser(TraceDataCache * dataCache,const TraceStreamerFilters * ctx)23 PerfDataParser::PerfDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx)
24 : EventParserBase(dataCache, ctx),
25 configNameIndex_(traceDataCache_->dataDict_.GetStringIndex("config_name")),
26 workloaderIndex_(traceDataCache_->dataDict_.GetStringIndex("workload_cmd")),
27 cmdlineIndex_(traceDataCache_->dataDict_.GetStringIndex("cmdline")),
28 runingStateIndex_(traceDataCache_->dataDict_.GetStringIndex("Running")),
29 suspendStatIndex_(traceDataCache_->dataDict_.GetStringIndex("Suspend")),
30 unkonwnStateIndex_(traceDataCache_->dataDict_.GetStringIndex("-")),
31 pidAndStackHashToCallChainId_(INVALID_UINT32)
32 {
33 SymbolsFile::onRecording_ = false;
34 }
InitPerfDataAndLoad(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t offset,bool isSplitFile,bool isFinish)35 uint64_t PerfDataParser::InitPerfDataAndLoad(const std::deque<uint8_t>& dequeBuffer,
36 uint64_t size,
37 uint64_t offset,
38 bool isSplitFile,
39 bool isFinish)
40 {
41 if (isSplitFile) {
42 return SplitPerfData(dequeBuffer, size, offset, isFinish);
43 }
44
45 bufferSize_ = size;
46 buffer_ = std::make_unique<uint8_t[]>(size);
47 std::copy(dequeBuffer.begin(), dequeBuffer.begin() + size, buffer_.get());
48 LoadPerfData();
49 buffer_.reset();
50 return size;
51 }
52
DataProcessingLength(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t offset,bool isFinish)53 uint64_t PerfDataParser::DataProcessingLength(const std::deque<uint8_t>& dequeBuffer,
54 uint64_t size,
55 uint64_t offset,
56 bool isFinish)
57 {
58 using PerfSplitFunc = bool (PerfDataParser::*)(const std::deque<uint8_t>&, uint64_t, uint64_t&, bool&);
59 std::vector<PerfSplitFunc> splitFunc = {&PerfDataParser::SplitPerfStarting,
60 &PerfDataParser::SplitPerfParsingHead,
61 &PerfDataParser::SplitPerfWaitForAttr,
62 &PerfDataParser::SplitPerfParsingAttr,
63 &PerfDataParser::SplitPerfWaitForData,
64 &PerfDataParser::SplitPerfParsingData,
65 &PerfDataParser::SplitPerfParsingFeatureSection,
66 &PerfDataParser::SplitPerfWaitForFinish};
67
68 if (static_cast<size_t>(splitState_) >= splitFunc.size()) {
69 TS_LOGE("Invalid split state %d", splitState_);
70 perfSplitError_ = true;
71 SplitDataWithdraw();
72 return size;
73 }
74 uint64_t processedLen = 0;
75 bool ret = true;
76 bool invalid = false;
77 while (ret) {
78 if (isFinish && splitState_ == SplitPerfState::WAIT_FOR_FINISH) {
79 uint64_t currentDataOffset = perfDataOffset_ + processedLength_ + processedLen;
80 HtraceSplitResult offsetData = {.type = (int32_t)SplitDataDataType::SPLIT_FILE_JSON,
81 .originSeg = {.offset = currentDataOffset, .size = size - processedLen}};
82 splitResult_.emplace_back(offsetData);
83 processedLength_ += size;
84 return size;
85 }
86
87 ret = (this->*splitFunc[static_cast<int32_t>(splitState_)])(dequeBuffer, size, processedLen, invalid);
88 if (invalid) {
89 perfSplitError_ = true;
90 SplitDataWithdraw();
91 return size;
92 }
93 }
94
95 if (isFinish) {
96 TS_LOGE("split not finish but data end");
97 perfSplitError_ = true;
98 SplitDataWithdraw();
99 return size;
100 }
101
102 processedLength_ += processedLen;
103 return processedLen;
104 }
105
SplitPerfData(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t offset,bool isFinish)106 uint64_t PerfDataParser::SplitPerfData(const std::deque<uint8_t>& dequeBuffer,
107 uint64_t size,
108 uint64_t offset,
109 bool isFinish)
110 {
111 if (processedLength_ == 0) {
112 perfDataOffset_ = offset;
113 perfSplitError_ = false;
114 }
115
116 if (perfSplitError_) {
117 return size;
118 }
119
120 uint64_t datalength = DataProcessingLength(dequeBuffer, size, offset, isFinish);
121 return datalength;
122 }
123
SplitPerfStarting(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t & processedLen,bool & invalid)124 bool PerfDataParser::SplitPerfStarting(const std::deque<uint8_t>& dequeBuffer,
125 uint64_t size,
126 uint64_t& processedLen,
127 bool& invalid)
128 {
129 if (hasProfilerHead_) {
130 HtraceSplitResult htraceHead = {.type = (int32_t)SplitDataDataType::SPLIT_FILE_DATA,
131 .buffer = {.address = reinterpret_cast<uint8_t*>(&profilerHeader_),
132 .size = sizeof(ProfilerTraceFileHeader)}};
133 splitResult_.emplace_back(htraceHead);
134 }
135
136 splitState_ = SplitPerfState::PARSING_HEAD;
137 return true;
138 }
139
SplitPerfParsingHead(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t & processedLen,bool & invalid)140 bool PerfDataParser::SplitPerfParsingHead(const std::deque<uint8_t>& dequeBuffer,
141 uint64_t size,
142 uint64_t& processedLen,
143 bool& invalid)
144 {
145 processedLen = 0;
146 if (size < sizeof(perf_file_header)) {
147 return false;
148 }
149
150 std::copy_n(dequeBuffer.begin(), sizeof(perf_file_header), reinterpret_cast<char*>(&perfHeader_));
151
152 if (memcmp(perfHeader_.magic, PERF_MAGIC, sizeof(perfHeader_.magic))) {
153 TS_LOGE("invalid magic id");
154 invalid = true;
155 return false;
156 }
157
158 const int fetureMax = 256;
159 const int sizeFetureCount = 8;
160 featureCount_ = 0;
161 for (auto i = 0; i < fetureMax / sizeFetureCount; i++) {
162 std::bitset<sizeFetureCount> features(perfHeader_.features[i]);
163 for (auto j = 0; j < sizeFetureCount; j++) {
164 if (features.test(j)) {
165 featureCount_++;
166 }
167 }
168 }
169
170 HtraceSplitResult perfHead = {
171 .type = (int32_t)SplitDataDataType::SPLIT_FILE_DATA,
172 .buffer = {.address = reinterpret_cast<uint8_t*>(&perfHeader_), .size = sizeof(perf_file_header)}};
173 splitResult_.emplace_back(perfHead);
174 processedLen += sizeof(perf_file_header);
175 splitState_ = SplitPerfState::WAIT_FOR_ATTR;
176 return true;
177 }
178
SplitPerfWaitForAttr(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t & processedLen,bool & invalid)179 bool PerfDataParser::SplitPerfWaitForAttr(const std::deque<uint8_t>& dequeBuffer,
180 uint64_t size,
181 uint64_t& processedLen,
182 bool& invalid)
183 {
184 if (processedLength_ + processedLen > perfHeader_.attrs.offset) {
185 TS_LOGE("offset of attr is wrong %" PRIu64 "", perfHeader_.attrs.offset);
186 invalid = true;
187 return false;
188 }
189
190 if (processedLength_ + size < perfHeader_.attrs.offset) {
191 processedLen = size;
192 return false;
193 }
194
195 processedLen += perfHeader_.attrs.offset - (processedLength_ + processedLen);
196 splitState_ = SplitPerfState::PARSING_ATTR;
197 return true;
198 }
199
SplitPerfParsingAttr(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t & processedLen,bool & invalid)200 bool PerfDataParser::SplitPerfParsingAttr(const std::deque<uint8_t>& dequeBuffer,
201 uint64_t size,
202 uint64_t& processedLen,
203 bool& invalid)
204 {
205 int attrCount = perfHeader_.attrs.size / perfHeader_.attrSize;
206 if (attrCount == 0) {
207 TS_LOGE("no attr in file");
208 invalid = true;
209 return false;
210 }
211
212 uint64_t LengthRemain = size - processedLen;
213 if (LengthRemain < perfHeader_.attrs.size) {
214 return false;
215 }
216
217 auto buffer = std::make_unique<uint8_t[]>(perfHeader_.attrs.size);
218 std::copy_n(dequeBuffer.begin() + processedLen, perfHeader_.attrs.size, buffer.get());
219 std::vector<perf_file_attr> vecAttr;
220 for (int index = 0; index < attrCount; ++index) {
221 perf_file_attr* attr = reinterpret_cast<perf_file_attr*>(buffer.get() + perfHeader_.attrSize * index);
222 vecAttr.push_back(*attr);
223 // for Update Clock Type
224 if (index == 0) {
225 useClockId_ = attr->attr.use_clockid;
226 clockId_ = attr->attr.clockid;
227 TS_LOGI("useClockId_ = %u, clockId_ = %u", useClockId_, clockId_);
228 }
229 }
230
231 sampleType_ = vecAttr[0].attr.sample_type;
232 if (!(sampleType_ & PERF_SAMPLE_TIME)) {
233 TS_LOGE("no time in sample data, not support split, sampleType_ = %" PRIx64 "", sampleType_);
234 invalid = true;
235 return false;
236 }
237 sampleTimeOffset_ = (((sampleType_ & PERF_SAMPLE_IDENTIFIER) != 0) + ((sampleType_ & PERF_SAMPLE_IP) != 0) +
238 ((sampleType_ & PERF_SAMPLE_TID) != 0)) *
239 sizeof(uint64_t);
240
241 processedLen += perfHeader_.attrs.size;
242 splitState_ = SplitPerfState::WAIT_FOR_DATA;
243 return true;
244 }
245
SplitPerfWaitForData(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t & processedLen,bool & invalid)246 bool PerfDataParser::SplitPerfWaitForData(const std::deque<uint8_t>& dequeBuffer,
247 uint64_t size,
248 uint64_t& processedLen,
249 bool& invalid)
250 {
251 if (processedLength_ + processedLen > perfHeader_.data.offset) {
252 TS_LOGE("offset of data is wrong %" PRIu64 "", perfHeader_.data.offset);
253 invalid = true;
254 return false;
255 }
256
257 if (processedLength_ + size < perfHeader_.data.offset) {
258 processedLen = size;
259 return false;
260 }
261
262 HtraceSplitResult offsetData = {.type = (int32_t)SplitDataDataType::SPLIT_FILE_JSON,
263 .originSeg = {.offset = perfDataOffset_ + sizeof(perf_file_header),
264 .size = perfHeader_.data.offset - sizeof(perf_file_header)}};
265 splitResult_.emplace_back(offsetData);
266
267 processedLen += perfHeader_.data.offset - (processedLength_ + processedLen);
268 splitState_ = SplitPerfState::PARSING_DATA;
269 return true;
270 }
271
DataLengthProcessing(const std::deque<uint8_t> & dequeBuffer,perf_event_header & dataHeader,uint64_t size,uint64_t & processedLen,bool & invalid)272 SplitPerfState PerfDataParser::DataLengthProcessing(const std::deque<uint8_t>& dequeBuffer,
273 perf_event_header& dataHeader,
274 uint64_t size,
275 uint64_t& processedLen,
276 bool& invalid)
277 {
278 uint64_t totalDataRemain = perfHeader_.data.offset + perfHeader_.data.size - processedLength_ - processedLen;
279 if (totalDataRemain < sizeof(perf_event_header)) {
280 processedLen += totalDataRemain;
281 splitDataSize_ += totalDataRemain;
282 splitState_ = SplitPerfState::PARSING_FEATURE_SECTION;
283 return SplitPerfState::PARSING_HEAD;
284 }
285
286 uint64_t LengthRemain = size - processedLen;
287 if (LengthRemain < sizeof(perf_event_header)) {
288 return SplitPerfState::STARTING;
289 }
290 std::copy_n(dequeBuffer.begin() + processedLen, sizeof(perf_event_header), reinterpret_cast<char*>(&dataHeader));
291 if (dataHeader.size < sizeof(perf_event_header)) {
292 TS_LOGE("invalid data size %u", dataHeader.size);
293 invalid = true;
294 return SplitPerfState::STARTING;
295 }
296 if (LengthRemain < dataHeader.size) {
297 return SplitPerfState::STARTING;
298 }
299 if (totalDataRemain < sizeof(perf_event_header)) {
300 processedLen += totalDataRemain;
301 splitDataSize_ += totalDataRemain;
302 splitState_ = SplitPerfState::PARSING_FEATURE_SECTION;
303 return SplitPerfState::PARSING_HEAD;
304 }
305 return SplitPerfState::WAIT_FOR_ATTR;
306 }
307
SplitPerfParsingData(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t & processedLen,bool & invalid)308 bool PerfDataParser::SplitPerfParsingData(const std::deque<uint8_t>& dequeBuffer,
309 uint64_t size,
310 uint64_t& processedLen,
311 bool& invalid)
312 {
313 perf_event_header dataHeader;
314 auto ret = DataLengthProcessing(dequeBuffer, dataHeader, size, processedLen, invalid);
315 if (SplitPerfState::STARTING == ret) {
316 return false;
317 } else if (SplitPerfState::PARSING_HEAD == ret) {
318 return true;
319 }
320 bool needRecord = true;
321 if (splitDataEnd_) {
322 needRecord = false;
323 } else if (dataHeader.type == PERF_RECORD_SAMPLE) {
324 auto buffer = std::make_unique<uint8_t[]>(dataHeader.size);
325 std::copy_n(dequeBuffer.begin() + processedLen + sizeof(perf_event_header),
326 dataHeader.size - sizeof(perf_event_header), buffer.get());
327 uint64_t time = *(reinterpret_cast<uint64_t*>(buffer.get() + sampleTimeOffset_));
328 uint64_t newTimeStamp = 0;
329 if (useClockId_ != 0) {
330 newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(perfToTSClockType_.at(clockId_), time);
331 }
332 UpdatePluginTimeRange(perfToTSClockType_.at(clockId_), time, newTimeStamp);
333 if (newTimeStamp < traceDataCache_->SplitFileMinTime()) {
334 needRecord = false;
335 } else if (newTimeStamp > traceDataCache_->SplitFileMaxTime()) {
336 splitDataEnd_ = true;
337 needRecord = false;
338 }
339 }
340
341 if (needRecord) {
342 uint64_t currentDataOffset = perfDataOffset_ + processedLength_ + processedLen;
343 if (splitResult_.rbegin() != splitResult_.rend() &&
344 (splitResult_.rbegin()->originSeg.offset + splitResult_.rbegin()->originSeg.size == currentDataOffset)) {
345 splitResult_.rbegin()->originSeg.size += dataHeader.size;
346 } else {
347 HtraceSplitResult offsetData = {.type = (int32_t)SplitDataDataType::SPLIT_FILE_JSON,
348 .originSeg = {.offset = currentDataOffset, .size = dataHeader.size}};
349 splitResult_.emplace_back(offsetData);
350 }
351 splitDataSize_ += dataHeader.size;
352 }
353 processedLen += dataHeader.size;
354 return true;
355 }
356
SplitPerfParsingFeatureSection(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t & processedLen,bool & invalid)357 bool PerfDataParser::SplitPerfParsingFeatureSection(const std::deque<uint8_t>& dequeBuffer,
358 uint64_t size,
359 uint64_t& processedLen,
360 bool& invalid)
361 {
362 featureSectioSize_ = featureCount_ * sizeof(perf_file_section);
363 if (featureSectioSize_ == 0) {
364 TS_LOGI("no feature section in file");
365 splitState_ = SplitPerfState::WAIT_FOR_FINISH;
366 return false;
367 }
368
369 uint64_t LengthRemain = size - processedLen;
370 if (LengthRemain < featureSectioSize_) {
371 return false;
372 }
373
374 featureSection_ = std::make_unique<uint8_t[]>(featureSectioSize_);
375 std::copy_n(dequeBuffer.begin() + processedLen, featureSectioSize_, featureSection_.get());
376 uint64_t splitDropSize = perfHeader_.data.size - splitDataSize_;
377 for (auto i = 0; i < featureCount_; ++i) {
378 perf_file_section* featureSections = reinterpret_cast<perf_file_section*>(featureSection_.get());
379 featureSections[i].offset -= splitDropSize;
380 }
381 HtraceSplitResult featureBuff = {.type = (int32_t)SplitDataDataType::SPLIT_FILE_DATA,
382 .buffer = {.address = featureSection_.get(), .size = featureSectioSize_}};
383 splitResult_.emplace_back(featureBuff);
384
385 processedLen += featureSectioSize_;
386 perfHeader_.data.size = splitDataSize_;
387 profilerHeader_.data.length -= splitDropSize;
388 splitState_ = SplitPerfState::WAIT_FOR_FINISH;
389 return true;
390 }
391
SplitPerfWaitForFinish(const std::deque<uint8_t> & dequeBuffer,uint64_t size,uint64_t & processedLen,bool & invalid)392 bool PerfDataParser::SplitPerfWaitForFinish(const std::deque<uint8_t>& dequeBuffer,
393 uint64_t size,
394 uint64_t& processedLen,
395 bool& invalid)
396 {
397 return false;
398 }
399
~PerfDataParser()400 PerfDataParser::~PerfDataParser()
401 {
402 recordDataReader_.reset();
403 if (remove(tmpPerfData_.c_str()) == -1) {
404 TS_LOGE("remove %s err:%s\n", tmpPerfData_.c_str(), strerror(errno));
405 }
406 TS_LOGI("perf data ts MIN:%llu, MAX:%llu", static_cast<unsigned long long>(GetPluginStartTime()),
407 static_cast<unsigned long long>(GetPluginEndTime()));
408 }
409
PerfReloadSymbolFiles(std::vector<std::string> & symbolsPaths)410 bool PerfDataParser::PerfReloadSymbolFiles(std::vector<std::string>& symbolsPaths)
411 {
412 if (access(tmpPerfData_.c_str(), F_OK) != 0) {
413 TS_LOGE("perf file:%s not exist", tmpPerfData_.c_str());
414 return false;
415 }
416 recordDataReader_ = PerfFileReader::Instance(tmpPerfData_);
417 report_ = std::make_unique<Report>();
418 report_->virtualRuntime_.SetSymbolsPaths(symbolsPaths);
419 if (recordDataReader_ == nullptr) {
420 return false;
421 }
422 if (Reload()) {
423 Finish();
424 return true;
425 } else {
426 return false;
427 }
428 }
LoadPerfData()429 bool PerfDataParser::LoadPerfData()
430 {
431 // try load the perf data
432 int32_t fd(base::OpenFile(tmpPerfData_, O_CREAT | O_RDWR, TS_PERMISSION_RW));
433 if (!fd) {
434 fprintf(stdout, "Failed to create file: %s", tmpPerfData_.c_str());
435 return false;
436 }
437 (void)ftruncate(fd, 0);
438 if (bufferSize_ != (size_t)write(fd, buffer_.get(), bufferSize_)) {
439 close(fd);
440 return false;
441 }
442 close(fd);
443 recordDataReader_ = PerfFileReader::Instance(tmpPerfData_);
444 if (recordDataReader_ == nullptr) {
445 return false;
446 }
447 report_ = std::make_unique<Report>();
448 return Reload();
449 }
Reload()450 bool PerfDataParser::Reload()
451 {
452 pidAndStackHashToCallChainId_.Clear();
453 fileDataDictIdToFileId_.clear();
454 tidToPid_.clear();
455 streamFilters_->perfDataFilter_->BeforeReload();
456 traceDataCache_->GetPerfSampleData()->Clear();
457 traceDataCache_->GetPerfThreadData()->Clear();
458
459 if (!recordDataReader_->ReadFeatureSection()) {
460 printf("record format error.\n");
461 return false;
462 }
463 // update perf report table
464 UpdateEventConfigInfo();
465 UpdateReportWorkloadInfo();
466 UpdateCmdlineInfo();
467
468 // update perf Files table
469 UpdateSymbolAndFilesData();
470
471 TS_LOGD("process record");
472 UpdateClockType();
473 recordDataReader_->ReadDataSection(std::bind(&PerfDataParser::RecordCallBack, this, std::placeholders::_1));
474 TS_LOGD("process record completed");
475 TS_LOGI("load perf data done");
476 return true;
477 }
478
UpdateEventConfigInfo()479 void PerfDataParser::UpdateEventConfigInfo()
480 {
481 auto features = recordDataReader_->GetFeatures();
482 cpuOffMode_ = find(features.begin(), features.end(), FEATURE::HIPERF_CPU_OFF) != features.end();
483 if (cpuOffMode_) {
484 TS_LOGD("this is cpuOffMode ");
485 }
486 const PerfFileSection* featureSection = recordDataReader_->GetFeatureSection(FEATURE::EVENT_DESC);
487 if (featureSection) {
488 TS_LOGI("have EVENT_DESC");
489 LoadEventDesc();
490 } else {
491 TS_LOGE("Do not have EVENT_DESC !!!");
492 }
493 }
494
LoadEventDesc()495 void PerfDataParser::LoadEventDesc()
496 {
497 const auto featureSection = recordDataReader_->GetFeatureSection(FEATURE::EVENT_DESC);
498 const auto& sectionEventdesc = *static_cast<const PerfFileSectionEventDesc*>(featureSection);
499 TS_LOGI("Event descriptions: %zu", sectionEventdesc.eventDesces_.size());
500 for (size_t i = 0; i < sectionEventdesc.eventDesces_.size(); i++) {
501 const auto& fileAttr = sectionEventdesc.eventDesces_[i];
502 TS_LOGI("event name[%zu]: %s ids: %s", i, fileAttr.name.c_str(), VectorToString(fileAttr.ids).c_str());
503 for (uint64_t id : fileAttr.ids) {
504 report_->configIdIndexMaps_[id] = report_->configs_.size(); // setup index
505 TS_LOGI("add config id map %" PRIu64 " to %zu", id, report_->configs_.size());
506 }
507 // when cpuOffMode_ , don't use count mode , use time mode.
508 auto& config = report_->configs_.emplace_back(fileAttr.name, fileAttr.attr.type, fileAttr.attr.config,
509 cpuOffMode_ ? false : true);
510 config.ids_ = fileAttr.ids;
511 TS_ASSERT(config.ids_.size() > 0);
512
513 auto perfReportData = traceDataCache_->GetPerfReportData();
514 auto configValueIndex = traceDataCache_->dataDict_.GetStringIndex(fileAttr.name.c_str());
515 perfReportData->AppendNewPerfReport(configNameIndex_, configValueIndex);
516 }
517 }
518
UpdateReportWorkloadInfo() const519 void PerfDataParser::UpdateReportWorkloadInfo() const
520 {
521 // workload
522 auto featureSection = recordDataReader_->GetFeatureSection(FEATURE::HIPERF_WORKLOAD_CMD);
523 std::string workloader = "";
524 if (featureSection) {
525 TS_LOGI("found HIPERF_META_WORKLOAD_CMD");
526 auto sectionString = static_cast<const PerfFileSectionString*>(featureSection);
527 workloader = sectionString->toString();
528 } else {
529 TS_LOGW("NOT found HIPERF_META_WORKLOAD_CMD");
530 }
531 if (workloader.empty()) {
532 TS_LOGW("NOT found HIPERF_META_WORKLOAD_CMD");
533 return;
534 }
535 auto perfReportData = traceDataCache_->GetPerfReportData();
536 auto workloaderValueIndex = traceDataCache_->dataDict_.GetStringIndex(workloader.c_str());
537 perfReportData->AppendNewPerfReport(workloaderIndex_, workloaderValueIndex);
538 }
539
UpdateCmdlineInfo() const540 void PerfDataParser::UpdateCmdlineInfo() const
541 {
542 auto cmdline = recordDataReader_->GetFeatureString(FEATURE::CMDLINE);
543 auto perfReportData = traceDataCache_->GetPerfReportData();
544 auto cmdlineValueIndex = traceDataCache_->dataDict_.GetStringIndex(cmdline.c_str());
545 perfReportData->AppendNewPerfReport(cmdlineIndex_, cmdlineValueIndex);
546 }
547
UpdateSymbolAndFilesData()548 void PerfDataParser::UpdateSymbolAndFilesData()
549 {
550 // we need unwind it (for function name match) even not give us path
551 report_->virtualRuntime_.SetDisableUnwind(false);
552
553 // found symbols in file
554 const auto featureSection = recordDataReader_->GetFeatureSection(FEATURE::HIPERF_FILES_SYMBOL);
555 if (featureSection != nullptr) {
556 const PerfFileSectionSymbolsFiles* sectionSymbolsFiles =
557 static_cast<const PerfFileSectionSymbolsFiles*>(featureSection);
558 report_->virtualRuntime_.UpdateFromPerfData(sectionSymbolsFiles->symbolFileStructs_);
559 }
560 // fileid, symbolIndex, filePathIndex
561 uint64_t fileId = 0;
562 for (auto& symbolsFile : report_->virtualRuntime_.GetSymbolsFiles()) {
563 auto filePathIndex = traceDataCache_->dataDict_.GetStringIndex(symbolsFile->filePath_.c_str());
564 uint32_t serial = 0;
565 for (auto& symbol : symbolsFile->GetSymbols()) {
566 auto symbolIndex = traceDataCache_->dataDict_.GetStringIndex(symbol.GetName());
567 streamFilters_->statFilter_->IncreaseStat(TRACE_PERF, STAT_EVENT_RECEIVED);
568 streamFilters_->perfDataFilter_->AppendPerfFiles(fileId, serial++, symbolIndex, filePathIndex);
569 }
570 if (symbolsFile->GetSymbols().size() == 0) {
571 streamFilters_->perfDataFilter_->AppendPerfFiles(fileId, INVALID_UINT32, INVALID_DATAINDEX, filePathIndex);
572 }
573 fileDataDictIdToFileId_.insert(std::make_pair(filePathIndex, fileId));
574 ++fileId;
575 }
576 }
UpdateClockType()577 void PerfDataParser::UpdateClockType()
578 {
579 const auto& attrIds_ = recordDataReader_->GetAttrSection();
580 if (attrIds_.size() > 0) {
581 useClockId_ = attrIds_[0].attr.use_clockid;
582 clockId_ = attrIds_[0].attr.clockid;
583 TS_LOGI("useClockId_ = %u, clockId_ = %u", useClockId_, clockId_);
584 }
585 }
RecordCallBack(std::unique_ptr<PerfEventRecord> record)586 bool PerfDataParser::RecordCallBack(std::unique_ptr<PerfEventRecord> record)
587 {
588 // tell process tree what happend for rebuild symbols
589 report_->virtualRuntime_.UpdateFromRecord(*record);
590
591 if (record->GetType() == PERF_RECORD_SAMPLE) {
592 std::unique_ptr<PerfRecordSample> sample(static_cast<PerfRecordSample*>(record.release()));
593 uint32_t callChainId = UpdateCallChainUnCompressed(sample);
594 UpdatePerfSampleData(callChainId, sample);
595 } else if (record->GetType() == PERF_RECORD_COMM) {
596 auto recordComm = static_cast<PerfRecordComm*>(record.get());
597 auto range = tidToPid_.equal_range(recordComm->data_.tid);
598 for (auto it = range.first; it != range.second; it++) {
599 if (it->second == recordComm->data_.pid) {
600 return true;
601 }
602 }
603 tidToPid_.insert(std::make_pair(recordComm->data_.tid, recordComm->data_.pid));
604 auto perfThreadData = traceDataCache_->GetPerfThreadData();
605 auto threadNameIndex = traceDataCache_->dataDict_.GetStringIndex(recordComm->data_.comm);
606 perfThreadData->AppendNewPerfThread(recordComm->data_.pid, recordComm->data_.tid, threadNameIndex);
607 }
608 return true;
609 }
610
UpdateCallChainUnCompressed(const std::unique_ptr<PerfRecordSample> & sample)611 uint32_t PerfDataParser::UpdateCallChainUnCompressed(const std::unique_ptr<PerfRecordSample>& sample)
612 {
613 std::string stackStr = "";
614 for (auto& callFrame : sample->callFrames_) {
615 stackStr += "+" + base::number(callFrame.ip_, base::INTEGER_RADIX_TYPE_HEX);
616 }
617 auto stackHash = hashFun_(stackStr);
618 auto pid = sample->data_.pid;
619 auto callChainId = pidAndStackHashToCallChainId_.Find(pid, stackHash);
620 if (callChainId != INVALID_UINT32) {
621 return callChainId;
622 }
623 callChainId = ++callChainId_;
624 pidAndStackHashToCallChainId_.Insert(pid, stackHash, callChainId);
625 uint64_t depth = 0;
626 for (auto frame = sample->callFrames_.rbegin(); frame != sample->callFrames_.rend(); ++frame) {
627 uint64_t fileId = INVALID_UINT64;
628 auto fileDataIndex = traceDataCache_->dataDict_.GetStringIndex(frame->filePath_);
629 if (fileDataDictIdToFileId_.count(fileDataIndex) != 0) {
630 fileId = fileDataDictIdToFileId_.at(fileDataIndex);
631 }
632 streamFilters_->perfDataFilter_->AppendPerfCallChain(callChainId, depth++, frame->ip_, frame->vaddrInFile_,
633 fileId, frame->symbolIndex_);
634 }
635 return callChainId;
636 }
637
UpdatePerfSampleData(uint32_t callChainId,std::unique_ptr<PerfRecordSample> & sample)638 void PerfDataParser::UpdatePerfSampleData(uint32_t callChainId, std::unique_ptr<PerfRecordSample>& sample)
639 {
640 auto perfSampleData = traceDataCache_->GetPerfSampleData();
641 uint64_t newTimeStamp = 0;
642 if (useClockId_ == 0) {
643 newTimeStamp = sample->data_.time;
644 } else {
645 newTimeStamp =
646 streamFilters_->clockFilter_->ToPrimaryTraceTime(perfToTSClockType_.at(clockId_), sample->data_.time);
647 }
648 UpdatePluginTimeRange(perfToTSClockType_.at(clockId_), sample->data_.time, newTimeStamp);
649
650 DataIndex threadStatIndex = unkonwnStateIndex_;
651 auto threadState = report_->GetConfigName(sample->data_.id);
652 if (threadState.compare(wakingEventName_) == 0) {
653 threadStatIndex = runingStateIndex_;
654 } else if (threadState.compare(cpuOffEventName_) == 0) {
655 threadStatIndex = suspendStatIndex_;
656 }
657 auto configIndex = report_->GetConfigIndex(sample->data_.id);
658 perfSampleData->AppendNewPerfSample(callChainId, sample->data_.time, sample->data_.tid, sample->data_.period,
659 configIndex, newTimeStamp, sample->data_.cpu, threadStatIndex);
660 }
661
Finish()662 void PerfDataParser::Finish()
663 {
664 if (!traceDataCache_->isSplitFile_) {
665 streamFilters_->perfDataFilter_->Finish();
666 }
667 // Update trace_range when there is only perf data in the trace file
668 if (traceDataCache_->traceStartTime_ == INVALID_UINT64 || traceDataCache_->traceEndTime_ == 0) {
669 traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime());
670 } else {
671 TS_LOGI("perfData time is not updated, maybe this trace file has other data");
672 }
673 pidAndStackHashToCallChainId_.Clear();
674 }
675 } // namespace TraceStreamer
676 } // namespace SysTuning
677