OSDN Git Service

Merge "simpleperf: replace config file with cmdline options." am: e5ad887a62 am:...
[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 "record_file.h"
26 #include "thread_tree.h"
27 #include "utils.h"
28
29 class ReportLib;
30
31 extern "C" {
32
33 #define EXPORT __attribute__((visibility("default")))
34
35 struct Sample {
36   uint64_t ip;
37   uint32_t pid;
38   uint32_t tid;
39   const char* thread_comm;
40   uint64_t time;
41   uint32_t in_kernel;
42   uint32_t cpu;
43   uint64_t period;
44 };
45
46 struct Event {
47   const char* name;
48 };
49
50 struct Mapping {
51   uint64_t start;
52   uint64_t end;
53   uint64_t pgoff;
54 };
55
56 struct SymbolEntry {
57   const char* dso_name;
58   uint64_t vaddr_in_file;
59   const char* symbol_name;
60   uint64_t symbol_addr;
61   Mapping* mapping;
62 };
63
64 struct CallChainEntry {
65   uint64_t ip;
66   SymbolEntry symbol;
67 };
68
69 struct CallChain {
70   uint32_t nr;
71   CallChainEntry* entries;
72 };
73
74 // Create a new instance,
75 // pass the instance to the other functions below.
76 ReportLib* CreateReportLib() EXPORT;
77 void DestroyReportLib(ReportLib* report_lib) EXPORT;
78
79 // Set log severity, different levels are:
80 // verbose, debug, info, warning, error, fatal.
81 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) EXPORT;
82 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) EXPORT;
83 bool SetRecordFile(ReportLib* report_lib, const char* record_file) EXPORT;
84 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) EXPORT;
85 void ShowIpForUnknownSymbol(ReportLib* report_lib) EXPORT;
86
87 Sample* GetNextSample(ReportLib* report_lib) EXPORT;
88 Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT;
89 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT;
90 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT;
91
92 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT;
93 }
94
95 struct EventAttrWithName {
96   perf_event_attr attr;
97   std::string name;
98 };
99
100 enum {
101   UPDATE_FLAG_OF_SAMPLE = 1 << 0,
102   UPDATE_FLAG_OF_EVENT = 1 << 1,
103   UPDATE_FLAG_OF_SYMBOL = 1 << 2,
104   UPDATE_FLAG_OF_CALLCHAIN = 1 << 3,
105 };
106
107 class ReportLib {
108  public:
109   ReportLib()
110       : log_severity_(
111             new android::base::ScopedLogSeverity(android::base::INFO)),
112         record_filename_("perf.data"),
113         current_thread_(nullptr),
114         update_flag_(0)
115          {}
116
117   bool SetLogSeverity(const char* log_level);
118
119   bool SetSymfs(const char* symfs_dir) { return Dso::SetSymFsDir(symfs_dir); }
120
121   bool SetRecordFile(const char* record_file) {
122     record_filename_ = record_file;
123     return true;
124   }
125
126   bool SetKallsymsFile(const char* kallsyms_file);
127
128   void ShowIpForUnknownSymbol() { thread_tree_.ShowIpForUnknownSymbol(); }
129
130   Sample* GetNextSample();
131   Event* GetEventOfCurrentSample();
132   SymbolEntry* GetSymbolOfCurrentSample();
133   CallChain* GetCallChainOfCurrentSample();
134
135   const char* GetBuildIdForPath(const char* path);
136
137  private:
138   Sample* GetCurrentSample();
139   bool OpenRecordFileIfNecessary();
140   Mapping* AddMapping(const MapEntry& map);
141
142   std::unique_ptr<android::base::ScopedLogSeverity> log_severity_;
143   std::string record_filename_;
144   std::unique_ptr<RecordFileReader> record_file_reader_;
145   ThreadTree thread_tree_;
146   std::unique_ptr<SampleRecord> current_record_;
147   const ThreadEntry* current_thread_;
148   Sample current_sample_;
149   Event current_event_;
150   SymbolEntry current_symbol_;
151   CallChain current_callchain_;
152   std::vector<std::unique_ptr<Mapping>> current_mappings_;
153   std::vector<CallChainEntry> callchain_entries_;
154   std::string build_id_string_;
155   int update_flag_;
156   std::vector<EventAttrWithName> event_attrs_;
157 };
158
159 bool ReportLib::SetLogSeverity(const char* log_level) {
160   android::base::LogSeverity severity;
161   if (!GetLogSeverity(log_level, &severity)) {
162     LOG(ERROR) << "Unknown log severity: " << log_level;
163     return false;
164   }
165   log_severity_ = nullptr;
166   log_severity_.reset(new android::base::ScopedLogSeverity(severity));
167   return true;
168 }
169
170 bool ReportLib::SetKallsymsFile(const char* kallsyms_file) {
171   std::string kallsyms;
172   if (!android::base::ReadFileToString(kallsyms_file, &kallsyms)) {
173     LOG(WARNING) << "Failed to read in kallsyms file from " << kallsyms_file;
174     return false;
175   }
176   Dso::SetKallsyms(std::move(kallsyms));
177   return true;
178 }
179
180 bool ReportLib::OpenRecordFileIfNecessary() {
181   if (record_file_reader_ == nullptr) {
182     record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
183     if (record_file_reader_ == nullptr) {
184       return false;
185     }
186     record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_);
187   }
188   return true;
189 }
190
191 Sample* ReportLib::GetNextSample() {
192   if (!OpenRecordFileIfNecessary()) {
193     return nullptr;
194   }
195   while (true) {
196     std::unique_ptr<Record> record;
197     if (!record_file_reader_->ReadRecord(record)) {
198       return nullptr;
199     }
200     if (record == nullptr) {
201       return nullptr;
202     }
203     thread_tree_.Update(*record);
204     if (record->type() == PERF_RECORD_SAMPLE) {
205       current_record_.reset(static_cast<SampleRecord*>(record.release()));
206       break;
207     }
208   }
209   update_flag_ = 0;
210   current_mappings_.clear();
211   return GetCurrentSample();
212 }
213
214 Sample* ReportLib::GetCurrentSample() {
215   if (!(update_flag_ & UPDATE_FLAG_OF_SAMPLE)) {
216     SampleRecord& r = *current_record_;
217     current_sample_.ip = r.ip_data.ip;
218     current_sample_.pid = r.tid_data.pid;
219     current_sample_.tid = r.tid_data.tid;
220     current_thread_ =
221         thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
222     current_sample_.thread_comm = current_thread_->comm;
223     current_sample_.time = r.time_data.time;
224     current_sample_.in_kernel = r.InKernel();
225     current_sample_.cpu = r.cpu_data.cpu;
226     current_sample_.period = r.period_data.period;
227     update_flag_ |= UPDATE_FLAG_OF_SAMPLE;
228   }
229   return &current_sample_;
230 }
231
232 Event* ReportLib::GetEventOfCurrentSample() {
233   if (!(update_flag_ & UPDATE_FLAG_OF_EVENT)) {
234     if (event_attrs_.empty()) {
235       std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
236       for (const auto& attr_with_id : attrs) {
237         EventAttrWithName attr;
238         attr.attr = *attr_with_id.attr;
239         attr.name = GetEventNameByAttr(attr.attr);
240         event_attrs_.push_back(attr);
241       }
242     }
243     size_t attr_index =
244         record_file_reader_->GetAttrIndexOfRecord(current_record_.get());
245     current_event_.name = event_attrs_[attr_index].name.c_str();
246     update_flag_ |= UPDATE_FLAG_OF_EVENT;
247   }
248   return &current_event_;
249 }
250
251 SymbolEntry* ReportLib::GetSymbolOfCurrentSample() {
252   if (!(update_flag_ & UPDATE_FLAG_OF_SYMBOL)) {
253     SampleRecord& r = *current_record_;
254     const MapEntry* map =
255         thread_tree_.FindMap(current_thread_, r.ip_data.ip, r.InKernel());
256     uint64_t vaddr_in_file;
257     const Symbol* symbol =
258         thread_tree_.FindSymbol(map, r.ip_data.ip, &vaddr_in_file);
259     current_symbol_.dso_name = map->dso->Path().c_str();
260     current_symbol_.vaddr_in_file = vaddr_in_file;
261     current_symbol_.symbol_name = symbol->DemangledName();
262     current_symbol_.symbol_addr = symbol->addr;
263     current_symbol_.mapping = AddMapping(*map);
264     update_flag_ |= UPDATE_FLAG_OF_SYMBOL;
265   }
266   return &current_symbol_;
267 }
268
269 CallChain* ReportLib::GetCallChainOfCurrentSample() {
270   if (!(update_flag_ & UPDATE_FLAG_OF_CALLCHAIN)) {
271     SampleRecord& r = *current_record_;
272     callchain_entries_.clear();
273
274     if (r.sample_type & PERF_SAMPLE_CALLCHAIN) {
275       bool first_ip = true;
276       bool in_kernel = r.InKernel();
277       for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) {
278         uint64_t ip = r.callchain_data.ips[i];
279         if (ip >= PERF_CONTEXT_MAX) {
280           switch (ip) {
281             case PERF_CONTEXT_KERNEL:
282               in_kernel = true;
283               break;
284             case PERF_CONTEXT_USER:
285               in_kernel = false;
286               break;
287             default:
288               LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex
289                          << ip;
290           }
291         } else {
292           if (first_ip) {
293             first_ip = false;
294             // Remove duplication with sample ip.
295             if (ip == r.ip_data.ip) {
296               continue;
297             }
298           }
299           const MapEntry* map =
300               thread_tree_.FindMap(current_thread_, ip, in_kernel);
301           uint64_t vaddr_in_file;
302           const Symbol* symbol =
303               thread_tree_.FindSymbol(map, ip, &vaddr_in_file);
304           CallChainEntry entry;
305           entry.ip = ip;
306           entry.symbol.dso_name = map->dso->Path().c_str();
307           entry.symbol.vaddr_in_file = vaddr_in_file;
308           entry.symbol.symbol_name = symbol->DemangledName();
309           entry.symbol.symbol_addr = symbol->addr;
310           entry.symbol.mapping = AddMapping(*map);
311           callchain_entries_.push_back(entry);
312         }
313       }
314     }
315     current_callchain_.nr = callchain_entries_.size();
316     current_callchain_.entries = callchain_entries_.data();
317     update_flag_ |= UPDATE_FLAG_OF_CALLCHAIN;
318   }
319   return &current_callchain_;
320 }
321
322 Mapping* ReportLib::AddMapping(const MapEntry& map) {
323   current_mappings_.emplace_back(std::unique_ptr<Mapping>(new Mapping));
324   Mapping* mapping = current_mappings_.back().get();
325   mapping->start = map.start_addr;
326   mapping->end = map.start_addr + map.len;
327   mapping->pgoff = map.pgoff;
328   return mapping;
329 }
330
331 const char* ReportLib::GetBuildIdForPath(const char* path) {
332   if (!OpenRecordFileIfNecessary()) {
333     build_id_string_.clear();
334     return build_id_string_.c_str();
335   }
336   BuildId build_id = Dso::FindExpectedBuildIdForPath(path);
337   if (build_id.IsEmpty()) {
338     build_id_string_.clear();
339   } else {
340     build_id_string_ = build_id.ToString();
341   }
342   return build_id_string_.c_str();
343 }
344
345 // Exported methods working with a client created instance
346 ReportLib* CreateReportLib() {
347   return new ReportLib();
348 }
349
350 void DestroyReportLib(ReportLib* report_lib) {
351   delete report_lib;
352 }
353
354 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) {
355   return report_lib->SetLogSeverity(log_level);
356 }
357
358 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) {
359   return report_lib->SetSymfs(symfs_dir);
360 }
361
362 bool SetRecordFile(ReportLib* report_lib, const char* record_file) {
363   return report_lib->SetRecordFile(record_file);
364 }
365
366 void ShowIpForUnknownSymbol(ReportLib* report_lib) {
367   return report_lib->ShowIpForUnknownSymbol();
368 }
369
370 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) {
371   return report_lib->SetKallsymsFile(kallsyms_file);
372 }
373
374 Sample* GetNextSample(ReportLib* report_lib) {
375   return report_lib->GetNextSample();
376 }
377
378 Event* GetEventOfCurrentSample(ReportLib* report_lib) {
379   return report_lib->GetEventOfCurrentSample();
380 }
381
382 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) {
383   return report_lib->GetSymbolOfCurrentSample();
384 }
385
386 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) {
387   return report_lib->GetCallChainOfCurrentSample();
388 }
389
390 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
391   return report_lib->GetBuildIdForPath(path);
392 }