diff options
Diffstat (limited to 'simpleperf/report_lib_interface.cpp')
-rw-r--r-- | simpleperf/report_lib_interface.cpp | 178 |
1 files changed, 74 insertions, 104 deletions
diff --git a/simpleperf/report_lib_interface.cpp b/simpleperf/report_lib_interface.cpp index 70a274f4..d6a4bc09 100644 --- a/simpleperf/report_lib_interface.cpp +++ b/simpleperf/report_lib_interface.cpp @@ -17,24 +17,22 @@ #include <memory> #include <utility> -#include <android-base/logging.h> #include <android-base/file.h> +#include <android-base/logging.h> #include <android-base/strings.h> +#include "JITDebugReader.h" #include "dso.h" #include "event_attr.h" #include "event_type.h" #include "record_file.h" +#include "report_utils.h" #include "thread_tree.h" #include "tracing.h" #include "utils.h" -class ReportLib; - extern "C" { -#define EXPORT __attribute__((visibility("default"))) - struct Sample { uint64_t ip; uint32_t pid; @@ -52,6 +50,7 @@ struct TracingFieldFormat { uint32_t elem_size; uint32_t elem_count; uint32_t is_signed; + uint32_t is_dynamic; }; struct TracingDataFormat { @@ -95,30 +94,9 @@ struct FeatureSection { uint32_t data_size; }; -// Create a new instance, -// pass the instance to the other functions below. -ReportLib* CreateReportLib() EXPORT; -void DestroyReportLib(ReportLib* report_lib) EXPORT; +} // extern "C" -// Set log severity, different levels are: -// verbose, debug, info, warning, error, fatal. -bool SetLogSeverity(ReportLib* report_lib, const char* log_level) EXPORT; -bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) EXPORT; -bool SetRecordFile(ReportLib* report_lib, const char* record_file) EXPORT; -bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) EXPORT; -void ShowIpForUnknownSymbol(ReportLib* report_lib) EXPORT; -void ShowArtFrames(ReportLib* report_lib, bool show) EXPORT; -void MergeJavaMethods(ReportLib* report_lib, bool merge) EXPORT; - -Sample* GetNextSample(ReportLib* report_lib) EXPORT; -Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT; -SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT; -CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT; -const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) EXPORT; - -const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT; -FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) EXPORT; -} +namespace simpleperf { struct EventInfo { perf_event_attr attr; @@ -134,13 +112,11 @@ struct EventInfo { class ReportLib { public: ReportLib() - : log_severity_( - new android::base::ScopedLogSeverity(android::base::INFO)), + : log_severity_(new android::base::ScopedLogSeverity(android::base::INFO)), record_filename_("perf.data"), current_thread_(nullptr), trace_offcpu_(false), - show_art_frames_(false) { - } + callchain_report_builder_(thread_tree_) {} bool SetLogSeverity(const char* log_level); @@ -154,8 +130,14 @@ class ReportLib { bool SetKallsymsFile(const char* kallsyms_file); void ShowIpForUnknownSymbol() { thread_tree_.ShowIpForUnknownSymbol(); } - void ShowArtFrames(bool show) { show_art_frames_ = show; } - void MergeJavaMethods(bool merge) { merge_java_methods_ = merge; } + void ShowArtFrames(bool show) { + bool remove_art_frame = !show; + callchain_report_builder_.SetRemoveArtFrame(remove_art_frame); + } + void MergeJavaMethods(bool merge) { callchain_report_builder_.SetConvertJITFrame(merge); } + bool AddProguardMappingFile(const char* mapping_file) { + return callchain_report_builder_.AddProguardMappingFile(mapping_file); + } Sample* GetNextSample(); Event* GetEventOfCurrentSample() { return ¤t_event_; } @@ -193,10 +175,7 @@ class ReportLib { std::unordered_map<pid_t, std::unique_ptr<SampleRecord>> next_sample_cache_; FeatureSection feature_section_; std::vector<char> feature_section_data_; - bool show_art_frames_; - bool merge_java_methods_ = true; - // Map from a java method name to it's dex file, start_addr and len. - std::unordered_map<std::string, std::tuple<Dso*, uint64_t, uint64_t>> java_methods_; + CallChainReportBuilder callchain_report_builder_; std::unique_ptr<Tracing> tracing_; }; @@ -232,15 +211,6 @@ bool ReportLib::OpenRecordFileIfNecessary() { if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end()) { trace_offcpu_ = it->second == "true"; } - if (merge_java_methods_) { - for (Dso* dso : thread_tree_.GetAllDsos()) { - if (dso->type() == DSO_DEX_FILE) { - for (auto& symbol : dso->GetSymbols()) { - java_methods_[symbol.Name()] = std::make_tuple(dso, symbol.addr, symbol.len); - } - } - } - } } return true; } @@ -295,8 +265,8 @@ void ReportLib::SetCurrentSample() { current_sample_.in_kernel = r.InKernel(); current_sample_.cpu = r.cpu_data.cpu; if (trace_offcpu_) { - uint64_t next_time = std::max(next_sample_cache_[r.tid_data.tid]->time_data.time, - r.time_data.time + 1); + uint64_t next_time = + std::max(next_sample_cache_[r.tid_data.tid]->time_data.time, r.time_data.time + 1); current_sample_.period = next_time - r.time_data.time; } else { current_sample_.period = r.period_data.period; @@ -304,62 +274,23 @@ void ReportLib::SetCurrentSample() { size_t kernel_ip_count; std::vector<uint64_t> ips = r.GetCallChain(&kernel_ip_count); - std::vector<std::pair<uint64_t, const MapEntry*>> ip_maps; - bool near_java_method = false; - auto is_map_for_interpreter = [](const MapEntry* map) { - return android::base::EndsWith(map->dso->Path(), "/libart.so") || - android::base::EndsWith(map->dso->Path(), "/libartd.so"); - }; - for (size_t i = 0; i < ips.size(); ++i) { - const MapEntry* map = thread_tree_.FindMap(current_thread_, ips[i], i < kernel_ip_count); - if (!show_art_frames_) { - // Remove interpreter frames both before and after the Java frame. - if (map->dso->IsForJavaMethod()) { - near_java_method = true; - while (!ip_maps.empty() && is_map_for_interpreter(ip_maps.back().second)) { - ip_maps.pop_back(); - } - } else if (is_map_for_interpreter(map)){ - if (near_java_method) { - continue; - } - } else { - near_java_method = false; - } - } - ip_maps.push_back(std::make_pair(ips[i], map)); - } - for (auto& pair : ip_maps) { - uint64_t ip = pair.first; - const MapEntry* map = pair.second; - uint64_t vaddr_in_file; - const Symbol* symbol = thread_tree_.FindSymbol(map, ip, &vaddr_in_file); - CallChainEntry entry; - entry.ip = ip; - entry.symbol.dso_name = map->dso->Path().c_str(); - entry.symbol.vaddr_in_file = vaddr_in_file; - entry.symbol.symbol_name = symbol->DemangledName(); - entry.symbol.symbol_addr = symbol->addr; - entry.symbol.symbol_len = symbol->len; - entry.symbol.mapping = AddMapping(*map); - - if (merge_java_methods_ && map->dso->type() == DSO_ELF_FILE && map->dso->IsForJavaMethod()) { - // This is a jitted java method, merge it with the interpreted java method having the same - // name if possible. Otherwise, merge it with other jitted java methods having the same name - // by assigning a common dso_name. - if (auto it = java_methods_.find(entry.symbol.symbol_name); it != java_methods_.end()) { - entry.symbol.dso_name = std::get<0>(it->second)->Path().c_str(); - entry.symbol.symbol_addr = std::get<1>(it->second); - entry.symbol.symbol_len = std::get<2>(it->second); - // Not enough info to map an offset in a jitted method to an offset in a dex file. So just - // use the symbol_addr. - entry.symbol.vaddr_in_file = entry.symbol.symbol_addr; - } else { - entry.symbol.dso_name = "[JIT cache]"; - } + std::vector<CallChainReportEntry> report_entries = + callchain_report_builder_.Build(current_thread_, ips, kernel_ip_count); + + for (const auto& report_entry : report_entries) { + callchain_entries_.resize(callchain_entries_.size() + 1); + CallChainEntry& entry = callchain_entries_.back(); + entry.ip = report_entry.ip; + if (report_entry.dso_name != nullptr) { + entry.symbol.dso_name = report_entry.dso_name; + } else { + entry.symbol.dso_name = report_entry.dso->GetReportPath().data(); } - - callchain_entries_.push_back(entry); + entry.symbol.vaddr_in_file = report_entry.vaddr_in_file; + entry.symbol.symbol_name = report_entry.symbol->DemangledName(); + entry.symbol.symbol_addr = report_entry.symbol->addr; + entry.symbol.symbol_len = report_entry.symbol->len; + entry.symbol.mapping = AddMapping(*report_entry.map); } current_sample_.ip = callchain_entries_[0].ip; current_symbol_ = &(callchain_entries_[0].symbol); @@ -409,6 +340,7 @@ void ReportLib::CreateEvents() { field.elem_size = format.fields[i].elem_size; field.elem_count = format.fields[i].elem_count; field.is_signed = format.fields[i].is_signed; + field.is_dynamic = format.fields[i].is_dynamic; } if (tracing_info.fields.empty()) { tracing_info.data_format.size = 0; @@ -462,6 +394,40 @@ FeatureSection* ReportLib::GetFeatureSection(const char* feature_name) { return &feature_section_; } +} // namespace simpleperf + +using ReportLib = simpleperf::ReportLib; + +extern "C" { + +#define EXPORT __attribute__((visibility("default"))) + +// Create a new instance, +// pass the instance to the other functions below. +ReportLib* CreateReportLib() EXPORT; +void DestroyReportLib(ReportLib* report_lib) EXPORT; + +// Set log severity, different levels are: +// verbose, debug, info, warning, error, fatal. +bool SetLogSeverity(ReportLib* report_lib, const char* log_level) EXPORT; +bool SetSymfs(ReportLib* report_lib, const char* symfs_dir) EXPORT; +bool SetRecordFile(ReportLib* report_lib, const char* record_file) EXPORT; +bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) EXPORT; +void ShowIpForUnknownSymbol(ReportLib* report_lib) EXPORT; +void ShowArtFrames(ReportLib* report_lib, bool show) EXPORT; +void MergeJavaMethods(ReportLib* report_lib, bool merge) EXPORT; +bool AddProguardMappingFile(ReportLib* report_lib, const char* mapping_file) EXPORT; + +Sample* GetNextSample(ReportLib* report_lib) EXPORT; +Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT; +SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT; +CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT; +const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) EXPORT; + +const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT; +FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) EXPORT; +} + // Exported methods working with a client created instance ReportLib* CreateReportLib() { return new ReportLib(); @@ -499,6 +465,10 @@ bool SetKallsymsFile(ReportLib* report_lib, const char* kallsyms_file) { return report_lib->SetKallsymsFile(kallsyms_file); } +bool AddProguardMappingFile(ReportLib* report_lib, const char* mapping_file) { + return report_lib->AddProguardMappingFile(mapping_file); +} + Sample* GetNextSample(ReportLib* report_lib) { return report_lib->GetNextSample(); } |