2 * Copyright (C) 2016 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <android-base/logging.h>
21 #include <android-base/file.h>
24 #include "event_attr.h"
25 #include "event_type.h"
26 #include "record_file.h"
27 #include "thread_tree.h"
34 #define EXPORT __attribute__((visibility("default")))
40 const char* thread_comm;
59 uint64_t vaddr_in_file;
60 const char* symbol_name;
66 struct CallChainEntry {
73 CallChainEntry* entries;
76 struct FeatureSection {
81 // Create a new instance,
82 // pass the instance to the other functions below.
83 ReportLib* CreateReportLib() EXPORT;
84 void DestroyReportLib(ReportLib* report_lib) EXPORT;
86 // Set log severity, different levels are:
87 // verbose, debug, info, warning, error, fatal.
88 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) EXPORT;
89 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) EXPORT;
90 bool SetRecordFile(ReportLib* report_lib, const char* record_file) EXPORT;
91 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) EXPORT;
92 void ShowIpForUnknownSymbol(ReportLib* report_lib) EXPORT;
94 Sample* GetNextSample(ReportLib* report_lib) EXPORT;
95 Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT;
96 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT;
97 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT;
99 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT;
100 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) EXPORT;
103 struct EventAttrWithName {
104 perf_event_attr attr;
109 UPDATE_FLAG_OF_SAMPLE = 1 << 0,
110 UPDATE_FLAG_OF_EVENT = 1 << 1,
111 UPDATE_FLAG_OF_SYMBOL = 1 << 2,
112 UPDATE_FLAG_OF_CALLCHAIN = 1 << 3,
119 new android::base::ScopedLogSeverity(android::base::INFO)),
120 record_filename_("perf.data"),
121 current_thread_(nullptr),
123 trace_offcpu_(false) {
126 bool SetLogSeverity(const char* log_level);
128 bool SetSymfs(const char* symfs_dir) { return Dso::SetSymFsDir(symfs_dir); }
130 bool SetRecordFile(const char* record_file) {
131 record_filename_ = record_file;
135 bool SetKallsymsFile(const char* kallsyms_file);
137 void ShowIpForUnknownSymbol() { thread_tree_.ShowIpForUnknownSymbol(); }
139 Sample* GetNextSample();
140 Event* GetEventOfCurrentSample();
141 SymbolEntry* GetSymbolOfCurrentSample();
142 CallChain* GetCallChainOfCurrentSample();
144 const char* GetBuildIdForPath(const char* path);
145 FeatureSection* GetFeatureSection(const char* feature_name);
148 Sample* GetCurrentSample();
149 bool OpenRecordFileIfNecessary();
150 Mapping* AddMapping(const MapEntry& map);
152 std::unique_ptr<android::base::ScopedLogSeverity> log_severity_;
153 std::string record_filename_;
154 std::unique_ptr<RecordFileReader> record_file_reader_;
155 ThreadTree thread_tree_;
156 std::unique_ptr<SampleRecord> current_record_;
157 const ThreadEntry* current_thread_;
158 Sample current_sample_;
159 Event current_event_;
160 SymbolEntry current_symbol_;
161 CallChain current_callchain_;
162 std::vector<std::unique_ptr<Mapping>> current_mappings_;
163 std::vector<CallChainEntry> callchain_entries_;
164 std::string build_id_string_;
166 std::vector<EventAttrWithName> event_attrs_;
167 std::unique_ptr<ScopedEventTypes> scoped_event_types_;
169 std::unordered_map<pid_t, std::unique_ptr<SampleRecord>> next_sample_cache_;
170 FeatureSection feature_section_;
171 std::vector<char> feature_section_data_;
174 bool ReportLib::SetLogSeverity(const char* log_level) {
175 android::base::LogSeverity severity;
176 if (!GetLogSeverity(log_level, &severity)) {
177 LOG(ERROR) << "Unknown log severity: " << log_level;
180 log_severity_ = nullptr;
181 log_severity_.reset(new android::base::ScopedLogSeverity(severity));
185 bool ReportLib::SetKallsymsFile(const char* kallsyms_file) {
186 std::string kallsyms;
187 if (!android::base::ReadFileToString(kallsyms_file, &kallsyms)) {
188 LOG(WARNING) << "Failed to read in kallsyms file from " << kallsyms_file;
191 Dso::SetKallsyms(std::move(kallsyms));
195 bool ReportLib::OpenRecordFileIfNecessary() {
196 if (record_file_reader_ == nullptr) {
197 record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
198 if (record_file_reader_ == nullptr) {
201 record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_);
202 std::unordered_map<std::string, std::string> meta_info_map;
203 if (record_file_reader_->HasFeature(PerfFileFormat::FEAT_META_INFO) &&
204 !record_file_reader_->ReadMetaInfoFeature(&meta_info_map)) {
207 auto it = meta_info_map.find("event_type_info");
208 if (it != meta_info_map.end()) {
209 scoped_event_types_.reset(new ScopedEventTypes(it->second));
211 it = meta_info_map.find("trace_offcpu");
212 if (it != meta_info_map.end()) {
213 trace_offcpu_ = it->second == "true";
219 Sample* ReportLib::GetNextSample() {
220 if (!OpenRecordFileIfNecessary()) {
224 std::unique_ptr<Record> record;
225 if (!record_file_reader_->ReadRecord(record)) {
228 if (record == nullptr) {
231 thread_tree_.Update(*record);
232 if (record->type() == PERF_RECORD_SAMPLE) {
234 SampleRecord* r = static_cast<SampleRecord*>(record.release());
235 auto it = next_sample_cache_.find(r->tid_data.tid);
236 if (it == next_sample_cache_.end()) {
237 next_sample_cache_[r->tid_data.tid].reset(r);
240 record.reset(it->second.release());
244 current_record_.reset(static_cast<SampleRecord*>(record.release()));
249 current_mappings_.clear();
250 return GetCurrentSample();
253 Sample* ReportLib::GetCurrentSample() {
254 if (!(update_flag_ & UPDATE_FLAG_OF_SAMPLE)) {
255 SampleRecord& r = *current_record_;
256 current_sample_.ip = r.ip_data.ip;
257 current_sample_.pid = r.tid_data.pid;
258 current_sample_.tid = r.tid_data.tid;
260 thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
261 current_sample_.thread_comm = current_thread_->comm;
262 current_sample_.time = r.time_data.time;
263 current_sample_.in_kernel = r.InKernel();
264 current_sample_.cpu = r.cpu_data.cpu;
266 uint64_t next_time = std::max(next_sample_cache_[r.tid_data.tid]->time_data.time,
267 r.time_data.time + 1);
268 current_sample_.period = next_time - r.time_data.time;
270 current_sample_.period = r.period_data.period;
272 update_flag_ |= UPDATE_FLAG_OF_SAMPLE;
274 return ¤t_sample_;
277 Event* ReportLib::GetEventOfCurrentSample() {
278 if (!(update_flag_ & UPDATE_FLAG_OF_EVENT)) {
279 if (event_attrs_.empty()) {
280 std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
281 for (const auto& attr_with_id : attrs) {
282 EventAttrWithName attr;
283 attr.attr = *attr_with_id.attr;
284 attr.name = GetEventNameByAttr(attr.attr);
285 event_attrs_.push_back(attr);
290 // For trace-offcpu, we don't want to show event sched:sched_switch.
293 attr_index = record_file_reader_->GetAttrIndexOfRecord(current_record_.get());
295 current_event_.name = event_attrs_[attr_index].name.c_str();
296 update_flag_ |= UPDATE_FLAG_OF_EVENT;
298 return ¤t_event_;
301 SymbolEntry* ReportLib::GetSymbolOfCurrentSample() {
302 if (!(update_flag_ & UPDATE_FLAG_OF_SYMBOL)) {
303 SampleRecord& r = *current_record_;
304 const MapEntry* map =
305 thread_tree_.FindMap(current_thread_, r.ip_data.ip, r.InKernel());
306 uint64_t vaddr_in_file;
307 const Symbol* symbol =
308 thread_tree_.FindSymbol(map, r.ip_data.ip, &vaddr_in_file);
309 current_symbol_.dso_name = map->dso->Path().c_str();
310 current_symbol_.vaddr_in_file = vaddr_in_file;
311 current_symbol_.symbol_name = symbol->DemangledName();
312 current_symbol_.symbol_addr = symbol->addr;
313 current_symbol_.symbol_len = symbol->len;
314 current_symbol_.mapping = AddMapping(*map);
315 update_flag_ |= UPDATE_FLAG_OF_SYMBOL;
317 return ¤t_symbol_;
320 CallChain* ReportLib::GetCallChainOfCurrentSample() {
321 if (!(update_flag_ & UPDATE_FLAG_OF_CALLCHAIN)) {
322 SampleRecord& r = *current_record_;
323 callchain_entries_.clear();
325 if (r.sample_type & PERF_SAMPLE_CALLCHAIN) {
326 bool first_ip = true;
327 bool in_kernel = r.InKernel();
328 for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) {
329 uint64_t ip = r.callchain_data.ips[i];
330 if (ip >= PERF_CONTEXT_MAX) {
332 case PERF_CONTEXT_KERNEL:
335 case PERF_CONTEXT_USER:
339 LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex
345 // Remove duplication with sample ip.
346 if (ip == r.ip_data.ip) {
350 const MapEntry* map =
351 thread_tree_.FindMap(current_thread_, ip, in_kernel);
352 uint64_t vaddr_in_file;
353 const Symbol* symbol =
354 thread_tree_.FindSymbol(map, ip, &vaddr_in_file);
355 CallChainEntry entry;
357 entry.symbol.dso_name = map->dso->Path().c_str();
358 entry.symbol.vaddr_in_file = vaddr_in_file;
359 entry.symbol.symbol_name = symbol->DemangledName();
360 entry.symbol.symbol_addr = symbol->addr;
361 entry.symbol.symbol_len = symbol->len;
362 entry.symbol.mapping = AddMapping(*map);
363 callchain_entries_.push_back(entry);
367 current_callchain_.nr = callchain_entries_.size();
368 current_callchain_.entries = callchain_entries_.data();
369 update_flag_ |= UPDATE_FLAG_OF_CALLCHAIN;
371 return ¤t_callchain_;
374 Mapping* ReportLib::AddMapping(const MapEntry& map) {
375 current_mappings_.emplace_back(std::unique_ptr<Mapping>(new Mapping));
376 Mapping* mapping = current_mappings_.back().get();
377 mapping->start = map.start_addr;
378 mapping->end = map.start_addr + map.len;
379 mapping->pgoff = map.pgoff;
383 const char* ReportLib::GetBuildIdForPath(const char* path) {
384 if (!OpenRecordFileIfNecessary()) {
385 build_id_string_.clear();
386 return build_id_string_.c_str();
388 BuildId build_id = Dso::FindExpectedBuildIdForPath(path);
389 if (build_id.IsEmpty()) {
390 build_id_string_.clear();
392 build_id_string_ = build_id.ToString();
394 return build_id_string_.c_str();
397 FeatureSection* ReportLib::GetFeatureSection(const char* feature_name) {
398 if (!OpenRecordFileIfNecessary()) {
401 int feature = PerfFileFormat::GetFeatureId(feature_name);
402 if (feature == -1 || !record_file_reader_->ReadFeatureSection(feature, &feature_section_data_)) {
405 feature_section_.data = feature_section_data_.data();
406 feature_section_.data_size = feature_section_data_.size();
407 return &feature_section_;
410 // Exported methods working with a client created instance
411 ReportLib* CreateReportLib() {
412 return new ReportLib();
415 void DestroyReportLib(ReportLib* report_lib) {
419 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) {
420 return report_lib->SetLogSeverity(log_level);
423 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) {
424 return report_lib->SetSymfs(symfs_dir);
427 bool SetRecordFile(ReportLib* report_lib, const char* record_file) {
428 return report_lib->SetRecordFile(record_file);
431 void ShowIpForUnknownSymbol(ReportLib* report_lib) {
432 return report_lib->ShowIpForUnknownSymbol();
435 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) {
436 return report_lib->SetKallsymsFile(kallsyms_file);
439 Sample* GetNextSample(ReportLib* report_lib) {
440 return report_lib->GetNextSample();
443 Event* GetEventOfCurrentSample(ReportLib* report_lib) {
444 return report_lib->GetEventOfCurrentSample();
447 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) {
448 return report_lib->GetSymbolOfCurrentSample();
451 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) {
452 return report_lib->GetCallChainOfCurrentSample();
455 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
456 return report_lib->GetBuildIdForPath(path);
459 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) {
460 return report_lib->GetFeatureSection(feature_name);