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