• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "perf_data_parser.h"
16 #include "perf_data_filter.h"
17 #include "stat_filter.h"
18 
19 namespace SysTuning {
20 namespace TraceStreamer {
PerfDataParser(TraceDataCache * dataCache,const TraceStreamerFilters * ctx)21 PerfDataParser::PerfDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx)
22     : HtracePluginTimeParser(dataCache, ctx), frameToCallChainId_(INVALID_UINT64)
23 {
24     configNameIndex_ = traceDataCache_->dataDict_.GetStringIndex("config_name");
25     workloaderIndex_ = traceDataCache_->dataDict_.GetStringIndex("workload_cmd");
26     cmdlineIndex_ = traceDataCache_->dataDict_.GetStringIndex("cmdline");
27     runingStateIndex_ = traceDataCache_->dataDict_.GetStringIndex("Running");
28     suspendStatIndex_ = traceDataCache_->dataDict_.GetStringIndex("Suspend");
29     unkonwnStateIndex_ = traceDataCache_->dataDict_.GetStringIndex("-");
30 }
InitPerfDataAndLoad(const std::deque<uint8_t> dequeBuffer,uint64_t size)31 void PerfDataParser::InitPerfDataAndLoad(const std::deque<uint8_t> dequeBuffer, uint64_t size)
32 {
33     bufferSize_ = size;
34     buffer_ = std::make_unique<uint8_t[]>(size);
35     std::copy(dequeBuffer.begin(), dequeBuffer.begin() + size, buffer_.get());
36     LoadPerfData();
37 }
~PerfDataParser()38 PerfDataParser::~PerfDataParser()
39 {
40     TS_LOGI("perf data ts MIN:%llu, MAX:%llu", static_cast<unsigned long long>(GetPluginStartTime()),
41             static_cast<unsigned long long>(GetPluginEndTime()));
42 }
43 
LoadPerfData()44 bool PerfDataParser::LoadPerfData()
45 {
46     TS_LOGI("enter");
47     // try load the perf data
48     recordDataReader_ = PerfFileReader::Instance(buffer_.get(), bufferSize_);
49     buffer_.release();
50     if (recordDataReader_ == nullptr) {
51         return false;
52     }
53 
54     if (!recordDataReader_->ReadFeatureSection()) {
55         printf("record format error.\n");
56         return false;
57     }
58     // update perf report table
59     UpdateEventConfigInfo();
60     UpdateReportWorkloadInfo();
61     UpdateCmdlineInfo();
62 
63     // update perf Files table
64     UpdateSymbolAndFilesData();
65 
66     TS_LOGD("process record");
67     UpdateClockType();
68     recordDataReader_->ReadDataSection(std::bind(&PerfDataParser::RecordCallBack, this, std::placeholders::_1));
69     TS_LOGD("process record completed");
70     TS_LOGI("load perf data done");
71     return true;
72 }
73 
UpdateEventConfigInfo()74 void PerfDataParser::UpdateEventConfigInfo()
75 {
76     auto features = recordDataReader_->GetFeatures();
77     cpuOffMode_ = find(features.begin(), features.end(), FEATURE::HIPERF_CPU_OFF) != features.end();
78     if (cpuOffMode_) {
79         TS_LOGD("this is cpuOffMode ");
80     }
81     const PerfFileSection* featureSection = recordDataReader_->GetFeatureSection(FEATURE::EVENT_DESC);
82     if (featureSection) {
83         TS_LOGI("have EVENT_DESC");
84         LoadEventDesc();
85     } else {
86         TS_LOGE("Do not have EVENT_DESC !!!");
87     }
88 }
89 
LoadEventDesc()90 void PerfDataParser::LoadEventDesc()
91 {
92     const auto featureSection = recordDataReader_->GetFeatureSection(FEATURE::EVENT_DESC);
93     const auto& sectionEventdesc = *static_cast<const PerfFileSectionEventDesc*>(featureSection);
94     TS_LOGI("Event descriptions: %zu", sectionEventdesc.eventDesces_.size());
95     for (size_t i = 0; i < sectionEventdesc.eventDesces_.size(); i++) {
96         const auto& fileAttr = sectionEventdesc.eventDesces_[i];
97         TS_LOGI("event name[%zu]: %s ids: %s", i, fileAttr.name.c_str(), VectorToString(fileAttr.ids).c_str());
98         for (uint64_t id : fileAttr.ids) {
99             report_.configIdIndexMaps_[id] = report_.configs_.size(); // setup index
100             TS_LOGI("add config id map %" PRIu64 " to %zu", id, report_.configs_.size());
101         }
102         // when cpuOffMode_ , don't use count mode , use time mode.
103         auto& config = report_.configs_.emplace_back(fileAttr.name, fileAttr.attr.type, fileAttr.attr.config,
104                                                      cpuOffMode_ ? false : true);
105         config.ids_ = fileAttr.ids;
106         TS_ASSERT(config.ids_.size() > 0);
107 
108         auto perfReportData = traceDataCache_->GetPerfReportData();
109         auto configValueIndex = traceDataCache_->dataDict_.GetStringIndex(fileAttr.name.c_str());
110         perfReportData->AppendNewPerfReport(configNameIndex_, configValueIndex);
111     }
112 }
113 
UpdateReportWorkloadInfo() const114 void PerfDataParser::UpdateReportWorkloadInfo() const
115 {
116     // workload
117     auto featureSection = recordDataReader_->GetFeatureSection(FEATURE::HIPERF_WORKLOAD_CMD);
118     std::string workloader = "";
119     if (featureSection) {
120         TS_LOGI("found HIPERF_META_WORKLOAD_CMD");
121         auto sectionString = static_cast<const PerfFileSectionString*>(featureSection);
122         workloader = sectionString->toString();
123     } else {
124         TS_LOGW("NOT found HIPERF_META_WORKLOAD_CMD");
125     }
126     if (workloader.empty()) {
127         TS_LOGW("NOT found HIPERF_META_WORKLOAD_CMD");
128         return;
129     }
130     auto perfReportData = traceDataCache_->GetPerfReportData();
131     auto workloaderValueIndex = traceDataCache_->dataDict_.GetStringIndex(workloader.c_str());
132     perfReportData->AppendNewPerfReport(workloaderIndex_, workloaderValueIndex);
133 }
134 
UpdateCmdlineInfo() const135 void PerfDataParser::UpdateCmdlineInfo() const
136 {
137     auto cmdline = recordDataReader_->GetFeatureString(FEATURE::CMDLINE);
138     auto perfReportData = traceDataCache_->GetPerfReportData();
139     auto cmdlineValueIndex = traceDataCache_->dataDict_.GetStringIndex(cmdline.c_str());
140     perfReportData->AppendNewPerfReport(cmdlineIndex_, cmdlineValueIndex);
141 }
142 
UpdateSymbolAndFilesData()143 void PerfDataParser::UpdateSymbolAndFilesData()
144 {
145     // we need unwind it (for function name match) even not give us path
146     report_.virtualRuntime_.SetDisableUnwind(false);
147 
148     // found symbols in file
149     const auto featureSection = recordDataReader_->GetFeatureSection(FEATURE::HIPERF_FILES_SYMBOL);
150     if (featureSection != nullptr) {
151         const PerfFileSectionSymbolsFiles* sectionSymbolsFiles =
152             static_cast<const PerfFileSectionSymbolsFiles*>(featureSection);
153         report_.virtualRuntime_.UpdateFromPerfData(sectionSymbolsFiles->symbolFileStructs_);
154     }
155     uint64_t fileId = 0;
156     for (auto& symbolsFile : report_.virtualRuntime_.GetSymbolsFiles()) {
157         auto filePathIndex = traceDataCache_->dataDict_.GetStringIndex(symbolsFile->filePath_.c_str());
158         uint32_t serial = 0;
159         for (auto& symbol : symbolsFile->GetSymbols()) {
160             auto symbolIndex = traceDataCache_->dataDict_.GetStringIndex(symbol.Name().data());
161             streamFilters_->statFilter_->IncreaseStat(TRACE_PERF, STAT_EVENT_RECEIVED);
162             streamFilters_->perfDataFilter_->AppendPerfFiles(fileId, serial++, symbolIndex, filePathIndex);
163         }
164         fileDataDictIdToFileId_.insert(std::make_pair(filePathIndex, fileId));
165         ++fileId;
166     }
167 }
UpdateClockType()168 void PerfDataParser::UpdateClockType()
169 {
170     const auto& attrIds_ = recordDataReader_->GetAttrSection();
171     if (attrIds_.size() > 0) {
172         useClockId_ = attrIds_[0].attr.use_clockid;
173         clockId_ = attrIds_[0].attr.clockid;
174         TS_LOGE("useClockId_ = %u, clockId_ = %u", useClockId_, clockId_);
175     }
176 }
RecordCallBack(std::unique_ptr<PerfEventRecord> record)177 bool PerfDataParser::RecordCallBack(std::unique_ptr<PerfEventRecord> record)
178 {
179     // tell process tree what happend for rebuild symbols
180     report_.virtualRuntime_.UpdateFromRecord(*record);
181 
182     if (record->GetType() == PERF_RECORD_SAMPLE) {
183         std::unique_ptr<PerfRecordSample> sample(static_cast<PerfRecordSample*>(record.release()));
184         auto callChainId = UpdatePerfCallChainData(sample);
185         UpdatePerfSampleData(callChainId, sample);
186     } else if (record->GetType() == PERF_RECORD_COMM) {
187         auto recordComm = static_cast<PerfRecordComm*>(record.get());
188         auto range = tidToPid_.equal_range(recordComm->data_.tid);
189         for (auto it = range.first; it != range.second; it++) {
190             if (it->second == recordComm->data_.pid) {
191                 return true;
192             }
193         }
194         tidToPid_.insert(std::make_pair(recordComm->data_.tid, recordComm->data_.pid));
195         auto perfThreadData = traceDataCache_->GetPerfThreadData();
196         auto threadNameIndex = traceDataCache_->dataDict_.GetStringIndex(recordComm->data_.comm);
197         perfThreadData->AppendNewPerfThread(recordComm->data_.pid, recordComm->data_.tid, threadNameIndex);
198     }
199     return true;
200 }
201 
UpdatePerfCallChainData(std::unique_ptr<PerfRecordSample> & sample)202 uint64_t PerfDataParser::UpdatePerfCallChainData(std::unique_ptr<PerfRecordSample>& sample)
203 {
204     uint64_t depth = 0;
205     bool callStackNotExist = false;
206     uint64_t callChainId = INVALID_UINT64;
207     std::vector<std::unique_ptr<CallStackTemp>> callStackTemp = {};
208     // Filter callstack unuse data
209     for (auto frame = sample->callFrames_.rbegin(); frame != sample->callFrames_.rend(); ++frame) {
210         auto symbolId = frame->symbolIndex_;
211         if (symbolId == -1 && frame->vaddrInFile_ == 0) {
212             continue;
213         }
214         auto fileDataIndex = traceDataCache_->dataDict_.GetStringIndex(frame->filePath_);
215         auto itor = fileDataDictIdToFileId_.find(fileDataIndex);
216         if (itor == fileDataDictIdToFileId_.end()) {
217             continue;
218         }
219         auto fileId = itor->second;
220         callStackTemp.emplace_back(
221             std::move(std::make_unique<CallStackTemp>(depth, frame->vaddrInFile_, fileId, symbolId)));
222         depth++;
223     }
224     // Determine whether to write callstack data to cache
225     auto size = callStackTemp.size();
226     for (auto itor = callStackTemp.begin(); itor != callStackTemp.end(); itor++) {
227         auto callstack = itor->get();
228         auto ret = frameToCallChainId_.Find(callstack->fileId_, callstack->symbolId_, callstack->depth_, size);
229         if (ret != INVALID_UINT64) { // find it
230             if (callChainId == INVALID_UINT64) {
231                 callChainId = ret;
232             } else if (callChainId != ret) {
233                 callStackNotExist = true;
234                 break;
235             }
236         } else { // not find it
237             callStackNotExist = true;
238             break;
239         }
240     }
241     // write callstack data to cache
242     if (callStackNotExist) {
243         callChainId = ++callChainId_;
244         for (auto itor = callStackTemp.begin(); itor != callStackTemp.end(); itor++) {
245             auto callstack = itor->get();
246             frameToCallChainId_.Insert(callstack->fileId_, callstack->symbolId_, callstack->depth_,
247                                        callStackTemp.size(), callChainId);
248             streamFilters_->perfDataFilter_->AppendPerfCallChain(
249                 callChainId, callstack->depth_, callstack->vaddrInFile_, callstack->fileId_, callstack->symbolId_);
250         }
251     }
252     callStackTemp.clear();
253     return callChainId;
254 }
255 
UpdatePerfSampleData(uint64_t callChainId,std::unique_ptr<PerfRecordSample> & sample)256 void PerfDataParser::UpdatePerfSampleData(uint64_t callChainId, std::unique_ptr<PerfRecordSample>& sample)
257 {
258     auto perfSampleData = traceDataCache_->GetPerfSampleData();
259     uint64_t newTimeStamp = 0;
260     if (useClockId_ == 0) {
261         newTimeStamp = sample->data_.time;
262     } else {
263         newTimeStamp =
264             streamFilters_->clockFilter_->ToPrimaryTraceTime(perfToTSClockType_.at(clockId_), sample->data_.time);
265     }
266     UpdatePluginTimeRange(perfToTSClockType_.at(clockId_), sample->data_.time, newTimeStamp);
267 
268     DataIndex threadStatIndex = unkonwnStateIndex_;
269     auto threadState = report_.GetConfigName(sample->data_.id);
270     if (threadState.compare(wakingEventName_) == 0) {
271         threadStatIndex = runingStateIndex_;
272     } else if (threadState.compare(cpuOffEventName_) == 0) {
273         threadStatIndex = suspendStatIndex_;
274     }
275     auto configIndex = report_.GetConfigIndex(sample->data_.id);
276     perfSampleData->AppendNewPerfSample(callChainId, sample->data_.time, sample->data_.tid, sample->data_.period,
277                                         configIndex, newTimeStamp, sample->data_.cpu, threadStatIndex);
278 }
279 
Finish()280 void PerfDataParser::Finish()
281 {
282     streamFilters_->perfDataFilter_->Finish();
283     // Update trace_range when there is only perf data in the trace file
284     if (traceDataCache_->traceStartTime_ == INVALID_UINT64 || traceDataCache_->traceEndTime_ == 0) {
285         traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime());
286     }
287     frameToCallChainId_.Clear();
288 }
289 } // namespace TraceStreamer
290 } // namespace SysTuning
291