diff options
Diffstat (limited to 'simpleperf/report_lib_interface.cpp')
-rw-r--r-- | simpleperf/report_lib_interface.cpp | 280 |
1 files changed, 43 insertions, 237 deletions
diff --git a/simpleperf/report_lib_interface.cpp b/simpleperf/report_lib_interface.cpp index 1025c325..d6a4bc09 100644 --- a/simpleperf/report_lib_interface.cpp +++ b/simpleperf/report_lib_interface.cpp @@ -15,8 +15,6 @@ */ #include <memory> -#include <optional> -#include <queue> #include <utility> #include <android-base/file.h> @@ -24,7 +22,6 @@ #include <android-base/strings.h> #include "JITDebugReader.h" -#include "RecordFilter.h" #include "dso.h" #include "event_attr.h" #include "event_type.h" @@ -100,7 +97,6 @@ struct FeatureSection { } // extern "C" namespace simpleperf { -namespace { struct EventInfo { perf_event_attr attr; @@ -113,77 +109,22 @@ struct EventInfo { } tracing_info; }; -// If a recording file is generated with --trace-offcpu, we can select TraceOffCpuMode to report. -// It affects which samples are reported, and how period in each sample is calculated. -enum class TraceOffCpuMode { - // Only report on-cpu samples, with period representing time spent on cpu. - ON_CPU, - // Only report off-cpu samples, with period representing time spent off cpu. - OFF_CPU, - // Report both on-cpu and off-cpu samples. - ON_OFF_CPU, - // Report on-cpu and off-cpu samples under the same event type. - MIXED_ON_OFF_CPU, -}; - -static std::string TraceOffCpuModeToString(TraceOffCpuMode mode) { - switch (mode) { - case TraceOffCpuMode::ON_CPU: - return "on-cpu"; - case TraceOffCpuMode::OFF_CPU: - return "off-cpu"; - case TraceOffCpuMode::ON_OFF_CPU: - return "on-off-cpu"; - case TraceOffCpuMode::MIXED_ON_OFF_CPU: - return "mixed-on-off-cpu"; - } -} - -static std::optional<TraceOffCpuMode> StringToTraceOffCpuMode(const std::string& s) { - if (s == "on-cpu") { - return TraceOffCpuMode::ON_CPU; - } - if (s == "off-cpu") { - return TraceOffCpuMode::OFF_CPU; - } - if (s == "on-off-cpu") { - return TraceOffCpuMode::ON_OFF_CPU; - } - if (s == "mixed-on-off-cpu") { - return TraceOffCpuMode::MIXED_ON_OFF_CPU; - } - return std::nullopt; -} - -struct TraceOffCpuData { - std::vector<TraceOffCpuMode> supported_modes; - std::string supported_modes_string; - std::optional<TraceOffCpuMode> mode; - std::unordered_map<pid_t, std::unique_ptr<SampleRecord>> thread_map; -}; - -} // namespace - class ReportLib { public: ReportLib() : log_severity_(new android::base::ScopedLogSeverity(android::base::INFO)), record_filename_("perf.data"), current_thread_(nullptr), - callchain_report_builder_(thread_tree_), - record_filter_(thread_tree_) {} + trace_offcpu_(false), + callchain_report_builder_(thread_tree_) {} bool SetLogSeverity(const char* log_level); bool SetSymfs(const char* symfs_dir) { return Dso::SetSymFsDir(symfs_dir); } bool SetRecordFile(const char* record_file) { - if (record_file_reader_) { - LOG(ERROR) << "recording file " << record_filename_ << " has been opened"; - return false; - } record_filename_ = record_file; - return OpenRecordFileIfNecessary(); + return true; } bool SetKallsymsFile(const char* kallsyms_file); @@ -197,9 +138,6 @@ class ReportLib { bool AddProguardMappingFile(const char* mapping_file) { return callchain_report_builder_.AddProguardMappingFile(mapping_file); } - const char* GetSupportedTraceOffCpuModes(); - bool SetTraceOffCpuMode(const char* mode); - bool SetSampleFilter(const char** filters, int filters_len); Sample* GetNextSample(); Event* GetEventOfCurrentSample() { return ¤t_event_; } @@ -211,10 +149,7 @@ class ReportLib { FeatureSection* GetFeatureSection(const char* feature_name); private: - void ProcessSampleRecord(std::unique_ptr<Record> r); - void ProcessSwitchRecord(std::unique_ptr<Record> r); - void AddSampleRecordToQueue(SampleRecord* r); - void SetCurrentSample(const SampleRecord& r); + void SetCurrentSample(); const EventInfo* FindEventOfCurrentSample(); void CreateEvents(); @@ -225,7 +160,7 @@ class ReportLib { std::string record_filename_; std::unique_ptr<RecordFileReader> record_file_reader_; ThreadTree thread_tree_; - std::queue<std::unique_ptr<SampleRecord>> sample_record_queue_; + std::unique_ptr<SampleRecord> current_record_; const ThreadEntry* current_thread_; Sample current_sample_; Event current_event_; @@ -236,12 +171,12 @@ class ReportLib { std::vector<CallChainEntry> callchain_entries_; std::string build_id_string_; std::vector<EventInfo> events_; - TraceOffCpuData trace_offcpu_; + bool trace_offcpu_; + std::unordered_map<pid_t, std::unique_ptr<SampleRecord>> next_sample_cache_; FeatureSection feature_section_; std::vector<char> feature_section_data_; CallChainReportBuilder callchain_report_builder_; std::unique_ptr<Tracing> tracing_; - RecordFilter record_filter_; }; bool ReportLib::SetLogSeverity(const char* log_level) { @@ -265,51 +200,6 @@ bool ReportLib::SetKallsymsFile(const char* kallsyms_file) { return true; } -const char* ReportLib::GetSupportedTraceOffCpuModes() { - if (!OpenRecordFileIfNecessary()) { - return nullptr; - } - std::string& s = trace_offcpu_.supported_modes_string; - s.clear(); - for (auto mode : trace_offcpu_.supported_modes) { - if (!s.empty()) { - s += ","; - } - s += TraceOffCpuModeToString(mode); - } - return s.data(); -} - -bool ReportLib::SetTraceOffCpuMode(const char* mode) { - auto mode_value = StringToTraceOffCpuMode(mode); - if (!mode_value) { - return false; - } - if (!OpenRecordFileIfNecessary()) { - return false; - } - auto& modes = trace_offcpu_.supported_modes; - if (std::find(modes.begin(), modes.end(), mode_value) == modes.end()) { - return false; - } - trace_offcpu_.mode = mode_value; - return true; -} - -bool ReportLib::SetSampleFilter(const char** filters, int filters_len) { - std::vector<std::string> args; - for (int i = 0; i < filters_len; i++) { - args.emplace_back(filters[i]); - } - OptionFormatMap option_formats = GetRecordFilterOptionFormats(false); - OptionValueMap options; - std::vector<std::pair<OptionName, OptionValue>> ordered_options; - if (!ConvertArgsToOptions(args, option_formats, "", &options, &ordered_options, nullptr)) { - return false; - } - return record_filter_.ParseOptions(options); -} - bool ReportLib::OpenRecordFileIfNecessary() { if (record_file_reader_ == nullptr) { record_file_reader_ = RecordFileReader::CreateInstance(record_filename_); @@ -318,24 +208,8 @@ bool ReportLib::OpenRecordFileIfNecessary() { } record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_); auto& meta_info = record_file_reader_->GetMetaInfoFeature(); - if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end() && it->second == "true") { - // If recorded with --trace-offcpu, default is to report on-off-cpu samples. - std::string event_name = GetEventNameByAttr(*record_file_reader_->AttrSection()[0].attr); - if (!android::base::StartsWith(event_name, "cpu-clock") && - !android::base::StartsWith(event_name, "task-clock")) { - LOG(ERROR) << "Recording file " << record_filename_ << " is no longer supported. " - << "--trace-offcpu must be used with `-e cpu-clock` or `-e task-clock`."; - return false; - } - trace_offcpu_.mode = TraceOffCpuMode::MIXED_ON_OFF_CPU; - trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::MIXED_ON_OFF_CPU); - trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::ON_OFF_CPU); - trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::ON_CPU); - trace_offcpu_.supported_modes.push_back(TraceOffCpuMode::OFF_CPU); - } - if (!record_filter_.CheckClock(record_file_reader_->GetClockId())) { - LOG(ERROR) << "Recording file " << record_filename_ << " doesn't match the clock of filter."; - return false; + if (auto it = meta_info.find("trace_offcpu"); it != meta_info.end()) { + trace_offcpu_ = it->second == "true"; } } return true; @@ -345,102 +219,43 @@ Sample* ReportLib::GetNextSample() { if (!OpenRecordFileIfNecessary()) { return nullptr; } - if (!sample_record_queue_.empty()) { - sample_record_queue_.pop(); - } - while (sample_record_queue_.empty()) { + while (true) { std::unique_ptr<Record> record; - if (!record_file_reader_->ReadRecord(record) || record == nullptr) { + if (!record_file_reader_->ReadRecord(record)) { + return nullptr; + } + if (record == nullptr) { return nullptr; } thread_tree_.Update(*record); if (record->type() == PERF_RECORD_SAMPLE) { - ProcessSampleRecord(std::move(record)); - } else if (record->type() == PERF_RECORD_SWITCH || - record->type() == PERF_RECORD_SWITCH_CPU_WIDE) { - ProcessSwitchRecord(std::move(record)); + if (trace_offcpu_) { + SampleRecord* r = static_cast<SampleRecord*>(record.release()); + auto it = next_sample_cache_.find(r->tid_data.tid); + if (it == next_sample_cache_.end()) { + next_sample_cache_[r->tid_data.tid].reset(r); + continue; + } else { + record.reset(it->second.release()); + it->second.reset(r); + } + } + current_record_.reset(static_cast<SampleRecord*>(record.release())); + break; } else if (record->type() == PERF_RECORD_TRACING_DATA || record->type() == SIMPLE_PERF_RECORD_TRACING_DATA) { const auto& r = *static_cast<TracingDataRecord*>(record.get()); tracing_.reset(new Tracing(std::vector<char>(r.data, r.data + r.data_size))); } } - SetCurrentSample(*sample_record_queue_.front()); + SetCurrentSample(); return ¤t_sample_; } -void ReportLib::ProcessSampleRecord(std::unique_ptr<Record> r) { - auto sr = static_cast<SampleRecord*>(r.get()); - if (!trace_offcpu_.mode) { - r.release(); - AddSampleRecordToQueue(sr); - return; - } - size_t attr_index = record_file_reader_->GetAttrIndexOfRecord(sr); - bool offcpu_sample = attr_index > 0; - if (trace_offcpu_.mode == TraceOffCpuMode::ON_CPU) { - if (!offcpu_sample) { - r.release(); - AddSampleRecordToQueue(sr); - } - return; - } - uint32_t tid = sr->tid_data.tid; - auto it = trace_offcpu_.thread_map.find(tid); - if (it == trace_offcpu_.thread_map.end() || !it->second) { - // If there is no previous off-cpu sample, then store the current off-cpu sample. - if (offcpu_sample) { - r.release(); - if (it == trace_offcpu_.thread_map.end()) { - trace_offcpu_.thread_map[tid].reset(sr); - } else { - it->second.reset(sr); - } - } - } else { - // If there is a previous off-cpu sample, update its period. - SampleRecord* prev_sr = it->second.get(); - prev_sr->period_data.period = - (prev_sr->Timestamp() < sr->Timestamp()) ? (sr->Timestamp() - prev_sr->Timestamp()) : 1; - it->second.release(); - AddSampleRecordToQueue(prev_sr); - if (offcpu_sample) { - r.release(); - it->second.reset(sr); - } - } - if (!offcpu_sample && (trace_offcpu_.mode == TraceOffCpuMode::ON_OFF_CPU || - trace_offcpu_.mode == TraceOffCpuMode::MIXED_ON_OFF_CPU)) { - r.release(); - AddSampleRecordToQueue(sr); - } -} - -void ReportLib::ProcessSwitchRecord(std::unique_ptr<Record> r) { - if (r->header.misc & PERF_RECORD_MISC_SWITCH_OUT) { - return; - } - uint32_t tid = r->sample_id.tid_data.tid; - auto it = trace_offcpu_.thread_map.find(tid); - if (it != trace_offcpu_.thread_map.end() && it->second) { - // If there is a previous off-cpu sample, update its period. - SampleRecord* prev_sr = it->second.get(); - prev_sr->period_data.period = - (prev_sr->Timestamp() < r->Timestamp()) ? (r->Timestamp() - prev_sr->Timestamp()) : 1; - it->second.release(); - AddSampleRecordToQueue(prev_sr); - } -} - -void ReportLib::AddSampleRecordToQueue(SampleRecord* r) { - if (record_filter_.Check(r)) { - sample_record_queue_.emplace(r); - } -} - -void ReportLib::SetCurrentSample(const SampleRecord& r) { +void ReportLib::SetCurrentSample() { current_mappings_.clear(); callchain_entries_.clear(); + SampleRecord& r = *current_record_; current_sample_.ip = r.ip_data.ip; current_sample_.pid = r.tid_data.pid; current_sample_.tid = r.tid_data.tid; @@ -449,7 +264,13 @@ void ReportLib::SetCurrentSample(const SampleRecord& r) { current_sample_.time = r.time_data.time; current_sample_.in_kernel = r.InKernel(); current_sample_.cpu = r.cpu_data.cpu; - current_sample_.period = r.period_data.period; + if (trace_offcpu_) { + 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; + } size_t kernel_ip_count; std::vector<uint64_t> ips = r.GetCallChain(&kernel_ip_count); @@ -490,13 +311,13 @@ const EventInfo* ReportLib::FindEventOfCurrentSample() { if (events_.empty()) { CreateEvents(); } - if (trace_offcpu_.mode == TraceOffCpuMode::MIXED_ON_OFF_CPU) { - // To mix on-cpu and off-cpu samples, pretend they are from the same event type. - // Otherwise, some report scripts may split them. - return &events_[0]; + size_t attr_index; + if (trace_offcpu_) { + // For trace-offcpu, we don't want to show event sched:sched_switch. + attr_index = 0; + } else { + attr_index = record_file_reader_->GetAttrIndexOfRecord(current_record_.get()); } - SampleRecord* r = sample_record_queue_.front().get(); - size_t attr_index = record_file_reader_->GetAttrIndexOfRecord(r); return &events_[attr_index]; } @@ -596,9 +417,6 @@ 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; -const char* GetSupportedTraceOffCpuModes(ReportLib* report_lib) EXPORT; -bool SetTraceOffCpuMode(ReportLib* report_lib, const char* mode) EXPORT; -bool SetSampleFilter(ReportLib* report_lib, const char** filters, int filters_len) EXPORT; Sample* GetNextSample(ReportLib* report_lib) EXPORT; Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT; @@ -651,18 +469,6 @@ bool AddProguardMappingFile(ReportLib* report_lib, const char* mapping_file) { return report_lib->AddProguardMappingFile(mapping_file); } -const char* GetSupportedTraceOffCpuModes(ReportLib* report_lib) { - return report_lib->GetSupportedTraceOffCpuModes(); -} - -bool SetTraceOffCpuMode(ReportLib* report_lib, const char* mode) { - return report_lib->SetTraceOffCpuMode(mode); -} - -bool SetSampleFilter(ReportLib* report_lib, const char** filters, int filters_len) { - return report_lib->SetSampleFilter(filters, filters_len); -} - Sample* GetNextSample(ReportLib* report_lib) { return report_lib->GetNextSample(); } |