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