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