• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <android-base/strings.h>
23 
24 #include "dso.h"
25 #include "event_attr.h"
26 #include "event_type.h"
27 #include "record_file.h"
28 #include "thread_tree.h"
29 #include "tracing.h"
30 #include "utils.h"
31 
32 class ReportLib;
33 
34 extern "C" {
35 
36 #define EXPORT __attribute__((visibility("default")))
37 
38 struct Sample {
39   uint64_t ip;
40   uint32_t pid;
41   uint32_t tid;
42   const char* thread_comm;
43   uint64_t time;
44   uint32_t in_kernel;
45   uint32_t cpu;
46   uint64_t period;
47 };
48 
49 struct TracingFieldFormat {
50   const char* name;
51   uint32_t offset;
52   uint32_t elem_size;
53   uint32_t elem_count;
54   uint32_t is_signed;
55 };
56 
57 struct TracingDataFormat {
58   uint32_t size;
59   uint32_t field_count;
60   TracingFieldFormat* fields;
61 };
62 
63 struct Event {
64   const char* name;
65   TracingDataFormat tracing_data_format;
66 };
67 
68 struct Mapping {
69   uint64_t start;
70   uint64_t end;
71   uint64_t pgoff;
72 };
73 
74 struct SymbolEntry {
75   const char* dso_name;
76   uint64_t vaddr_in_file;
77   const char* symbol_name;
78   uint64_t symbol_addr;
79   uint64_t symbol_len;
80   Mapping* mapping;
81 };
82 
83 struct CallChainEntry {
84   uint64_t ip;
85   SymbolEntry symbol;
86 };
87 
88 struct CallChain {
89   uint32_t nr;
90   CallChainEntry* entries;
91 };
92 
93 struct FeatureSection {
94   const char* data;
95   uint32_t data_size;
96 };
97 
98 // Create a new instance,
99 // pass the instance to the other functions below.
100 ReportLib* CreateReportLib() EXPORT;
101 void DestroyReportLib(ReportLib* report_lib) EXPORT;
102 
103 // Set log severity, different levels are:
104 // verbose, debug, info, warning, error, fatal.
105 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) EXPORT;
106 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) EXPORT;
107 bool SetRecordFile(ReportLib* report_lib, const char* record_file) EXPORT;
108 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) EXPORT;
109 void ShowIpForUnknownSymbol(ReportLib* report_lib) EXPORT;
110 void ShowArtFrames(ReportLib* report_lib, bool show) EXPORT;
111 
112 Sample* GetNextSample(ReportLib* report_lib) EXPORT;
113 Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT;
114 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT;
115 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT;
116 const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) EXPORT;
117 
118 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT;
119 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) EXPORT;
120 }
121 
122 struct EventInfo {
123   perf_event_attr attr;
124   std::string name;
125 
126   struct TracingInfo {
127     TracingDataFormat data_format;
128     std::vector<std::string> field_names;
129     std::vector<TracingFieldFormat> fields;
130   } tracing_info;
131 };
132 
133 class ReportLib {
134  public:
ReportLib()135   ReportLib()
136       : log_severity_(
137             new android::base::ScopedLogSeverity(android::base::INFO)),
138         record_filename_("perf.data"),
139         current_thread_(nullptr),
140         trace_offcpu_(false),
141         show_art_frames_(false) {
142   }
143 
144   bool SetLogSeverity(const char* log_level);
145 
SetSymfs(const char * symfs_dir)146   bool SetSymfs(const char* symfs_dir) { return Dso::SetSymFsDir(symfs_dir); }
147 
SetRecordFile(const char * record_file)148   bool SetRecordFile(const char* record_file) {
149     record_filename_ = record_file;
150     return true;
151   }
152 
153   bool SetKallsymsFile(const char* kallsyms_file);
154 
ShowIpForUnknownSymbol()155   void ShowIpForUnknownSymbol() { thread_tree_.ShowIpForUnknownSymbol(); }
ShowArtFrames(bool show)156   void ShowArtFrames(bool show) { show_art_frames_ = show; }
157 
158   Sample* GetNextSample();
GetEventOfCurrentSample()159   Event* GetEventOfCurrentSample() { return &current_event_; }
GetSymbolOfCurrentSample()160   SymbolEntry* GetSymbolOfCurrentSample() { return current_symbol_; }
GetCallChainOfCurrentSample()161   CallChain* GetCallChainOfCurrentSample() { return &current_callchain_; }
GetTracingDataOfCurrentSample()162   const char* GetTracingDataOfCurrentSample() { return current_tracing_data_; }
163 
164   const char* GetBuildIdForPath(const char* path);
165   FeatureSection* GetFeatureSection(const char* feature_name);
166 
167  private:
168   void SetCurrentSample();
169   const EventInfo* FindEventOfCurrentSample();
170   void CreateEvents();
171 
172   bool OpenRecordFileIfNecessary();
173   Mapping* AddMapping(const MapEntry& map);
174 
175   std::unique_ptr<android::base::ScopedLogSeverity> log_severity_;
176   std::string record_filename_;
177   std::unique_ptr<RecordFileReader> record_file_reader_;
178   ThreadTree thread_tree_;
179   std::unique_ptr<SampleRecord> current_record_;
180   const ThreadEntry* current_thread_;
181   Sample current_sample_;
182   Event current_event_;
183   SymbolEntry* current_symbol_;
184   CallChain current_callchain_;
185   const char* current_tracing_data_;
186   std::vector<std::unique_ptr<Mapping>> current_mappings_;
187   std::vector<CallChainEntry> callchain_entries_;
188   std::string build_id_string_;
189   std::vector<EventInfo> events_;
190   std::unique_ptr<ScopedEventTypes> scoped_event_types_;
191   bool trace_offcpu_;
192   std::unordered_map<pid_t, std::unique_ptr<SampleRecord>> next_sample_cache_;
193   FeatureSection feature_section_;
194   std::vector<char> feature_section_data_;
195   bool show_art_frames_;
196   std::unique_ptr<Tracing> tracing_;
197 };
198 
SetLogSeverity(const char * log_level)199 bool ReportLib::SetLogSeverity(const char* log_level) {
200   android::base::LogSeverity severity;
201   if (!GetLogSeverity(log_level, &severity)) {
202     LOG(ERROR) << "Unknown log severity: " << log_level;
203     return false;
204   }
205   log_severity_ = nullptr;
206   log_severity_.reset(new android::base::ScopedLogSeverity(severity));
207   return true;
208 }
209 
SetKallsymsFile(const char * kallsyms_file)210 bool ReportLib::SetKallsymsFile(const char* kallsyms_file) {
211   std::string kallsyms;
212   if (!android::base::ReadFileToString(kallsyms_file, &kallsyms)) {
213     LOG(WARNING) << "Failed to read in kallsyms file from " << kallsyms_file;
214     return false;
215   }
216   Dso::SetKallsyms(std::move(kallsyms));
217   return true;
218 }
219 
OpenRecordFileIfNecessary()220 bool ReportLib::OpenRecordFileIfNecessary() {
221   if (record_file_reader_ == nullptr) {
222     record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
223     if (record_file_reader_ == nullptr) {
224       return false;
225     }
226     record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_);
227     std::unordered_map<std::string, std::string> meta_info_map;
228     if (record_file_reader_->HasFeature(PerfFileFormat::FEAT_META_INFO) &&
229         !record_file_reader_->ReadMetaInfoFeature(&meta_info_map)) {
230       return false;
231     }
232     auto it = meta_info_map.find("event_type_info");
233     if (it != meta_info_map.end()) {
234       scoped_event_types_.reset(new ScopedEventTypes(it->second));
235     }
236     it = meta_info_map.find("trace_offcpu");
237     if (it != meta_info_map.end()) {
238       trace_offcpu_ = it->second == "true";
239     }
240   }
241   return true;
242 }
243 
GetNextSample()244 Sample* ReportLib::GetNextSample() {
245   if (!OpenRecordFileIfNecessary()) {
246     return nullptr;
247   }
248   while (true) {
249     std::unique_ptr<Record> record;
250     if (!record_file_reader_->ReadRecord(record)) {
251       return nullptr;
252     }
253     if (record == nullptr) {
254       return nullptr;
255     }
256     thread_tree_.Update(*record);
257     if (record->type() == PERF_RECORD_SAMPLE) {
258       if (trace_offcpu_) {
259         SampleRecord* r = static_cast<SampleRecord*>(record.release());
260         auto it = next_sample_cache_.find(r->tid_data.tid);
261         if (it == next_sample_cache_.end()) {
262           next_sample_cache_[r->tid_data.tid].reset(r);
263           continue;
264         } else {
265           record.reset(it->second.release());
266           it->second.reset(r);
267         }
268       }
269       current_record_.reset(static_cast<SampleRecord*>(record.release()));
270       break;
271     } else if (record->type() == PERF_RECORD_TRACING_DATA ||
272                record->type() == SIMPLE_PERF_RECORD_TRACING_DATA) {
273       const auto& r = *static_cast<TracingDataRecord*>(record.get());
274       tracing_.reset(new Tracing(std::vector<char>(r.data, r.data + r.data_size)));
275     }
276   }
277   SetCurrentSample();
278   return &current_sample_;
279 }
280 
SetCurrentSample()281 void ReportLib::SetCurrentSample() {
282   current_mappings_.clear();
283   callchain_entries_.clear();
284   SampleRecord& r = *current_record_;
285   current_sample_.ip = r.ip_data.ip;
286   current_sample_.pid = r.tid_data.pid;
287   current_sample_.tid = r.tid_data.tid;
288   current_thread_ = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
289   current_sample_.thread_comm = current_thread_->comm;
290   current_sample_.time = r.time_data.time;
291   current_sample_.in_kernel = r.InKernel();
292   current_sample_.cpu = r.cpu_data.cpu;
293   if (trace_offcpu_) {
294     uint64_t next_time = std::max(next_sample_cache_[r.tid_data.tid]->time_data.time,
295                                   r.time_data.time + 1);
296     current_sample_.period = next_time - r.time_data.time;
297   } else {
298     current_sample_.period = r.period_data.period;
299   }
300 
301   size_t kernel_ip_count;
302   std::vector<uint64_t> ips = r.GetCallChain(&kernel_ip_count);
303   std::vector<std::pair<uint64_t, const MapEntry*>> ip_maps;
304   bool near_java_method = false;
305   auto is_map_for_interpreter = [](const MapEntry* map) {
306     return android::base::EndsWith(map->dso->Path(), "/libart.so");
307   };
308   for (size_t i = 0; i < ips.size(); ++i) {
309     const MapEntry* map = thread_tree_.FindMap(current_thread_, ips[i], i < kernel_ip_count);
310     if (!show_art_frames_) {
311       // Remove interpreter frames both before and after the Java frame.
312       if (map->dso->IsForJavaMethod()) {
313         near_java_method = true;
314         while (!ip_maps.empty() && is_map_for_interpreter(ip_maps.back().second)) {
315           ip_maps.pop_back();
316         }
317       } else if (is_map_for_interpreter(map)){
318         if (near_java_method) {
319           continue;
320         }
321       } else {
322         near_java_method = false;
323       }
324     }
325     ip_maps.push_back(std::make_pair(ips[i], map));
326   }
327   for (auto& pair : ip_maps) {
328     uint64_t ip = pair.first;
329     const MapEntry* map = pair.second;
330     uint64_t vaddr_in_file;
331     const Symbol* symbol = thread_tree_.FindSymbol(map, ip, &vaddr_in_file);
332     CallChainEntry entry;
333     entry.ip = ip;
334     entry.symbol.dso_name = map->dso->Path().c_str();
335     entry.symbol.vaddr_in_file = vaddr_in_file;
336     entry.symbol.symbol_name = symbol->DemangledName();
337     entry.symbol.symbol_addr = symbol->addr;
338     entry.symbol.symbol_len = symbol->len;
339     entry.symbol.mapping = AddMapping(*map);
340     callchain_entries_.push_back(entry);
341   }
342   current_sample_.ip = callchain_entries_[0].ip;
343   current_symbol_ = &(callchain_entries_[0].symbol);
344   current_callchain_.nr = callchain_entries_.size() - 1;
345   current_callchain_.entries = &callchain_entries_[1];
346   const EventInfo* event = FindEventOfCurrentSample();
347   current_event_.name = event->name.c_str();
348   current_event_.tracing_data_format = event->tracing_info.data_format;
349   if (current_event_.tracing_data_format.size > 0u && (r.sample_type & PERF_SAMPLE_RAW)) {
350     CHECK_GE(r.raw_data.size, current_event_.tracing_data_format.size);
351     current_tracing_data_ = r.raw_data.data;
352   } else {
353     current_tracing_data_ = nullptr;
354   }
355 }
356 
FindEventOfCurrentSample()357 const EventInfo* ReportLib::FindEventOfCurrentSample() {
358   if (events_.empty()) {
359     CreateEvents();
360   }
361   size_t attr_index;
362   if (trace_offcpu_) {
363     // For trace-offcpu, we don't want to show event sched:sched_switch.
364     attr_index = 0;
365   } else {
366     attr_index = record_file_reader_->GetAttrIndexOfRecord(current_record_.get());
367   }
368   return &events_[attr_index];
369 }
370 
CreateEvents()371 void ReportLib::CreateEvents() {
372   std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
373   events_.resize(attrs.size());
374   for (size_t i = 0; i < attrs.size(); ++i) {
375     events_[i].attr = *attrs[i].attr;
376     events_[i].name = GetEventNameByAttr(events_[i].attr);
377     EventInfo::TracingInfo& tracing_info = events_[i].tracing_info;
378     if (events_[i].attr.type == PERF_TYPE_TRACEPOINT && tracing_) {
379       TracingFormat format = tracing_->GetTracingFormatHavingId(events_[i].attr.config);
380       tracing_info.field_names.resize(format.fields.size());
381       tracing_info.fields.resize(format.fields.size());
382       for (size_t i = 0; i < format.fields.size(); ++i) {
383         tracing_info.field_names[i] = format.fields[i].name;
384         TracingFieldFormat& field = tracing_info.fields[i];
385         field.name = tracing_info.field_names[i].c_str();
386         field.offset = format.fields[i].offset;
387         field.elem_size = format.fields[i].elem_size;
388         field.elem_count = format.fields[i].elem_count;
389         field.is_signed = format.fields[i].is_signed;
390       }
391       if (tracing_info.fields.empty()) {
392         tracing_info.data_format.size = 0;
393       } else {
394         TracingFieldFormat& field = tracing_info.fields.back();
395         tracing_info.data_format.size = field.offset + field.elem_size * field.elem_count;
396       }
397       tracing_info.data_format.field_count = tracing_info.fields.size();
398       tracing_info.data_format.fields = &tracing_info.fields[0];
399     } else {
400       tracing_info.data_format.size = 0;
401       tracing_info.data_format.field_count = 0;
402       tracing_info.data_format.fields = nullptr;
403     }
404   }
405 }
406 
AddMapping(const MapEntry & map)407 Mapping* ReportLib::AddMapping(const MapEntry& map) {
408   current_mappings_.emplace_back(std::unique_ptr<Mapping>(new Mapping));
409   Mapping* mapping = current_mappings_.back().get();
410   mapping->start = map.start_addr;
411   mapping->end = map.start_addr + map.len;
412   mapping->pgoff = map.pgoff;
413   return mapping;
414 }
415 
GetBuildIdForPath(const char * path)416 const char* ReportLib::GetBuildIdForPath(const char* path) {
417   if (!OpenRecordFileIfNecessary()) {
418     build_id_string_.clear();
419     return build_id_string_.c_str();
420   }
421   BuildId build_id = Dso::FindExpectedBuildIdForPath(path);
422   if (build_id.IsEmpty()) {
423     build_id_string_.clear();
424   } else {
425     build_id_string_ = build_id.ToString();
426   }
427   return build_id_string_.c_str();
428 }
429 
GetFeatureSection(const char * feature_name)430 FeatureSection* ReportLib::GetFeatureSection(const char* feature_name) {
431   if (!OpenRecordFileIfNecessary()) {
432     return nullptr;
433   }
434   int feature = PerfFileFormat::GetFeatureId(feature_name);
435   if (feature == -1 || !record_file_reader_->ReadFeatureSection(feature, &feature_section_data_)) {
436     return nullptr;
437   }
438   feature_section_.data = feature_section_data_.data();
439   feature_section_.data_size = feature_section_data_.size();
440   return &feature_section_;
441 }
442 
443 // Exported methods working with a client created instance
CreateReportLib()444 ReportLib* CreateReportLib() {
445   return new ReportLib();
446 }
447 
DestroyReportLib(ReportLib * report_lib)448 void DestroyReportLib(ReportLib* report_lib) {
449   delete report_lib;
450 }
451 
SetLogSeverity(ReportLib * report_lib,const char * log_level)452 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) {
453   return report_lib->SetLogSeverity(log_level);
454 }
455 
SetSymfs(ReportLib * report_lib,const char * symfs_dir)456 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) {
457   return report_lib->SetSymfs(symfs_dir);
458 }
459 
SetRecordFile(ReportLib * report_lib,const char * record_file)460 bool SetRecordFile(ReportLib* report_lib, const char* record_file) {
461   return report_lib->SetRecordFile(record_file);
462 }
463 
ShowIpForUnknownSymbol(ReportLib * report_lib)464 void ShowIpForUnknownSymbol(ReportLib* report_lib) {
465   return report_lib->ShowIpForUnknownSymbol();
466 }
467 
ShowArtFrames(ReportLib * report_lib,bool show)468 void ShowArtFrames(ReportLib* report_lib, bool show) {
469   return report_lib->ShowArtFrames(show);
470 }
471 
SetKallsymsFile(ReportLib * report_lib,const char * kallsyms_file)472 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) {
473   return report_lib->SetKallsymsFile(kallsyms_file);
474 }
475 
GetNextSample(ReportLib * report_lib)476 Sample* GetNextSample(ReportLib* report_lib) {
477   return report_lib->GetNextSample();
478 }
479 
GetEventOfCurrentSample(ReportLib * report_lib)480 Event* GetEventOfCurrentSample(ReportLib* report_lib) {
481   return report_lib->GetEventOfCurrentSample();
482 }
483 
GetSymbolOfCurrentSample(ReportLib * report_lib)484 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) {
485   return report_lib->GetSymbolOfCurrentSample();
486 }
487 
GetCallChainOfCurrentSample(ReportLib * report_lib)488 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) {
489   return report_lib->GetCallChainOfCurrentSample();
490 }
491 
GetTracingDataOfCurrentSample(ReportLib * report_lib)492 const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) {
493   return report_lib->GetTracingDataOfCurrentSample();
494 }
495 
GetBuildIdForPath(ReportLib * report_lib,const char * path)496 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
497   return report_lib->GetBuildIdForPath(path);
498 }
499 
GetFeatureSection(ReportLib * report_lib,const char * feature_name)500 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) {
501   return report_lib->GetFeatureSection(feature_name);
502 }
503