• 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 <optional>
19 #include <queue>
20 #include <utility>
21 
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android-base/strings.h>
25 
26 #include "JITDebugReader.h"
27 #include "RecordFilter.h"
28 #include "dso.h"
29 #include "event_attr.h"
30 #include "event_type.h"
31 #include "record_file.h"
32 #include "report_utils.h"
33 #include "thread_tree.h"
34 #include "tracing.h"
35 #include "utils.h"
36 
37 extern "C" {
38 
39 struct Sample {
40   uint64_t ip;
41   uint32_t pid;
42   uint32_t tid;
43   const char* thread_comm;
44   uint64_t time;
45   uint32_t in_kernel;
46   uint32_t cpu;
47   uint64_t period;
48 };
49 
50 struct TracingFieldFormat {
51   const char* name;
52   uint32_t offset;
53   uint32_t elem_size;
54   uint32_t elem_count;
55   uint32_t is_signed;
56   uint32_t is_dynamic;
57 };
58 
59 struct TracingDataFormat {
60   uint32_t size;
61   uint32_t field_count;
62   TracingFieldFormat* fields;
63 };
64 
65 struct Event {
66   const char* name;
67   TracingDataFormat tracing_data_format;
68 };
69 
70 struct Mapping {
71   uint64_t start;
72   uint64_t end;
73   uint64_t pgoff;
74 };
75 
76 struct SymbolEntry {
77   const char* dso_name;
78   uint64_t vaddr_in_file;
79   const char* symbol_name;
80   uint64_t symbol_addr;
81   uint64_t symbol_len;
82   Mapping* mapping;
83 };
84 
85 struct CallChainEntry {
86   uint64_t ip;
87   SymbolEntry symbol;
88 };
89 
90 struct CallChain {
91   uint32_t nr;
92   CallChainEntry* entries;
93 };
94 
95 struct FeatureSection {
96   const char* data;
97   uint32_t data_size;
98 };
99 
100 }  // extern "C"
101 
102 namespace simpleperf {
103 namespace {
104 
105 struct EventInfo {
106   perf_event_attr attr;
107   std::string name;
108 
109   struct TracingInfo {
110     TracingDataFormat data_format;
111     std::vector<std::string> field_names;
112     std::vector<TracingFieldFormat> fields;
113   } tracing_info;
114 };
115 
116 // If a recording file is generated with --trace-offcpu, we can select TraceOffCpuMode to report.
117 // It affects which samples are reported, and how period in each sample is calculated.
118 enum class TraceOffCpuMode {
119   // Only report on-cpu samples, with period representing time spent on cpu.
120   ON_CPU,
121   // Only report off-cpu samples, with period representing time spent off cpu.
122   OFF_CPU,
123   // Report both on-cpu and off-cpu samples.
124   ON_OFF_CPU,
125   // Report on-cpu and off-cpu samples under the same event type.
126   MIXED_ON_OFF_CPU,
127 };
128 
TraceOffCpuModeToString(TraceOffCpuMode mode)129 static std::string TraceOffCpuModeToString(TraceOffCpuMode mode) {
130   switch (mode) {
131     case TraceOffCpuMode::ON_CPU:
132       return "on-cpu";
133     case TraceOffCpuMode::OFF_CPU:
134       return "off-cpu";
135     case TraceOffCpuMode::ON_OFF_CPU:
136       return "on-off-cpu";
137     case TraceOffCpuMode::MIXED_ON_OFF_CPU:
138       return "mixed-on-off-cpu";
139   }
140 }
141 
StringToTraceOffCpuMode(const std::string & s)142 static std::optional<TraceOffCpuMode> StringToTraceOffCpuMode(const std::string& s) {
143   if (s == "on-cpu") {
144     return TraceOffCpuMode::ON_CPU;
145   }
146   if (s == "off-cpu") {
147     return TraceOffCpuMode::OFF_CPU;
148   }
149   if (s == "on-off-cpu") {
150     return TraceOffCpuMode::ON_OFF_CPU;
151   }
152   if (s == "mixed-on-off-cpu") {
153     return TraceOffCpuMode::MIXED_ON_OFF_CPU;
154   }
155   return std::nullopt;
156 }
157 
158 struct TraceOffCpuData {
159   std::vector<TraceOffCpuMode> supported_modes;
160   std::string supported_modes_string;
161   std::optional<TraceOffCpuMode> mode;
162   std::unordered_map<pid_t, std::unique_ptr<SampleRecord>> thread_map;
163 };
164 
165 }  // namespace
166 
167 class ReportLib {
168  public:
ReportLib()169   ReportLib()
170       : log_severity_(new android::base::ScopedLogSeverity(android::base::INFO)),
171         record_filename_("perf.data"),
172         current_thread_(nullptr),
173         callchain_report_builder_(thread_tree_),
174         record_filter_(thread_tree_) {}
175 
176   bool SetLogSeverity(const char* log_level);
177 
SetSymfs(const char * symfs_dir)178   bool SetSymfs(const char* symfs_dir) { return Dso::SetSymFsDir(symfs_dir); }
179 
SetRecordFile(const char * record_file)180   bool SetRecordFile(const char* record_file) {
181     if (record_file_reader_) {
182       LOG(ERROR) << "recording file " << record_filename_ << " has been opened";
183       return false;
184     }
185     record_filename_ = record_file;
186     return OpenRecordFileIfNecessary();
187   }
188 
189   bool SetKallsymsFile(const char* kallsyms_file);
190 
ShowIpForUnknownSymbol()191   void ShowIpForUnknownSymbol() { thread_tree_.ShowIpForUnknownSymbol(); }
ShowArtFrames(bool show)192   void ShowArtFrames(bool show) {
193     bool remove_art_frame = !show;
194     callchain_report_builder_.SetRemoveArtFrame(remove_art_frame);
195   }
MergeJavaMethods(bool merge)196   void MergeJavaMethods(bool merge) { callchain_report_builder_.SetConvertJITFrame(merge); }
AddProguardMappingFile(const char * mapping_file)197   bool AddProguardMappingFile(const char* mapping_file) {
198     return callchain_report_builder_.AddProguardMappingFile(mapping_file);
199   }
200   const char* GetSupportedTraceOffCpuModes();
201   bool SetTraceOffCpuMode(const char* mode);
202   bool SetSampleFilter(const char** filters, int filters_len);
203 
204   Sample* GetNextSample();
GetEventOfCurrentSample()205   Event* GetEventOfCurrentSample() { return &current_event_; }
GetSymbolOfCurrentSample()206   SymbolEntry* GetSymbolOfCurrentSample() { return current_symbol_; }
GetCallChainOfCurrentSample()207   CallChain* GetCallChainOfCurrentSample() { return &current_callchain_; }
GetTracingDataOfCurrentSample()208   const char* GetTracingDataOfCurrentSample() { return current_tracing_data_; }
209 
210   const char* GetBuildIdForPath(const char* path);
211   FeatureSection* GetFeatureSection(const char* feature_name);
212 
213  private:
214   void ProcessSampleRecord(std::unique_ptr<Record> r);
215   void ProcessSwitchRecord(std::unique_ptr<Record> r);
216   void AddSampleRecordToQueue(SampleRecord* r);
217   void SetCurrentSample(const SampleRecord& r);
218   const EventInfo* FindEventOfCurrentSample();
219   void CreateEvents();
220 
221   bool OpenRecordFileIfNecessary();
222   Mapping* AddMapping(const MapEntry& map);
223 
224   std::unique_ptr<android::base::ScopedLogSeverity> log_severity_;
225   std::string record_filename_;
226   std::unique_ptr<RecordFileReader> record_file_reader_;
227   ThreadTree thread_tree_;
228   std::queue<std::unique_ptr<SampleRecord>> sample_record_queue_;
229   const ThreadEntry* current_thread_;
230   Sample current_sample_;
231   Event current_event_;
232   SymbolEntry* current_symbol_;
233   CallChain current_callchain_;
234   const char* current_tracing_data_;
235   std::vector<std::unique_ptr<Mapping>> current_mappings_;
236   std::vector<CallChainEntry> callchain_entries_;
237   std::string build_id_string_;
238   std::vector<EventInfo> events_;
239   TraceOffCpuData trace_offcpu_;
240   FeatureSection feature_section_;
241   std::vector<char> feature_section_data_;
242   CallChainReportBuilder callchain_report_builder_;
243   std::unique_ptr<Tracing> tracing_;
244   RecordFilter record_filter_;
245 };
246 
SetLogSeverity(const char * log_level)247 bool ReportLib::SetLogSeverity(const char* log_level) {
248   android::base::LogSeverity severity;
249   if (!GetLogSeverity(log_level, &severity)) {
250     LOG(ERROR) << "Unknown log severity: " << log_level;
251     return false;
252   }
253   log_severity_ = nullptr;
254   log_severity_.reset(new android::base::ScopedLogSeverity(severity));
255   return true;
256 }
257 
SetKallsymsFile(const char * kallsyms_file)258 bool ReportLib::SetKallsymsFile(const char* kallsyms_file) {
259   std::string kallsyms;
260   if (!android::base::ReadFileToString(kallsyms_file, &kallsyms)) {
261     LOG(WARNING) << "Failed to read in kallsyms file from " << kallsyms_file;
262     return false;
263   }
264   Dso::SetKallsyms(std::move(kallsyms));
265   return true;
266 }
267 
GetSupportedTraceOffCpuModes()268 const char* ReportLib::GetSupportedTraceOffCpuModes() {
269   if (!OpenRecordFileIfNecessary()) {
270     return nullptr;
271   }
272   std::string& s = trace_offcpu_.supported_modes_string;
273   s.clear();
274   for (auto mode : trace_offcpu_.supported_modes) {
275     if (!s.empty()) {
276       s += ",";
277     }
278     s += TraceOffCpuModeToString(mode);
279   }
280   return s.data();
281 }
282 
SetTraceOffCpuMode(const char * mode)283 bool ReportLib::SetTraceOffCpuMode(const char* mode) {
284   auto mode_value = StringToTraceOffCpuMode(mode);
285   if (!mode_value) {
286     return false;
287   }
288   if (!OpenRecordFileIfNecessary()) {
289     return false;
290   }
291   auto& modes = trace_offcpu_.supported_modes;
292   if (std::find(modes.begin(), modes.end(), mode_value) == modes.end()) {
293     return false;
294   }
295   trace_offcpu_.mode = mode_value;
296   return true;
297 }
298 
SetSampleFilter(const char ** filters,int filters_len)299 bool ReportLib::SetSampleFilter(const char** filters, int filters_len) {
300   std::vector<std::string> args;
301   for (int i = 0; i < filters_len; i++) {
302     args.emplace_back(filters[i]);
303   }
304   OptionFormatMap option_formats = GetRecordFilterOptionFormats(false);
305   OptionValueMap options;
306   std::vector<std::pair<OptionName, OptionValue>> ordered_options;
307   if (!ConvertArgsToOptions(args, option_formats, "", &options, &ordered_options, nullptr)) {
308     return false;
309   }
310   return record_filter_.ParseOptions(options);
311 }
312 
OpenRecordFileIfNecessary()313 bool ReportLib::OpenRecordFileIfNecessary() {
314   if (record_file_reader_ == nullptr) {
315     record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
316     if (record_file_reader_ == nullptr) {
317       return false;
318     }
319     record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_);
320     auto& meta_info = record_file_reader_->GetMetaInfoFeature();
321     if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end() && it->second == "true") {
322       // If recorded with --trace-offcpu, default is to report on-off-cpu samples.
323       std::string event_name = GetEventNameByAttr(*record_file_reader_->AttrSection()[0].attr);
324       if (!android::base::StartsWith(event_name, "cpu-clock") &&
325           !android::base::StartsWith(event_name, "task-clock")) {
326         LOG(ERROR) << "Recording file " << record_filename_ << " is no longer supported. "
327                    << "--trace-offcpu must be used with `-e cpu-clock` or `-e task-clock`.";
328         return false;
329       }
330       trace_offcpu_.mode = TraceOffCpuMode::MIXED_ON_OFF_CPU;
331       trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::MIXED_ON_OFF_CPU);
332       trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::ON_OFF_CPU);
333       trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::ON_CPU);
334       trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::OFF_CPU);
335     }
336     if (!record_filter_.CheckClock(record_file_reader_->GetClockId())) {
337       LOG(ERROR) << "Recording file " << record_filename_ << " doesn't match the clock of filter.";
338       return false;
339     }
340   }
341   return true;
342 }
343 
GetNextSample()344 Sample* ReportLib::GetNextSample() {
345   if (!OpenRecordFileIfNecessary()) {
346     return nullptr;
347   }
348   if (!sample_record_queue_.empty()) {
349     sample_record_queue_.pop();
350   }
351   while (sample_record_queue_.empty()) {
352     std::unique_ptr<Record> record;
353     if (!record_file_reader_->ReadRecord(record) || record == nullptr) {
354       return nullptr;
355     }
356     thread_tree_.Update(*record);
357     if (record->type() == PERF_RECORD_SAMPLE) {
358       ProcessSampleRecord(std::move(record));
359     } else if (record->type() == PERF_RECORD_SWITCH ||
360                record->type() == PERF_RECORD_SWITCH_CPU_WIDE) {
361       ProcessSwitchRecord(std::move(record));
362     } else if (record->type() == PERF_RECORD_TRACING_DATA ||
363                record->type() == SIMPLE_PERF_RECORD_TRACING_DATA) {
364       const auto& r = *static_cast<TracingDataRecord*>(record.get());
365       tracing_.reset(new Tracing(std::vector<char>(r.data, r.data + r.data_size)));
366     }
367   }
368   SetCurrentSample(*sample_record_queue_.front());
369   return &current_sample_;
370 }
371 
ProcessSampleRecord(std::unique_ptr<Record> r)372 void ReportLib::ProcessSampleRecord(std::unique_ptr<Record> r) {
373   auto sr = static_cast<SampleRecord*>(r.get());
374   if (!trace_offcpu_.mode) {
375     r.release();
376     AddSampleRecordToQueue(sr);
377     return;
378   }
379   size_t attr_index = record_file_reader_->GetAttrIndexOfRecord(sr);
380   bool offcpu_sample = attr_index > 0;
381   if (trace_offcpu_.mode == TraceOffCpuMode::ON_CPU) {
382     if (!offcpu_sample) {
383       r.release();
384       AddSampleRecordToQueue(sr);
385     }
386     return;
387   }
388   uint32_t tid = sr->tid_data.tid;
389   auto it = trace_offcpu_.thread_map.find(tid);
390   if (it == trace_offcpu_.thread_map.end() || !it->second) {
391     // If there is no previous off-cpu sample, then store the current off-cpu sample.
392     if (offcpu_sample) {
393       r.release();
394       if (it == trace_offcpu_.thread_map.end()) {
395         trace_offcpu_.thread_map[tid].reset(sr);
396       } else {
397         it->second.reset(sr);
398       }
399     }
400   } else {
401     // If there is a previous off-cpu sample, update its period.
402     SampleRecord* prev_sr = it->second.get();
403     prev_sr->period_data.period =
404         (prev_sr->Timestamp() < sr->Timestamp()) ? (sr->Timestamp() - prev_sr->Timestamp()) : 1;
405     it->second.release();
406     AddSampleRecordToQueue(prev_sr);
407     if (offcpu_sample) {
408       r.release();
409       it->second.reset(sr);
410     }
411   }
412   if (!offcpu_sample && (trace_offcpu_.mode == TraceOffCpuMode::ON_OFF_CPU ||
413                          trace_offcpu_.mode == TraceOffCpuMode::MIXED_ON_OFF_CPU)) {
414     r.release();
415     AddSampleRecordToQueue(sr);
416   }
417 }
418 
ProcessSwitchRecord(std::unique_ptr<Record> r)419 void ReportLib::ProcessSwitchRecord(std::unique_ptr<Record> r) {
420   if (r->header.misc & PERF_RECORD_MISC_SWITCH_OUT) {
421     return;
422   }
423   uint32_t tid = r->sample_id.tid_data.tid;
424   auto it = trace_offcpu_.thread_map.find(tid);
425   if (it != trace_offcpu_.thread_map.end() && it->second) {
426     // If there is a previous off-cpu sample, update its period.
427     SampleRecord* prev_sr = it->second.get();
428     prev_sr->period_data.period =
429         (prev_sr->Timestamp() < r->Timestamp()) ? (r->Timestamp() - prev_sr->Timestamp()) : 1;
430     it->second.release();
431     AddSampleRecordToQueue(prev_sr);
432   }
433 }
434 
AddSampleRecordToQueue(SampleRecord * r)435 void ReportLib::AddSampleRecordToQueue(SampleRecord* r) {
436   if (record_filter_.Check(r)) {
437     sample_record_queue_.emplace(r);
438   }
439 }
440 
SetCurrentSample(const SampleRecord & r)441 void ReportLib::SetCurrentSample(const SampleRecord& r) {
442   current_mappings_.clear();
443   callchain_entries_.clear();
444   current_sample_.ip = r.ip_data.ip;
445   current_sample_.pid = r.tid_data.pid;
446   current_sample_.tid = r.tid_data.tid;
447   current_thread_ = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
448   current_sample_.thread_comm = current_thread_->comm;
449   current_sample_.time = r.time_data.time;
450   current_sample_.in_kernel = r.InKernel();
451   current_sample_.cpu = r.cpu_data.cpu;
452   current_sample_.period = r.period_data.period;
453 
454   size_t kernel_ip_count;
455   std::vector<uint64_t> ips = r.GetCallChain(&kernel_ip_count);
456   std::vector<CallChainReportEntry> report_entries =
457       callchain_report_builder_.Build(current_thread_, ips, kernel_ip_count);
458 
459   for (const auto& report_entry : report_entries) {
460     callchain_entries_.resize(callchain_entries_.size() + 1);
461     CallChainEntry& entry = callchain_entries_.back();
462     entry.ip = report_entry.ip;
463     if (report_entry.dso_name != nullptr) {
464       entry.symbol.dso_name = report_entry.dso_name;
465     } else {
466       entry.symbol.dso_name = report_entry.dso->GetReportPath().data();
467     }
468     entry.symbol.vaddr_in_file = report_entry.vaddr_in_file;
469     entry.symbol.symbol_name = report_entry.symbol->DemangledName();
470     entry.symbol.symbol_addr = report_entry.symbol->addr;
471     entry.symbol.symbol_len = report_entry.symbol->len;
472     entry.symbol.mapping = AddMapping(*report_entry.map);
473   }
474   current_sample_.ip = callchain_entries_[0].ip;
475   current_symbol_ = &(callchain_entries_[0].symbol);
476   current_callchain_.nr = callchain_entries_.size() - 1;
477   current_callchain_.entries = &callchain_entries_[1];
478   const EventInfo* event = FindEventOfCurrentSample();
479   current_event_.name = event->name.c_str();
480   current_event_.tracing_data_format = event->tracing_info.data_format;
481   if (current_event_.tracing_data_format.size > 0u && (r.sample_type & PERF_SAMPLE_RAW)) {
482     CHECK_GE(r.raw_data.size, current_event_.tracing_data_format.size);
483     current_tracing_data_ = r.raw_data.data;
484   } else {
485     current_tracing_data_ = nullptr;
486   }
487 }
488 
FindEventOfCurrentSample()489 const EventInfo* ReportLib::FindEventOfCurrentSample() {
490   if (events_.empty()) {
491     CreateEvents();
492   }
493   if (trace_offcpu_.mode == TraceOffCpuMode::MIXED_ON_OFF_CPU) {
494     // To mix on-cpu and off-cpu samples, pretend they are from the same event type.
495     // Otherwise, some report scripts may split them.
496     return &events_[0];
497   }
498   SampleRecord* r = sample_record_queue_.front().get();
499   size_t attr_index = record_file_reader_->GetAttrIndexOfRecord(r);
500   return &events_[attr_index];
501 }
502 
CreateEvents()503 void ReportLib::CreateEvents() {
504   std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
505   events_.resize(attrs.size());
506   for (size_t i = 0; i < attrs.size(); ++i) {
507     events_[i].attr = *attrs[i].attr;
508     events_[i].name = GetEventNameByAttr(events_[i].attr);
509     EventInfo::TracingInfo& tracing_info = events_[i].tracing_info;
510     if (events_[i].attr.type == PERF_TYPE_TRACEPOINT && tracing_) {
511       TracingFormat format = tracing_->GetTracingFormatHavingId(events_[i].attr.config);
512       tracing_info.field_names.resize(format.fields.size());
513       tracing_info.fields.resize(format.fields.size());
514       for (size_t i = 0; i < format.fields.size(); ++i) {
515         tracing_info.field_names[i] = format.fields[i].name;
516         TracingFieldFormat& field = tracing_info.fields[i];
517         field.name = tracing_info.field_names[i].c_str();
518         field.offset = format.fields[i].offset;
519         field.elem_size = format.fields[i].elem_size;
520         field.elem_count = format.fields[i].elem_count;
521         field.is_signed = format.fields[i].is_signed;
522         field.is_dynamic = format.fields[i].is_dynamic;
523       }
524       if (tracing_info.fields.empty()) {
525         tracing_info.data_format.size = 0;
526       } else {
527         TracingFieldFormat& field = tracing_info.fields.back();
528         tracing_info.data_format.size = field.offset + field.elem_size * field.elem_count;
529       }
530       tracing_info.data_format.field_count = tracing_info.fields.size();
531       tracing_info.data_format.fields = &tracing_info.fields[0];
532     } else {
533       tracing_info.data_format.size = 0;
534       tracing_info.data_format.field_count = 0;
535       tracing_info.data_format.fields = nullptr;
536     }
537   }
538 }
539 
AddMapping(const MapEntry & map)540 Mapping* ReportLib::AddMapping(const MapEntry& map) {
541   current_mappings_.emplace_back(std::unique_ptr<Mapping>(new Mapping));
542   Mapping* mapping = current_mappings_.back().get();
543   mapping->start = map.start_addr;
544   mapping->end = map.start_addr + map.len;
545   mapping->pgoff = map.pgoff;
546   return mapping;
547 }
548 
GetBuildIdForPath(const char * path)549 const char* ReportLib::GetBuildIdForPath(const char* path) {
550   if (!OpenRecordFileIfNecessary()) {
551     build_id_string_.clear();
552     return build_id_string_.c_str();
553   }
554   BuildId build_id = Dso::FindExpectedBuildIdForPath(path);
555   if (build_id.IsEmpty()) {
556     build_id_string_.clear();
557   } else {
558     build_id_string_ = build_id.ToString();
559   }
560   return build_id_string_.c_str();
561 }
562 
GetFeatureSection(const char * feature_name)563 FeatureSection* ReportLib::GetFeatureSection(const char* feature_name) {
564   if (!OpenRecordFileIfNecessary()) {
565     return nullptr;
566   }
567   int feature = PerfFileFormat::GetFeatureId(feature_name);
568   if (feature == -1 || !record_file_reader_->ReadFeatureSection(feature, &feature_section_data_)) {
569     return nullptr;
570   }
571   feature_section_.data = feature_section_data_.data();
572   feature_section_.data_size = feature_section_data_.size();
573   return &feature_section_;
574 }
575 
576 }  // namespace simpleperf
577 
578 using ReportLib = simpleperf::ReportLib;
579 
580 extern "C" {
581 
582 #define EXPORT __attribute__((visibility("default")))
583 
584 // Create a new instance,
585 // pass the instance to the other functions below.
586 ReportLib* CreateReportLib() EXPORT;
587 void DestroyReportLib(ReportLib* report_lib) EXPORT;
588 
589 // Set log severity, different levels are:
590 // verbose, debug, info, warning, error, fatal.
591 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) EXPORT;
592 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) EXPORT;
593 bool SetRecordFile(ReportLib* report_lib, const char* record_file) EXPORT;
594 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) EXPORT;
595 void ShowIpForUnknownSymbol(ReportLib* report_lib) EXPORT;
596 void ShowArtFrames(ReportLib* report_lib, bool show) EXPORT;
597 void MergeJavaMethods(ReportLib* report_lib, bool merge) EXPORT;
598 bool AddProguardMappingFile(ReportLib* report_lib, const char* mapping_file) EXPORT;
599 const char* GetSupportedTraceOffCpuModes(ReportLib* report_lib) EXPORT;
600 bool SetTraceOffCpuMode(ReportLib* report_lib, const char* mode) EXPORT;
601 bool SetSampleFilter(ReportLib* report_lib, const char** filters, int filters_len) EXPORT;
602 
603 Sample* GetNextSample(ReportLib* report_lib) EXPORT;
604 Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT;
605 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT;
606 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT;
607 const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) EXPORT;
608 
609 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT;
610 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) EXPORT;
611 }
612 
613 // Exported methods working with a client created instance
CreateReportLib()614 ReportLib* CreateReportLib() {
615   return new ReportLib();
616 }
617 
DestroyReportLib(ReportLib * report_lib)618 void DestroyReportLib(ReportLib* report_lib) {
619   delete report_lib;
620 }
621 
SetLogSeverity(ReportLib * report_lib,const char * log_level)622 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) {
623   return report_lib->SetLogSeverity(log_level);
624 }
625 
SetSymfs(ReportLib * report_lib,const char * symfs_dir)626 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) {
627   return report_lib->SetSymfs(symfs_dir);
628 }
629 
SetRecordFile(ReportLib * report_lib,const char * record_file)630 bool SetRecordFile(ReportLib* report_lib, const char* record_file) {
631   return report_lib->SetRecordFile(record_file);
632 }
633 
ShowIpForUnknownSymbol(ReportLib * report_lib)634 void ShowIpForUnknownSymbol(ReportLib* report_lib) {
635   return report_lib->ShowIpForUnknownSymbol();
636 }
637 
ShowArtFrames(ReportLib * report_lib,bool show)638 void ShowArtFrames(ReportLib* report_lib, bool show) {
639   return report_lib->ShowArtFrames(show);
640 }
641 
MergeJavaMethods(ReportLib * report_lib,bool merge)642 void MergeJavaMethods(ReportLib* report_lib, bool merge) {
643   return report_lib->MergeJavaMethods(merge);
644 }
645 
SetKallsymsFile(ReportLib * report_lib,const char * kallsyms_file)646 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) {
647   return report_lib->SetKallsymsFile(kallsyms_file);
648 }
649 
AddProguardMappingFile(ReportLib * report_lib,const char * mapping_file)650 bool AddProguardMappingFile(ReportLib* report_lib, const char* mapping_file) {
651   return report_lib->AddProguardMappingFile(mapping_file);
652 }
653 
GetSupportedTraceOffCpuModes(ReportLib * report_lib)654 const char* GetSupportedTraceOffCpuModes(ReportLib* report_lib) {
655   return report_lib->GetSupportedTraceOffCpuModes();
656 }
657 
SetTraceOffCpuMode(ReportLib * report_lib,const char * mode)658 bool SetTraceOffCpuMode(ReportLib* report_lib, const char* mode) {
659   return report_lib->SetTraceOffCpuMode(mode);
660 }
661 
SetSampleFilter(ReportLib * report_lib,const char ** filters,int filters_len)662 bool SetSampleFilter(ReportLib* report_lib, const char** filters, int filters_len) {
663   return report_lib->SetSampleFilter(filters, filters_len);
664 }
665 
GetNextSample(ReportLib * report_lib)666 Sample* GetNextSample(ReportLib* report_lib) {
667   return report_lib->GetNextSample();
668 }
669 
GetEventOfCurrentSample(ReportLib * report_lib)670 Event* GetEventOfCurrentSample(ReportLib* report_lib) {
671   return report_lib->GetEventOfCurrentSample();
672 }
673 
GetSymbolOfCurrentSample(ReportLib * report_lib)674 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) {
675   return report_lib->GetSymbolOfCurrentSample();
676 }
677 
GetCallChainOfCurrentSample(ReportLib * report_lib)678 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) {
679   return report_lib->GetCallChainOfCurrentSample();
680 }
681 
GetTracingDataOfCurrentSample(ReportLib * report_lib)682 const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) {
683   return report_lib->GetTracingDataOfCurrentSample();
684 }
685 
GetBuildIdForPath(ReportLib * report_lib,const char * path)686 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
687   return report_lib->GetBuildIdForPath(path);
688 }
689 
GetFeatureSection(ReportLib * report_lib,const char * feature_name)690 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) {
691   return report_lib->GetFeatureSection(feature_name);
692 }
693