• 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 "ETMDecoder.h"
27 #include "JITDebugReader.h"
28 #include "RecordFilter.h"
29 #include "dso.h"
30 #include "event_attr.h"
31 #include "event_type.h"
32 #include "record_file.h"
33 #include "report_utils.h"
34 #include "thread_tree.h"
35 #include "tracing.h"
36 #include "utils.h"
37 
38 extern "C" {
39 
40 struct Sample {
41   uint64_t ip;
42   uint32_t pid;
43   uint32_t tid;
44   const char* thread_comm;
45   uint64_t time;
46   uint32_t in_kernel;
47   uint32_t cpu;
48   uint64_t period;
49 };
50 
51 struct TracingFieldFormat {
52   const char* name;
53   uint32_t offset;
54   uint32_t elem_size;
55   uint32_t elem_count;
56   uint32_t is_signed;
57   uint32_t is_dynamic;
58 };
59 
60 struct TracingDataFormat {
61   uint32_t size;
62   uint32_t field_count;
63   TracingFieldFormat* fields;
64 };
65 
66 struct Event {
67   const char* name;
68   TracingDataFormat tracing_data_format;
69 };
70 
71 struct Mapping {
72   uint64_t start;
73   uint64_t end;
74   uint64_t pgoff;
75 };
76 
77 struct SymbolEntry {
78   const char* dso_name;
79   uint64_t vaddr_in_file;
80   const char* symbol_name;
81   uint64_t symbol_addr;
82   uint64_t symbol_len;
83   Mapping* mapping;
84 };
85 
86 struct CallChainEntry {
87   uint64_t ip;
88   SymbolEntry symbol;
89 };
90 
91 struct CallChain {
92   uint32_t nr;
93   CallChainEntry* entries;
94 };
95 
96 struct EventCounter {
97   const char* name;
98   uint64_t id;
99   uint64_t count;
100 };
101 
102 struct EventCountersView {
103   size_t nr;
104   EventCounter* event_counter;
105 };
106 
107 struct FeatureSection {
108   const char* data;
109   uint32_t data_size;
110 };
111 
112 struct BuildIdPair {
113   const unsigned char* build_id;
114   const char* filename;
115 };
116 
117 struct DsoAddress {
118   const char* path;
119   uint64_t offset;
120 };
121 
122 struct Thread {
123   int pid;
124   int tid;
125   const char* comm;
126 };
127 
128 }  // extern "C"
129 
130 namespace simpleperf {
131 namespace {
132 
133 struct EventInfo {
134   perf_event_attr attr;
135   std::string name;
136 
137   struct TracingInfo {
138     TracingDataFormat data_format;
139     std::vector<std::string> field_names;
140     std::vector<TracingFieldFormat> fields;
141   } tracing_info;
142 };
143 
144 // If a recording file is generated with --trace-offcpu, we can select TraceOffCpuMode to report.
145 // It affects which samples are reported, and how period in each sample is calculated.
146 enum class TraceOffCpuMode {
147   // Only report on-cpu samples, with period representing time spent on cpu.
148   ON_CPU,
149   // Only report off-cpu samples, with period representing time spent off cpu.
150   OFF_CPU,
151   // Report both on-cpu and off-cpu samples.
152   ON_OFF_CPU,
153   // Report on-cpu and off-cpu samples under the same event type.
154   MIXED_ON_OFF_CPU,
155 };
156 
TraceOffCpuModeToString(TraceOffCpuMode mode)157 static std::string TraceOffCpuModeToString(TraceOffCpuMode mode) {
158   switch (mode) {
159     case TraceOffCpuMode::ON_CPU:
160       return "on-cpu";
161     case TraceOffCpuMode::OFF_CPU:
162       return "off-cpu";
163     case TraceOffCpuMode::ON_OFF_CPU:
164       return "on-off-cpu";
165     case TraceOffCpuMode::MIXED_ON_OFF_CPU:
166       return "mixed-on-off-cpu";
167   }
168 }
169 
StringToTraceOffCpuMode(const std::string & s)170 static std::optional<TraceOffCpuMode> StringToTraceOffCpuMode(const std::string& s) {
171   if (s == "on-cpu") {
172     return TraceOffCpuMode::ON_CPU;
173   }
174   if (s == "off-cpu") {
175     return TraceOffCpuMode::OFF_CPU;
176   }
177   if (s == "on-off-cpu") {
178     return TraceOffCpuMode::ON_OFF_CPU;
179   }
180   if (s == "mixed-on-off-cpu") {
181     return TraceOffCpuMode::MIXED_ON_OFF_CPU;
182   }
183   return std::nullopt;
184 }
185 
186 struct TraceOffCpuData {
187   std::vector<TraceOffCpuMode> supported_modes;
188   std::string supported_modes_string;
189   std::optional<TraceOffCpuMode> mode;
190   std::unordered_map<pid_t, std::unique_ptr<SampleRecord>> thread_map;
191 };
192 
193 }  // namespace
194 
195 using UserCallback = ETMDecoder::UserCallback;
196 class ETMThreadTreeSimple : public ETMThreadTree {
197  public:
ETMThreadTreeSimple(ThreadTree & thread_tree)198   ETMThreadTreeSimple(ThreadTree& thread_tree) : thread_tree_(thread_tree) {}
DisableThreadExitRecords()199   void DisableThreadExitRecords() override { thread_tree_.DisableThreadExitRecords(); }
FindThread(int tid)200   const ThreadEntry* FindThread(int tid) override { return thread_tree_.FindThread(tid); }
GetKernelMaps()201   const MapSet& GetKernelMaps() override { return thread_tree_.GetKernelMaps(); }
202 
203  private:
204   ThreadTree& thread_tree_;
205 };
206 
207 class ReportLib {
208  public:
ReportLib()209   ReportLib()
210       : log_severity_(new android::base::ScopedLogSeverity(android::base::INFO)),
211         record_filename_("perf.data"),
212         current_thread_(nullptr),
213         callchain_report_builder_(thread_tree_),
214         record_filter_(thread_tree_),
215         etm_thread_tree_(thread_tree_) {}
216 
217   bool SetLogSeverity(const char* log_level);
218 
SetSymfs(const char * symfs_dir)219   bool SetSymfs(const char* symfs_dir) { return Dso::SetSymFsDir(symfs_dir); }
220 
SetRecordFile(const char * record_file)221   bool SetRecordFile(const char* record_file) {
222     if (record_file_reader_) {
223       LOG(ERROR) << "recording file " << record_filename_ << " has been opened";
224       return false;
225     }
226     record_filename_ = record_file;
227     return OpenRecordFileIfNecessary();
228   }
229 
230   bool SetKallsymsFile(const char* kallsyms_file);
231 
ShowIpForUnknownSymbol()232   void ShowIpForUnknownSymbol() { thread_tree_.ShowIpForUnknownSymbol(); }
ShowArtFrames(bool show)233   void ShowArtFrames(bool show) {
234     bool remove_art_frame = !show;
235     callchain_report_builder_.SetRemoveArtFrame(remove_art_frame);
236   }
RemoveMethod(const char * method_name_regex)237   bool RemoveMethod(const char* method_name_regex) {
238     return callchain_report_builder_.RemoveMethod(method_name_regex);
239   }
MergeJavaMethods(bool merge)240   void MergeJavaMethods(bool merge) { callchain_report_builder_.SetConvertJITFrame(merge); }
AddProguardMappingFile(const char * mapping_file)241   bool AddProguardMappingFile(const char* mapping_file) {
242     return callchain_report_builder_.AddProguardMappingFile(mapping_file);
243   }
244   const char* GetSupportedTraceOffCpuModes();
245   bool SetTraceOffCpuMode(const char* mode);
246   bool SetSampleFilter(const char** filters, int filters_len);
247   bool AggregateThreads(const char** thread_name_regex, int thread_name_regex_len);
248 
249   Sample* GetNextSample();
GetEventOfCurrentSample()250   Event* GetEventOfCurrentSample() { return &current_event_; }
GetSymbolOfCurrentSample()251   SymbolEntry* GetSymbolOfCurrentSample() { return current_symbol_; }
GetCallChainOfCurrentSample()252   CallChain* GetCallChainOfCurrentSample() { return &current_callchain_; }
GetEventCountersOfCurrentSample()253   EventCountersView* GetEventCountersOfCurrentSample() {
254     event_counters_view_.nr = event_counters_.size();
255     event_counters_view_.event_counter = event_counters_.data();
256     return &event_counters_view_;
257   }
GetTracingDataOfCurrentSample()258   const char* GetTracingDataOfCurrentSample() { return current_tracing_data_; }
GetProcessNameOfCurrentSample()259   const char* GetProcessNameOfCurrentSample() {
260     const ThreadEntry* thread = thread_tree_.FindThread(current_sample_.pid);
261     return (thread != nullptr) ? thread->comm : "unknown";
262   }
263 
264   const char* GetBuildIdForPath(const char* path);
265   FeatureSection* GetFeatureSection(const char* feature_name);
266   BuildIdPair* GetAllBuildIds();
267 
SetCallback(UserCallback callback)268   void SetCallback(UserCallback callback) { callback_ = callback; }
269   DsoAddress ConvertETMAddressToVaddrInFile(uint8_t trace_id, uint64_t address);
270 
271   Thread GetThread(int tid);
272   SymbolEntry* ReadSymbolsForPath(const char* path);
273 
274  private:
275   std::unique_ptr<SampleRecord> GetNextSampleRecord();
276   void ProcessSampleRecord(std::unique_ptr<Record> r);
277   void ProcessSwitchRecord(std::unique_ptr<Record> r);
278   bool ProcessAuxData(std::unique_ptr<Record> r);
279   void AddSampleRecordToQueue(SampleRecord* r);
280   bool SetCurrentSample(std::unique_ptr<SampleRecord> sample_record);
281   void SetEventCounters(const SampleRecord& r);
282   const EventInfo& FindEvent(const SampleRecord& r);
283   void CreateEvents();
284 
285   bool OpenRecordFileIfNecessary();
286   Mapping* AddMapping(const MapEntry& map);
287 
288   std::unique_ptr<android::base::ScopedLogSeverity> log_severity_;
289   std::string record_filename_;
290   std::unique_ptr<RecordFileReader> record_file_reader_;
291   ThreadTree thread_tree_;
292   std::queue<std::unique_ptr<SampleRecord>> sample_record_queue_;
293   const ThreadEntry* current_thread_;
294   Sample current_sample_;
295   Event current_event_;
296   SymbolEntry* current_symbol_;
297   CallChain current_callchain_;
298   std::vector<EventCounter> event_counters_;
299   EventCountersView event_counters_view_;
300   const char* current_tracing_data_;
301   std::vector<std::unique_ptr<Mapping>> current_mappings_;
302   std::vector<CallChainEntry> callchain_entries_;
303   std::string build_id_string_;
304   std::vector<EventInfo> events_;
305   TraceOffCpuData trace_offcpu_;
306   FeatureSection feature_section_;
307   std::vector<char> feature_section_data_;
308   CallChainReportBuilder callchain_report_builder_;
309   ThreadReportBuilder thread_report_builder_;
310   std::unique_ptr<Tracing> tracing_;
311   RecordFilter record_filter_;
312   std::vector<BuildIdRecord> buildid_records_;
313   std::vector<BuildIdPair> buildids_;
314 
315   ETMThreadTreeSimple etm_thread_tree_;
316   std::unique_ptr<ETMDecoder> etm_decoder_;
317   UserCallback callback_;
318   std::vector<uint8_t> aux_data_buffer_;
319   std::string filepath_;
320   std::string comm_;
321   std::vector<SymbolEntry> symbols_;
322 };
323 
SetLogSeverity(const char * log_level)324 bool ReportLib::SetLogSeverity(const char* log_level) {
325   android::base::LogSeverity severity;
326   if (!GetLogSeverity(log_level, &severity)) {
327     LOG(ERROR) << "Unknown log severity: " << log_level;
328     return false;
329   }
330   log_severity_ = nullptr;
331   log_severity_.reset(new android::base::ScopedLogSeverity(severity));
332   return true;
333 }
334 
SetKallsymsFile(const char * kallsyms_file)335 bool ReportLib::SetKallsymsFile(const char* kallsyms_file) {
336   std::string kallsyms;
337   if (!android::base::ReadFileToString(kallsyms_file, &kallsyms)) {
338     LOG(WARNING) << "Failed to read in kallsyms file from " << kallsyms_file;
339     return false;
340   }
341   Dso::SetKallsyms(std::move(kallsyms));
342   return true;
343 }
344 
GetSupportedTraceOffCpuModes()345 const char* ReportLib::GetSupportedTraceOffCpuModes() {
346   if (!OpenRecordFileIfNecessary()) {
347     return nullptr;
348   }
349   std::string& s = trace_offcpu_.supported_modes_string;
350   s.clear();
351   for (auto mode : trace_offcpu_.supported_modes) {
352     if (!s.empty()) {
353       s += ",";
354     }
355     s += TraceOffCpuModeToString(mode);
356   }
357   return s.data();
358 }
359 
SetTraceOffCpuMode(const char * mode)360 bool ReportLib::SetTraceOffCpuMode(const char* mode) {
361   auto mode_value = StringToTraceOffCpuMode(mode);
362   if (!mode_value) {
363     return false;
364   }
365   if (!OpenRecordFileIfNecessary()) {
366     return false;
367   }
368   auto& modes = trace_offcpu_.supported_modes;
369   if (std::find(modes.begin(), modes.end(), mode_value) == modes.end()) {
370     return false;
371   }
372   trace_offcpu_.mode = mode_value;
373   return true;
374 }
375 
SetSampleFilter(const char ** filters,int filters_len)376 bool ReportLib::SetSampleFilter(const char** filters, int filters_len) {
377   std::vector<std::string> args;
378   for (int i = 0; i < filters_len; i++) {
379     args.emplace_back(filters[i]);
380   }
381   OptionFormatMap option_formats = GetRecordFilterOptionFormats(false);
382   OptionValueMap options;
383   std::vector<std::pair<OptionName, OptionValue>> ordered_options;
384   if (!ConvertArgsToOptions(args, option_formats, "", &options, &ordered_options, nullptr)) {
385     return false;
386   }
387   return record_filter_.ParseOptions(options);
388 }
389 
AggregateThreads(const char ** thread_name_regex,int thread_name_regex_len)390 bool ReportLib::AggregateThreads(const char** thread_name_regex, int thread_name_regex_len) {
391   std::vector<std::string> regs(thread_name_regex_len);
392   for (int i = 0; i < thread_name_regex_len; ++i) {
393     regs[i] = thread_name_regex[i];
394   }
395   return thread_report_builder_.AggregateThreads(regs);
396 }
397 
OpenRecordFileIfNecessary()398 bool ReportLib::OpenRecordFileIfNecessary() {
399   if (record_file_reader_ == nullptr) {
400     record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
401     if (record_file_reader_ == nullptr) {
402       return false;
403     }
404     if (!record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_)) {
405       return false;
406     }
407     auto& meta_info = record_file_reader_->GetMetaInfoFeature();
408     if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end() && it->second == "true") {
409       // If recorded with --trace-offcpu, default is to report on-off-cpu samples.
410       std::string event_name = GetEventNameByAttr(record_file_reader_->AttrSection()[0].attr);
411       if (!android::base::StartsWith(event_name, "cpu-clock") &&
412           !android::base::StartsWith(event_name, "task-clock")) {
413         LOG(ERROR) << "Recording file " << record_filename_ << " is no longer supported. "
414                    << "--trace-offcpu must be used with `-e cpu-clock` or `-e task-clock`.";
415         return false;
416       }
417       trace_offcpu_.mode = TraceOffCpuMode::MIXED_ON_OFF_CPU;
418       trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::MIXED_ON_OFF_CPU);
419       trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::ON_OFF_CPU);
420       trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::ON_CPU);
421       trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::OFF_CPU);
422     }
423     if (!record_filter_.CheckClock(record_file_reader_->GetClockId())) {
424       LOG(ERROR) << "Recording file " << record_filename_ << " doesn't match the clock of filter.";
425       return false;
426     }
427   }
428   return true;
429 }
430 
GetNextSample()431 Sample* ReportLib::GetNextSample() {
432   if (!OpenRecordFileIfNecessary()) {
433     return nullptr;
434   }
435 
436   while (true) {
437     std::unique_ptr<SampleRecord> r = GetNextSampleRecord();
438     if (!r) {
439       break;
440     }
441     if (SetCurrentSample(std::move(r))) {
442       return &current_sample_;
443     }
444   }
445   return nullptr;
446 }
447 
GetNextSampleRecord()448 std::unique_ptr<SampleRecord> ReportLib::GetNextSampleRecord() {
449   while (sample_record_queue_.empty()) {
450     std::unique_ptr<Record> record;
451     if (!record_file_reader_->ReadRecord(record) || record == nullptr) {
452       return nullptr;
453     }
454     thread_tree_.Update(*record);
455     if (record->type() == PERF_RECORD_SAMPLE) {
456       ProcessSampleRecord(std::move(record));
457     } else if (record->type() == PERF_RECORD_SWITCH ||
458                record->type() == PERF_RECORD_SWITCH_CPU_WIDE) {
459       ProcessSwitchRecord(std::move(record));
460     } else if (record->type() == PERF_RECORD_TRACING_DATA ||
461                record->type() == SIMPLE_PERF_RECORD_TRACING_DATA) {
462       const auto& r = *static_cast<TracingDataRecord*>(record.get());
463       tracing_ = Tracing::Create(std::vector<char>(r.data, r.data + r.data_size));
464       if (!tracing_) {
465         return nullptr;
466       }
467     } else if (record->type() == PERF_RECORD_AUXTRACE_INFO) {
468       if (!callback_) {
469         LOG(ERROR) << "ETM trace found but no callback was set!";
470         return nullptr;
471       }
472       etm_decoder_ =
473           ETMDecoder::Create(static_cast<AuxTraceInfoRecord&>(*record), etm_thread_tree_);
474       if (!etm_decoder_) {
475         return nullptr;
476       }
477       etm_decoder_->RegisterCallback(callback_);
478     } else if (record->type() == PERF_RECORD_AUX) {
479       if (!ProcessAuxData(std::move(record))) {
480         return nullptr;
481       }
482     }
483   }
484   std::unique_ptr<SampleRecord> result = std::move(sample_record_queue_.front());
485   sample_record_queue_.pop();
486   return result;
487 }
488 
ProcessSampleRecord(std::unique_ptr<Record> r)489 void ReportLib::ProcessSampleRecord(std::unique_ptr<Record> r) {
490   auto sr = static_cast<SampleRecord*>(r.get());
491   if (!trace_offcpu_.mode) {
492     r.release();
493     AddSampleRecordToQueue(sr);
494     return;
495   }
496   size_t attr_index = record_file_reader_->GetAttrIndexOfRecord(sr);
497   bool offcpu_sample = attr_index > 0;
498   if (trace_offcpu_.mode == TraceOffCpuMode::ON_CPU) {
499     if (!offcpu_sample) {
500       r.release();
501       AddSampleRecordToQueue(sr);
502     }
503     return;
504   }
505   uint32_t tid = sr->tid_data.tid;
506   auto it = trace_offcpu_.thread_map.find(tid);
507   if (it == trace_offcpu_.thread_map.end() || !it->second) {
508     // If there is no previous off-cpu sample, then store the current off-cpu sample.
509     if (offcpu_sample) {
510       r.release();
511       if (it == trace_offcpu_.thread_map.end()) {
512         trace_offcpu_.thread_map[tid].reset(sr);
513       } else {
514         it->second.reset(sr);
515       }
516     }
517   } else {
518     // If there is a previous off-cpu sample, update its period.
519     SampleRecord* prev_sr = it->second.get();
520     prev_sr->period_data.period =
521         (prev_sr->Timestamp() < sr->Timestamp()) ? (sr->Timestamp() - prev_sr->Timestamp()) : 1;
522     it->second.release();
523     AddSampleRecordToQueue(prev_sr);
524     if (offcpu_sample) {
525       r.release();
526       it->second.reset(sr);
527     }
528   }
529   if (!offcpu_sample && (trace_offcpu_.mode == TraceOffCpuMode::ON_OFF_CPU ||
530                          trace_offcpu_.mode == TraceOffCpuMode::MIXED_ON_OFF_CPU)) {
531     r.release();
532     AddSampleRecordToQueue(sr);
533   }
534 }
535 
ProcessSwitchRecord(std::unique_ptr<Record> r)536 void ReportLib::ProcessSwitchRecord(std::unique_ptr<Record> r) {
537   if (r->header.misc & PERF_RECORD_MISC_SWITCH_OUT) {
538     return;
539   }
540   uint32_t tid = r->sample_id.tid_data.tid;
541   auto it = trace_offcpu_.thread_map.find(tid);
542   if (it != trace_offcpu_.thread_map.end() && it->second) {
543     // If there is a previous off-cpu sample, update its period.
544     SampleRecord* prev_sr = it->second.get();
545     prev_sr->period_data.period =
546         (prev_sr->Timestamp() < r->Timestamp()) ? (r->Timestamp() - prev_sr->Timestamp()) : 1;
547     it->second.release();
548     AddSampleRecordToQueue(prev_sr);
549   }
550 }
551 
ProcessAuxData(std::unique_ptr<Record> r)552 bool ReportLib::ProcessAuxData(std::unique_ptr<Record> r) {
553   AuxRecord& aux = static_cast<AuxRecord&>(*r);
554   if (aux.data->aux_size > SIZE_MAX) {
555     LOG(ERROR) << "invalid aux size";
556     return false;
557   }
558   size_t aux_size = aux.data->aux_size;
559   if (aux_size > 0) {
560     bool error = false;
561     if (!record_file_reader_->ReadAuxData(aux.Cpu(), aux.data->aux_offset, aux_size,
562                                           aux_data_buffer_, error)) {
563       return !error;
564     }
565     if (!etm_decoder_) {
566       LOG(ERROR) << "ETMDecoder has not been created";
567       return false;
568     }
569     return etm_decoder_->ProcessData(aux_data_buffer_.data(), aux_size, !aux.Unformatted(),
570                                      aux.Cpu());
571   }
572   return true;
573 }
574 
AddSampleRecordToQueue(SampleRecord * r)575 void ReportLib::AddSampleRecordToQueue(SampleRecord* r) {
576   if (record_filter_.Check(*r)) {
577     sample_record_queue_.emplace(r);
578   }
579 }
580 
SetCurrentSample(std::unique_ptr<SampleRecord> sample_record)581 bool ReportLib::SetCurrentSample(std::unique_ptr<SampleRecord> sample_record) {
582   const SampleRecord& r = *sample_record;
583   current_mappings_.clear();
584   callchain_entries_.clear();
585   current_sample_.ip = r.ip_data.ip;
586   current_thread_ = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
587   ThreadReport thread_report = thread_report_builder_.Build(*current_thread_);
588   current_sample_.pid = thread_report.pid;
589   current_sample_.tid = thread_report.tid;
590   current_sample_.thread_comm = thread_report.thread_name;
591   current_sample_.time = r.time_data.time;
592   current_sample_.in_kernel = r.InKernel();
593   current_sample_.cpu = r.cpu_data.cpu;
594   current_sample_.period = r.period_data.period;
595 
596   size_t kernel_ip_count;
597   std::vector<uint64_t> ips = r.GetCallChain(&kernel_ip_count);
598   std::vector<CallChainReportEntry> report_entries =
599       callchain_report_builder_.Build(current_thread_, ips, kernel_ip_count);
600   if (report_entries.empty()) {
601     // Skip samples with callchain fully removed by RemoveMethod().
602     return false;
603   }
604 
605   for (const auto& report_entry : report_entries) {
606     callchain_entries_.resize(callchain_entries_.size() + 1);
607     CallChainEntry& entry = callchain_entries_.back();
608     entry.ip = report_entry.ip;
609     if (report_entry.dso_name != nullptr) {
610       entry.symbol.dso_name = report_entry.dso_name;
611     } else {
612       entry.symbol.dso_name = report_entry.dso->GetReportPath().data();
613     }
614     entry.symbol.vaddr_in_file = report_entry.vaddr_in_file;
615     entry.symbol.symbol_name = report_entry.symbol->DemangledName();
616     entry.symbol.symbol_addr = report_entry.symbol->addr;
617     entry.symbol.symbol_len = report_entry.symbol->len;
618     entry.symbol.mapping = AddMapping(*report_entry.map);
619   }
620   current_sample_.ip = callchain_entries_[0].ip;
621   current_symbol_ = &(callchain_entries_[0].symbol);
622   current_callchain_.nr = callchain_entries_.size() - 1;
623   current_callchain_.entries = &callchain_entries_[1];
624   const EventInfo& event = FindEvent(r);
625   current_event_.name = event.name.c_str();
626   current_event_.tracing_data_format = event.tracing_info.data_format;
627   if (current_event_.tracing_data_format.size > 0u && (r.sample_type & PERF_SAMPLE_RAW)) {
628     CHECK_GE(r.raw_data.size, current_event_.tracing_data_format.size);
629     current_tracing_data_ = r.raw_data.data;
630   } else {
631     current_tracing_data_ = nullptr;
632   }
633   SetEventCounters(r);
634   return true;
635 }
636 
SetEventCounters(const SampleRecord & r)637 void ReportLib::SetEventCounters(const SampleRecord& r) {
638   const std::vector<uint64_t>& ids = r.read_data.ids;
639   const std::vector<uint64_t>& counts = r.read_data.counts;
640   CHECK_EQ(ids.size(), counts.size());
641 
642   event_counters_.clear();
643   for (size_t i = 0; i < ids.size(); i++) {
644     uint64_t event_id = ids[i];
645     uint64_t count = counts[i];
646     std::optional<size_t> attr_index = record_file_reader_->GetAttrIndexByEventId(event_id);
647     if (!attr_index) {
648       LOG(ERROR) << "Failed to find event name for event id " << event_id;
649       continue;
650     }
651 
652     event_counters_.emplace_back(events_[*attr_index].name.c_str(), event_id, count);
653   }
654 }
655 
FindEvent(const SampleRecord & r)656 const EventInfo& ReportLib::FindEvent(const SampleRecord& r) {
657   if (events_.empty()) {
658     CreateEvents();
659   }
660   if (trace_offcpu_.mode == TraceOffCpuMode::MIXED_ON_OFF_CPU) {
661     // To mix on-cpu and off-cpu samples, pretend they are from the same event type.
662     // Otherwise, some report scripts may split them.
663     return events_[0];
664   }
665   size_t attr_index = record_file_reader_->GetAttrIndexOfRecord(&r);
666   return events_[attr_index];
667 }
668 
CreateEvents()669 void ReportLib::CreateEvents() {
670   const EventAttrIds& attrs = record_file_reader_->AttrSection();
671   events_.resize(attrs.size());
672   for (size_t i = 0; i < attrs.size(); ++i) {
673     events_[i].attr = attrs[i].attr;
674     events_[i].name = GetEventNameByAttr(events_[i].attr);
675     EventInfo::TracingInfo& tracing_info = events_[i].tracing_info;
676     tracing_info.data_format.size = 0;
677     tracing_info.data_format.field_count = 0;
678     tracing_info.data_format.fields = nullptr;
679 
680     if (events_[i].attr.type == PERF_TYPE_TRACEPOINT && tracing_) {
681       std::optional<TracingFormat> opt_format =
682           tracing_->GetTracingFormatHavingId(events_[i].attr.config);
683       if (!opt_format.has_value() || opt_format.value().fields.empty()) {
684         continue;
685       }
686       const TracingFormat& format = opt_format.value();
687       tracing_info.field_names.resize(format.fields.size());
688       tracing_info.fields.resize(format.fields.size());
689       for (size_t i = 0; i < format.fields.size(); ++i) {
690         tracing_info.field_names[i] = format.fields[i].name;
691         TracingFieldFormat& field = tracing_info.fields[i];
692         field.name = tracing_info.field_names[i].c_str();
693         field.offset = format.fields[i].offset;
694         field.elem_size = format.fields[i].elem_size;
695         field.elem_count = format.fields[i].elem_count;
696         field.is_signed = format.fields[i].is_signed;
697         field.is_dynamic = format.fields[i].is_dynamic;
698       }
699       TracingFieldFormat& field = tracing_info.fields.back();
700       tracing_info.data_format.size = field.offset + field.elem_size * field.elem_count;
701       tracing_info.data_format.field_count = tracing_info.fields.size();
702       tracing_info.data_format.fields = &tracing_info.fields[0];
703     }
704   }
705 }
706 
AddMapping(const MapEntry & map)707 Mapping* ReportLib::AddMapping(const MapEntry& map) {
708   current_mappings_.emplace_back(std::unique_ptr<Mapping>(new Mapping));
709   Mapping* mapping = current_mappings_.back().get();
710   mapping->start = map.start_addr;
711   mapping->end = map.start_addr + map.len;
712   mapping->pgoff = map.pgoff;
713   return mapping;
714 }
715 
GetBuildIdForPath(const char * path)716 const char* ReportLib::GetBuildIdForPath(const char* path) {
717   if (!OpenRecordFileIfNecessary()) {
718     build_id_string_.clear();
719     return build_id_string_.c_str();
720   }
721   BuildId build_id = Dso::FindExpectedBuildIdForPath(path);
722   if (build_id.IsEmpty()) {
723     build_id_string_.clear();
724   } else {
725     build_id_string_ = build_id.ToString();
726   }
727   return build_id_string_.c_str();
728 }
729 
GetFeatureSection(const char * feature_name)730 FeatureSection* ReportLib::GetFeatureSection(const char* feature_name) {
731   if (!OpenRecordFileIfNecessary()) {
732     return nullptr;
733   }
734   int feature = PerfFileFormat::GetFeatureId(feature_name);
735   if (feature == -1 || !record_file_reader_->ReadFeatureSection(feature, &feature_section_data_)) {
736     return nullptr;
737   }
738   feature_section_.data = feature_section_data_.data();
739   feature_section_.data_size = feature_section_data_.size();
740   return &feature_section_;
741 }
742 
GetAllBuildIds()743 BuildIdPair* ReportLib::GetAllBuildIds() {
744   if (!OpenRecordFileIfNecessary()) {
745     return nullptr;
746   }
747   buildid_records_.clear();
748   buildid_records_ = record_file_reader_->ReadBuildIdFeature();
749   if (buildid_records_.empty()) {
750     return nullptr;
751   }
752   buildids_.clear();
753   buildids_.reserve(buildid_records_.size() + 1);
754   for (const auto& r : buildid_records_) {
755     buildids_.emplace_back(r.build_id.Data(), r.filename);
756   }
757   buildids_.emplace_back(nullptr, nullptr);
758   return buildids_.data();
759 }
760 
ConvertETMAddressToVaddrInFile(uint8_t trace_id,uint64_t address)761 DsoAddress ReportLib::ConvertETMAddressToVaddrInFile(uint8_t trace_id, uint64_t address) {
762   if (!etm_decoder_) {
763     LOG(ERROR) << "ETMDecoder was not created yet!";
764     return DsoAddress{.path = nullptr, .offset = 0};
765   }
766   const simpleperf::MapEntry* e = etm_decoder_->FindMap(trace_id, address);
767   if (e) {
768     filepath_ = e->dso->Path();
769     return DsoAddress{.path = filepath_.c_str(), .offset = e->GetVaddrInFile(address)};
770   } else {
771     return DsoAddress{.path = nullptr, .offset = address};
772   }
773 }
774 
GetThread(int tid)775 Thread ReportLib::GetThread(int tid) {
776   Thread result{.pid = -1, .tid = -1, .comm = nullptr};
777   ThreadEntry* thread = thread_tree_.FindThread(tid);
778   if (thread) {
779     comm_ = thread->comm;
780     result.pid = thread->pid;
781     result.tid = thread->tid;
782     result.comm = comm_.c_str();
783   }
784   return result;
785 }
786 
ReadSymbolsForPath(const char * path)787 SymbolEntry* ReportLib::ReadSymbolsForPath(const char* path) {
788   std::string filename(path);
789   Dso* dso = thread_tree_.FindUserDso(filename);
790   if (!dso) {
791     return nullptr;
792   }
793   dso->LoadSymbols();
794   auto symbols = dso->GetSymbols();
795 
796   symbols_.clear();
797   symbols_.reserve(symbols.size() + 1);
798   for (auto& symbol : symbols) {
799     symbols_.emplace_back(nullptr, 0, symbol.DemangledName(), symbol.addr, symbol.len, nullptr);
800   }
801   symbols_.emplace_back(nullptr, 0, nullptr, 0, 0, nullptr);
802   return symbols_.data();
803 }
804 
805 }  // namespace simpleperf
806 
807 using ReportLib = simpleperf::ReportLib;
808 
809 extern "C" {
810 
811 #define EXPORT __attribute__((visibility("default")))
812 
813 // Create a new instance,
814 // pass the instance to the other functions below.
815 ReportLib* CreateReportLib() EXPORT;
816 void DestroyReportLib(ReportLib* report_lib) EXPORT;
817 
818 // Set log severity, different levels are:
819 // verbose, debug, info, warning, error, fatal.
820 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) EXPORT;
821 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) EXPORT;
822 bool SetRecordFile(ReportLib* report_lib, const char* record_file) EXPORT;
823 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) EXPORT;
824 void ShowIpForUnknownSymbol(ReportLib* report_lib) EXPORT;
825 void ShowArtFrames(ReportLib* report_lib, bool show) EXPORT;
826 bool RemoveMethod(ReportLib* report_lib, const char* method_name_regex) EXPORT;
827 void MergeJavaMethods(ReportLib* report_lib, bool merge) EXPORT;
828 bool AddProguardMappingFile(ReportLib* report_lib, const char* mapping_file) EXPORT;
829 const char* GetSupportedTraceOffCpuModes(ReportLib* report_lib) EXPORT;
830 bool SetTraceOffCpuMode(ReportLib* report_lib, const char* mode) EXPORT;
831 bool SetSampleFilter(ReportLib* report_lib, const char** filters, int filters_len) EXPORT;
832 bool AggregateThreads(ReportLib* report_lib, const char** thread_name_regex,
833                       int thread_name_regex_len) EXPORT;
834 
835 Sample* GetNextSample(ReportLib* report_lib) EXPORT;
836 Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT;
837 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT;
838 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT;
839 EventCountersView* GetEventCountersOfCurrentSample(ReportLib* report_lib) EXPORT;
840 const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) EXPORT;
841 const char* GetProcessNameOfCurrentSample(ReportLib* report_lib) EXPORT;
842 
843 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT;
844 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) EXPORT;
845 BuildIdPair* GetAllBuildIds(ReportLib* report_lib) EXPORT;
846 
847 void SetETMCallback(ReportLib* report_lib, void (*callback)(const uint8_t, const void*)) EXPORT;
848 DsoAddress ConvertETMAddressToVaddrInFile(ReportLib* report_lib, uint8_t trace_id,
849                                           uint64_t address) EXPORT;
850 Thread GetThread(ReportLib* report_lib, int tid) EXPORT;
851 SymbolEntry* ReadSymbolsForPath(ReportLib* report_lib, const char* path) EXPORT;
852 }
853 
854 // Exported methods working with a client created instance
CreateReportLib()855 ReportLib* CreateReportLib() {
856   return new ReportLib();
857 }
858 
DestroyReportLib(ReportLib * report_lib)859 void DestroyReportLib(ReportLib* report_lib) {
860   delete report_lib;
861 }
862 
SetLogSeverity(ReportLib * report_lib,const char * log_level)863 bool SetLogSeverity(ReportLib* report_lib, const char* log_level) {
864   return report_lib->SetLogSeverity(log_level);
865 }
866 
SetSymfs(ReportLib * report_lib,const char * symfs_dir)867 bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) {
868   return report_lib->SetSymfs(symfs_dir);
869 }
870 
SetRecordFile(ReportLib * report_lib,const char * record_file)871 bool SetRecordFile(ReportLib* report_lib, const char* record_file) {
872   return report_lib->SetRecordFile(record_file);
873 }
874 
ShowIpForUnknownSymbol(ReportLib * report_lib)875 void ShowIpForUnknownSymbol(ReportLib* report_lib) {
876   return report_lib->ShowIpForUnknownSymbol();
877 }
878 
ShowArtFrames(ReportLib * report_lib,bool show)879 void ShowArtFrames(ReportLib* report_lib, bool show) {
880   return report_lib->ShowArtFrames(show);
881 }
882 
RemoveMethod(ReportLib * report_lib,const char * method_name_regex)883 bool RemoveMethod(ReportLib* report_lib, const char* method_name_regex) {
884   return report_lib->RemoveMethod(method_name_regex);
885 }
886 
MergeJavaMethods(ReportLib * report_lib,bool merge)887 void MergeJavaMethods(ReportLib* report_lib, bool merge) {
888   return report_lib->MergeJavaMethods(merge);
889 }
890 
SetKallsymsFile(ReportLib * report_lib,const char * kallsyms_file)891 bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) {
892   return report_lib->SetKallsymsFile(kallsyms_file);
893 }
894 
AddProguardMappingFile(ReportLib * report_lib,const char * mapping_file)895 bool AddProguardMappingFile(ReportLib* report_lib, const char* mapping_file) {
896   return report_lib->AddProguardMappingFile(mapping_file);
897 }
898 
GetSupportedTraceOffCpuModes(ReportLib * report_lib)899 const char* GetSupportedTraceOffCpuModes(ReportLib* report_lib) {
900   return report_lib->GetSupportedTraceOffCpuModes();
901 }
902 
SetTraceOffCpuMode(ReportLib * report_lib,const char * mode)903 bool SetTraceOffCpuMode(ReportLib* report_lib, const char* mode) {
904   return report_lib->SetTraceOffCpuMode(mode);
905 }
906 
SetSampleFilter(ReportLib * report_lib,const char ** filters,int filters_len)907 bool SetSampleFilter(ReportLib* report_lib, const char** filters, int filters_len) {
908   return report_lib->SetSampleFilter(filters, filters_len);
909 }
910 
AggregateThreads(ReportLib * report_lib,const char ** thread_name_regex,int thread_name_regex_len)911 bool AggregateThreads(ReportLib* report_lib, const char** thread_name_regex,
912                       int thread_name_regex_len) {
913   return report_lib->AggregateThreads(thread_name_regex, thread_name_regex_len);
914 }
915 
GetNextSample(ReportLib * report_lib)916 Sample* GetNextSample(ReportLib* report_lib) {
917   return report_lib->GetNextSample();
918 }
919 
GetEventOfCurrentSample(ReportLib * report_lib)920 Event* GetEventOfCurrentSample(ReportLib* report_lib) {
921   return report_lib->GetEventOfCurrentSample();
922 }
923 
GetSymbolOfCurrentSample(ReportLib * report_lib)924 SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) {
925   return report_lib->GetSymbolOfCurrentSample();
926 }
927 
GetCallChainOfCurrentSample(ReportLib * report_lib)928 CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) {
929   return report_lib->GetCallChainOfCurrentSample();
930 }
931 
GetEventCountersOfCurrentSample(ReportLib * report_lib)932 EventCountersView* GetEventCountersOfCurrentSample(ReportLib* report_lib) {
933   return report_lib->GetEventCountersOfCurrentSample();
934 }
935 
GetTracingDataOfCurrentSample(ReportLib * report_lib)936 const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) {
937   return report_lib->GetTracingDataOfCurrentSample();
938 }
939 
GetProcessNameOfCurrentSample(ReportLib * report_lib)940 const char* GetProcessNameOfCurrentSample(ReportLib* report_lib) {
941   return report_lib->GetProcessNameOfCurrentSample();
942 }
943 
GetBuildIdForPath(ReportLib * report_lib,const char * path)944 const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
945   return report_lib->GetBuildIdForPath(path);
946 }
947 
GetFeatureSection(ReportLib * report_lib,const char * feature_name)948 FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) {
949   return report_lib->GetFeatureSection(feature_name);
950 }
951 
GetAllBuildIds(ReportLib * report_lib)952 BuildIdPair* GetAllBuildIds(ReportLib* report_lib) {
953   return report_lib->GetAllBuildIds();
954 }
955 
SetETMCallback(ReportLib * report_lib,void (* callback)(const uint8_t,const void *))956 void SetETMCallback(ReportLib* report_lib, void (*callback)(const uint8_t, const void*)) {
957   report_lib->SetCallback(callback);
958 }
959 
ConvertETMAddressToVaddrInFile(ReportLib * report_lib,uint8_t trace_id,uint64_t address)960 DsoAddress ConvertETMAddressToVaddrInFile(ReportLib* report_lib, uint8_t trace_id,
961                                           uint64_t address) {
962   return report_lib->ConvertETMAddressToVaddrInFile(trace_id, address);
963 }
964 
GetThread(ReportLib * report_lib,int tid)965 Thread GetThread(ReportLib* report_lib, int tid) {
966   return report_lib->GetThread(tid);
967 }
968 
ReadSymbolsForPath(ReportLib * report_lib,const char * path)969 SymbolEntry* ReadSymbolsForPath(ReportLib* report_lib, const char* path) {
970   return report_lib->ReadSymbolsForPath(path);
971 }
972