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 §ionEventdesc = *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