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 ¤t_event_; }
GetSymbolOfCurrentSample()160 SymbolEntry* GetSymbolOfCurrentSample() { return current_symbol_; }
GetCallChainOfCurrentSample()161 CallChain* GetCallChainOfCurrentSample() { return ¤t_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 ¤t_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