OSDN Git Service

Merge "Perfprofd: Factor out threaded handler" into pi-dev
[android-x86/system-extras.git] / simpleperf / report_lib_interface.cpp
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <memory>
18 #include <utility>
19
20 #include <android-base/logging.h>
21 #include <android-base/file.h>
22
23 #include "dso.h"
24 #include "event_attr.h"
25 #include "event_type.h"
26 #include "record_file.h"
27 #include "thread_tree.h"
28 #include "utils.h"
29
30 class ReportLib;
31
32 extern "C" {
33
34 #define EXPORT __attribute__((visibility("default")))
35
36 struct Sample {
37   uint64_t ip;
38   uint32_t pid;
39   uint32_t tid;
40   const char* thread_comm;
41   uint64_t time;
42   uint32_t in_kernel;
43   uint32_t cpu;
44   uint64_t period;
45 };
46
47 struct Event {
48   const char* name;
49 };
50
51 struct Mapping {
52   uint64_t start;
53   uint64_t end;
54   uint64_t pgoff;
55 };
56
57 struct SymbolEntry {
58   const char* dso_name;
59   uint64_t vaddr_in_file;
60   const char* symbol_name;
61   uint64_t symbol_addr;
62   uint64_t symbol_len;
63   Mapping* mapping;
64 };
65
66 struct CallChainEntry {
67   uint64_t ip;
68   SymbolEntry symbol;
69 };
70
71 struct CallChain {
72   uint32_t nr;
73   CallChainEntry* entries;
74 };
75
76 struct FeatureSection {
77   const char* data;
78   uint32_t data_size;
79 };
80
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;
85
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;
93
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;
98
99 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT;
100 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) EXPORT;
101 }
102
103 struct EventAttrWithName {
104   perf_event_attr attr;
105   std::string name;
106 };
107
108 enum {
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,
113 };
114
115 class ReportLib {
116  public:
117   ReportLib()
118       : log_severity_(
119             new android::base::ScopedLogSeverity(android::base::INFO)),
120         record_filename_("perf.data"),
121         current_thread_(nullptr),
122         update_flag_(0),
123         trace_offcpu_(false) {
124   }
125
126   bool SetLogSeverity(const char* log_level);
127
128   bool SetSymfs(const char* symfs_dir) { return Dso::SetSymFsDir(symfs_dir); }
129
130   bool SetRecordFile(const char* record_file) {
131     record_filename_ = record_file;
132     return true;
133   }
134
135   bool SetKallsymsFile(const char* kallsyms_file);
136
137   void ShowIpForUnknownSymbol() { thread_tree_.ShowIpForUnknownSymbol(); }
138
139   Sample* GetNextSample();
140   Event* GetEventOfCurrentSample();
141   SymbolEntry* GetSymbolOfCurrentSample();
142   CallChain* GetCallChainOfCurrentSample();
143
144   const char* GetBuildIdForPath(const char* path);
145   FeatureSection* GetFeatureSection(const char* feature_name);
146
147  private:
148   Sample* GetCurrentSample();
149   bool OpenRecordFileIfNecessary();
150   Mapping* AddMapping(const MapEntry& map);
151
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_;
165   int update_flag_;
166   std::vector<EventAttrWithName> event_attrs_;
167   std::unique_ptr<ScopedEventTypes> scoped_event_types_;
168   bool trace_offcpu_;
169   std::unordered_map<pid_t, std::unique_ptr<SampleRecord>> next_sample_cache_;
170   FeatureSection feature_section_;
171   std::vector<char> feature_section_data_;
172 };
173
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;
178     return false;
179   }
180   log_severity_ = nullptr;
181   log_severity_.reset(new android::base::ScopedLogSeverity(severity));
182   return true;
183 }
184
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;
189     return false;
190   }
191   Dso::SetKallsyms(std::move(kallsyms));
192   return true;
193 }
194
195 bool ReportLib::OpenRecordFileIfNecessary() {
196   if (record_file_reader_ == nullptr) {
197     record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
198     if (record_file_reader_ == nullptr) {
199       return false;
200     }
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)) {
205       return false;
206     }
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));
210     }
211     it = meta_info_map.find("trace_offcpu");
212     if (it != meta_info_map.end()) {
213       trace_offcpu_ = it->second == "true";
214     }
215   }
216   return true;
217 }
218
219 Sample* ReportLib::GetNextSample() {
220   if (!OpenRecordFileIfNecessary()) {
221     return nullptr;
222   }
223   while (true) {
224     std::unique_ptr<Record> record;
225     if (!record_file_reader_->ReadRecord(record)) {
226       return nullptr;
227     }
228     if (record == nullptr) {
229       return nullptr;
230     }
231     thread_tree_.Update(*record);
232     if (record->type() == PERF_RECORD_SAMPLE) {
233       if (trace_offcpu_) {
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);
238           continue;
239         } else {
240           record.reset(it->second.release());
241           it->second.reset(r);
242         }
243       }
244       current_record_.reset(static_cast<SampleRecord*>(record.release()));
245       break;
246     }
247   }
248   update_flag_ = 0;
249   current_mappings_.clear();
250   return GetCurrentSample();
251 }
252
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;
259     current_thread_ =
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;
265     if (trace_offcpu_) {
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;
269     } else {
270       current_sample_.period = r.period_data.period;
271     }
272     update_flag_ |= UPDATE_FLAG_OF_SAMPLE;
273   }
274   return &current_sample_;
275 }
276
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);
286       }
287     }
288     size_t attr_index;
289     if (trace_offcpu_) {
290       // For trace-offcpu, we don't want to show event sched:sched_switch.
291       attr_index = 0;
292     } else {
293       attr_index = record_file_reader_->GetAttrIndexOfRecord(current_record_.get());
294     }
295     current_event_.name = event_attrs_[attr_index].name.c_str();
296     update_flag_ |= UPDATE_FLAG_OF_EVENT;
297   }
298   return &current_event_;
299 }
300
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;
316   }
317   return &current_symbol_;
318 }
319
320 CallChain* ReportLib::GetCallChainOfCurrentSample() {
321   if (!(update_flag_ & UPDATE_FLAG_OF_CALLCHAIN)) {
322     SampleRecord& r = *current_record_;
323     callchain_entries_.clear();
324
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) {
331           switch (ip) {
332             case PERF_CONTEXT_KERNEL:
333               in_kernel = true;
334               break;
335             case PERF_CONTEXT_USER:
336               in_kernel = false;
337               break;
338             default:
339               LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex
340                          << ip;
341           }
342         } else {
343           if (first_ip) {
344             first_ip = false;
345             // Remove duplication with sample ip.
346             if (ip == r.ip_data.ip) {
347               continue;
348             }
349           }
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;
356           entry.ip = ip;
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);
364         }
365       }
366     }
367     current_callchain_.nr = callchain_entries_.size();
368     current_callchain_.entries = callchain_entries_.data();
369     update_flag_ |= UPDATE_FLAG_OF_CALLCHAIN;
370   }
371   return &current_callchain_;
372 }
373
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;
380   return mapping;
381 }
382
383 const char* ReportLib::GetBuildIdForPath(const char* path) {
384   if (!OpenRecordFileIfNecessary()) {
385     build_id_string_.clear();
386     return build_id_string_.c_str();
387   }
388   BuildId build_id = Dso::FindExpectedBuildIdForPath(path);
389   if (build_id.IsEmpty()) {
390     build_id_string_.clear();
391   } else {
392     build_id_string_ = build_id.ToString();
393   }
394   return build_id_string_.c_str();
395 }
396
397 FeatureSection* ReportLib::GetFeatureSection(const char* feature_name) {
398   if (!OpenRecordFileIfNecessary()) {
399     return nullptr;
400   }
401   int feature = PerfFileFormat::GetFeatureId(feature_name);
402   if (feature == -1 || !record_file_reader_->ReadFeatureSection(feature, &feature_section_data_)) {
403     return nullptr;
404   }
405   feature_section_.data = feature_section_data_.data();
406   feature_section_.data_size = feature_section_data_.size();
407   return &feature_section_;
408 }
409
410 // Exported methods working with a client created instance
411 ReportLib* CreateReportLib() {
412   return new ReportLib();
413 }
414
415 void DestroyReportLib(ReportLib* report_lib) {
416   delete report_lib;
417 }
418
419 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) {
420   return report_lib->SetLogSeverity(log_level);
421 }
422
423 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) {
424   return report_lib->SetSymfs(symfs_dir);
425 }
426
427 bool SetRecordFile(ReportLib* report_lib, const char* record_file) {
428   return report_lib->SetRecordFile(record_file);
429 }
430
431 void ShowIpForUnknownSymbol(ReportLib* report_lib) {
432   return report_lib->ShowIpForUnknownSymbol();
433 }
434
435 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) {
436   return report_lib->SetKallsymsFile(kallsyms_file);
437 }
438
439 Sample* GetNextSample(ReportLib* report_lib) {
440   return report_lib->GetNextSample();
441 }
442
443 Event* GetEventOfCurrentSample(ReportLib* report_lib) {
444   return report_lib->GetEventOfCurrentSample();
445 }
446
447 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) {
448   return report_lib->GetSymbolOfCurrentSample();
449 }
450
451 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) {
452   return report_lib->GetCallChainOfCurrentSample();
453 }
454
455 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
456   return report_lib->GetBuildIdForPath(path);
457 }
458
459 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) {
460   return report_lib->GetFeatureSection(feature_name);
461 }