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