• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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