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