• 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