diff options
author | Yabin Cui <yabinc@google.com> | 2017-07-31 15:08:27 -0700 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2017-08-03 16:04:57 -0700 |
commit | 20663f5fece4082531567d5268130186e40e7f9a (patch) | |
tree | 83f8f0509b29027bfabeab3a85c6043a6ddf464a | |
parent | 2ad09b2ffda41e7974666bbed848ee32fdbbee81 (diff) | |
download | extras-20663f5fece4082531567d5268130186e40e7f9a.tar.gz |
simpleperf: export meta info in report_sample.proto.
To support perf.data generated with --trace-offcpu option,
update interface in report_sample.proto:
1. Add meta info to show all event types.
2. Add event_type_id in each sample to show which even type it belongs to.
Bug: http://b/37572306
Test: run simpleperf_unit_test.
Change-Id: I2878979ec2023904df1006ce353dcf233b6a2642
-rw-r--r-- | simpleperf/cmd_report_sample.cpp | 75 | ||||
-rw-r--r-- | simpleperf/cmd_report_sample_test.cpp | 12 | ||||
-rw-r--r-- | simpleperf/event_selection_set.cpp | 2 | ||||
-rw-r--r-- | simpleperf/event_type.cpp | 4 | ||||
-rw-r--r-- | simpleperf/event_type.h | 2 | ||||
-rw-r--r-- | simpleperf/report_sample.proto | 23 |
6 files changed, 104 insertions, 14 deletions
diff --git a/simpleperf/cmd_report_sample.cpp b/simpleperf/cmd_report_sample.cpp index 73af7d90..44e7471e 100644 --- a/simpleperf/cmd_report_sample.cpp +++ b/simpleperf/cmd_report_sample.cpp @@ -24,6 +24,8 @@ #include <google/protobuf/io/zero_copy_stream_impl_lite.h> #include "command.h" +#include "event_attr.h" +#include "event_type.h" #include "record_file.h" #include "thread_tree.h" #include "utils.h" @@ -79,13 +81,16 @@ class ReportSampleCommand : public Command { report_fp_(nullptr), coded_os_(nullptr), sample_count_(0), - lost_count_(0) {} + lost_count_(0), + trace_offcpu_(false) {} bool Run(const std::vector<std::string>& args) override; private: bool ParseOptions(const std::vector<std::string>& args); bool DumpProtobufReport(const std::string& filename); + bool OpenRecordFile(); + bool PrintMetaInfo(); bool ProcessRecord(std::unique_ptr<Record> record); bool PrintSampleRecordInProtobuf(const SampleRecord& record); bool GetCallEntry(const ThreadEntry* thread, bool in_kernel, uint64_t ip, bool omit_unknown_dso, @@ -110,6 +115,9 @@ class ReportSampleCommand : public Command { google::protobuf::io::CodedOutputStream* coded_os_; size_t sample_count_; size_t lost_count_; + bool trace_offcpu_; + std::unique_ptr<ScopedEventTypes> scoped_event_types_; + std::vector<std::string> event_types_; }; bool ReportSampleCommand::Run(const std::vector<std::string>& args) { @@ -139,12 +147,9 @@ bool ReportSampleCommand::Run(const std::vector<std::string>& args) { } // 4. Open record file. - record_file_reader_ = RecordFileReader::CreateInstance(record_filename_); - if (record_file_reader_ == nullptr) { + if (!OpenRecordFile()) { return false; } - record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_); - if (use_protobuf_) { GOOGLE_PROTOBUF_VERIFY_VERSION; } else { @@ -166,6 +171,9 @@ bool ReportSampleCommand::Run(const std::vector<std::string>& args) { } // 6. Read record file, and print samples online. + if (!PrintMetaInfo()) { + return false; + } if (!record_file_reader_->ReadDataSection( [this](std::unique_ptr<Record> record) { return ProcessRecord(std::move(record)); @@ -277,6 +285,7 @@ bool ReportSampleCommand::DumpProtobufReport(const std::string& filename) { auto& sample = proto_record.sample(); static size_t sample_count = 0; FprintIndented(report_fp_, 0, "sample %zu:\n", ++sample_count); + FprintIndented(report_fp_, 1, "event_type_id: %zu\n", sample.event_type_id()); FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", sample.time()); FprintIndented(report_fp_, 1, "event_count: %" PRIu64 "\n", sample.event_count()); FprintIndented(report_fp_, 1, "thread_id: %d\n", sample.thread_id()); @@ -324,6 +333,12 @@ bool ReportSampleCommand::DumpProtobufReport(const std::string& filename) { FprintIndented(report_fp_, 1, "thread_id: %u\n", thread.thread_id()); FprintIndented(report_fp_, 1, "process_id: %u\n", thread.process_id()); FprintIndented(report_fp_, 1, "thread_name: %s\n", thread.thread_name().c_str()); + } else if (proto_record.has_meta_info()) { + auto& meta_info = proto_record.meta_info(); + FprintIndented(report_fp_, 0, "meta_info:\n"); + for (int i = 0; i < meta_info.event_type_size(); ++i) { + FprintIndented(report_fp_, 1, "event_type: %s\n", meta_info.event_type(i).c_str()); + } } else { LOG(ERROR) << "unexpected record type "; return false; @@ -344,6 +359,49 @@ bool ReportSampleCommand::DumpProtobufReport(const std::string& filename) { return true; } +bool ReportSampleCommand::OpenRecordFile() { + record_file_reader_ = RecordFileReader::CreateInstance(record_filename_); + if (record_file_reader_ == nullptr) { + return false; + } + record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_); + if (record_file_reader_->HasFeature(PerfFileFormat::FEAT_META_INFO)) { + std::unordered_map<std::string, std::string> meta_info; + if (!record_file_reader_->ReadMetaInfoFeature(&meta_info)) { + return false; + } + auto it = meta_info.find("event_type_info"); + if (it != meta_info.end()) { + scoped_event_types_.reset(new ScopedEventTypes(it->second)); + } + it = meta_info.find("trace_offcpu"); + if (it != meta_info.end()) { + trace_offcpu_ = it->second == "true"; + } + } + for (EventAttrWithId& attr : record_file_reader_->AttrSection()) { + event_types_.push_back(GetEventNameByAttr(*attr.attr)); + } + return true; +} + +bool ReportSampleCommand::PrintMetaInfo() { + if (use_protobuf_) { + proto::Record proto_record; + proto::MetaInfo* meta_info = proto_record.mutable_meta_info(); + for (auto& event_type : event_types_) { + *(meta_info->add_event_type()) = event_type; + } + return WriteRecordInProtobuf(proto_record); + } + FprintIndented(report_fp_, 0, "meta_info:\n"); + FprintIndented(report_fp_, 1, "trace_offcpu: %s\n", trace_offcpu_ ? "true" : "false"); + for (auto& event_type : event_types_) { + FprintIndented(report_fp_, 1, "event_type: %s\n", event_type.c_str()); + } + return true; +} + bool ReportSampleCommand::ProcessRecord(std::unique_ptr<Record> record) { thread_tree_.Update(*record); if (record->type() == PERF_RECORD_SAMPLE) { @@ -369,6 +427,7 @@ bool ReportSampleCommand::PrintSampleRecordInProtobuf(const SampleRecord& r) { sample->set_time(r.time_data.time); sample->set_event_count(r.period_data.period); sample->set_thread_id(r.tid_data.tid); + sample->set_event_type_id(record_file_reader_->GetAttrIndexOfRecord(&r)); bool in_kernel = r.InKernel(); const ThreadEntry* thread = @@ -542,9 +601,13 @@ bool ReportSampleCommand::PrintSampleRecord(const SampleRecord& r) { const Symbol* symbol; FprintIndented(report_fp_, 0, "sample:\n"); + FprintIndented(report_fp_, 1, "event_type: %s\n", + event_types_[record_file_reader_->GetAttrIndexOfRecord(&r)].c_str()); FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", r.time_data.time); FprintIndented(report_fp_, 1, "event_count: %" PRIu64 "\n", r.period_data.period); FprintIndented(report_fp_, 1, "thread_id: %d\n", r.tid_data.tid); + const char* thread_name = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid)->comm; + FprintIndented(report_fp_, 1, "thread_name: %s\n", thread_name); bool in_kernel = r.InKernel(); const ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid); @@ -595,7 +658,7 @@ bool ReportSampleCommand::PrintSampleRecord(const SampleRecord& r) { void ReportSampleCommand::PrintLostSituation() { FprintIndented(report_fp_, 0, "lost_situation:\n"); FprintIndented(report_fp_, 1, "sample_count: %" PRIu64 "\n", sample_count_); - FprintIndented(report_fp_, 1, "lost_count: %" PRIu64 "\n", sample_count_); + FprintIndented(report_fp_, 1, "lost_count: %" PRIu64 "\n", lost_count_); } } // namespace diff --git a/simpleperf/cmd_report_sample_test.cpp b/simpleperf/cmd_report_sample_test.cpp index 2a712be4..4c99613a 100644 --- a/simpleperf/cmd_report_sample_test.cpp +++ b/simpleperf/cmd_report_sample_test.cpp @@ -91,3 +91,15 @@ TEST(cmd_report_sample, has_thread_record) { ASSERT_TRUE(android::base::ReadFileToString(tmpfile2.path, &data)); ASSERT_NE(data.find("thread:"), std::string::npos); } + +TEST(cmd_report_sample, trace_offcpu) { + TemporaryFile tmpfile; + TemporaryFile tmpfile2; + ASSERT_TRUE(ReportSampleCmd()->Run({"-i", GetTestData(PERF_DATA_WITH_TRACE_OFFCPU), + "-o", tmpfile.path, "--protobuf"})); + ASSERT_TRUE(ReportSampleCmd()->Run( + {"--dump-protobuf-report", tmpfile.path, "-o", tmpfile2.path})); + std::string data; + ASSERT_TRUE(android::base::ReadFileToString(tmpfile2.path, &data)); + ASSERT_NE(data.find("event_type: sched:sched_switch"), std::string::npos); +} diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp index de04d3d1..59607cb2 100644 --- a/simpleperf/event_selection_set.cpp +++ b/simpleperf/event_selection_set.cpp @@ -57,7 +57,7 @@ bool IsDwarfCallChainSamplingSupported() { } bool IsDumpingRegsForTracepointEventsSupported() { - const EventType* event_type = FindEventTypeByName("sched:sched_switch"); + const EventType* event_type = FindEventTypeByName("sched:sched_switch", false); if (event_type == nullptr) { return false; } diff --git a/simpleperf/event_type.cpp b/simpleperf/event_type.cpp index 21da17c9..39dd67d3 100644 --- a/simpleperf/event_type.cpp +++ b/simpleperf/event_type.cpp @@ -151,7 +151,7 @@ const std::vector<EventType>& GetAllEventTypes() { return event_type_array; } -const EventType* FindEventTypeByName(const std::string& name) { +const EventType* FindEventTypeByName(const std::string& name, bool report_error) { const EventType* result = nullptr; for (auto& event_type : GetAllEventTypes()) { if (android::base::EqualsIgnoreCase(event_type.name, name)) { @@ -159,7 +159,7 @@ const EventType* FindEventTypeByName(const std::string& name) { break; } } - if (result == nullptr) { + if (result == nullptr && report_error) { LOG(ERROR) << "Unknown event_type '" << name << "', try `simpleperf list` to list all possible event type names"; return nullptr; diff --git a/simpleperf/event_type.h b/simpleperf/event_type.h index 1dd7f39f..727f75ff 100644 --- a/simpleperf/event_type.h +++ b/simpleperf/event_type.h @@ -68,7 +68,7 @@ class ScopedEventTypes { }; const std::vector<EventType>& GetAllEventTypes(); -const EventType* FindEventTypeByName(const std::string& name); +const EventType* FindEventTypeByName(const std::string& name, bool report_error = true); struct EventTypeAndModifier { std::string name; diff --git a/simpleperf/report_sample.proto b/simpleperf/report_sample.proto index a40f8032..a869d64f 100644 --- a/simpleperf/report_sample.proto +++ b/simpleperf/report_sample.proto @@ -35,12 +35,22 @@ message Sample { repeated CallChainEntry callchain = 3; - // Count of the events that have happened since last sample (regardless of - // whether the last sample is lost). The event type is decided by '-e' option - // in simpleperf record command. By default, '-e cpu-cycles' is used, and this - // field is the number of cpu cycles. + // Simpleperf generates one sample whenever a specified amount of events happen + // while running a monitored thread. So each sample belongs to one event type. + // Event type can be cpu-cycles, cpu-clock, sched:sched_switch or other types. + // By using '-e' option, we can ask simpleperf to record samples for one or more + // event types. + // Each event type generates samples independently. But recording more event types + // will cost more cpu time generating samples, which may affect the monitored threads + // and sample lost rate. + // event_count field shows the count of the events (belong to the sample's event type) + // that have happened since last sample (belong to the sample's event type) for the + // same thread. However, if there are lost samples between current sample and previous + // sample, the event_count is the count of events from the last lost sample. optional uint64 event_count = 4; + // An index in meta_info.event_type, shows which event type current sample belongs to. + optional uint32 event_type_id = 5; } message LostSituation { @@ -65,11 +75,16 @@ message Thread { optional string thread_name = 3; } +message MetaInfo { + repeated string event_type = 2; +} + message Record { oneof record_data { Sample sample = 1; LostSituation lost = 2; File file = 3; Thread thread = 4; + MetaInfo meta_info = 5; } }
\ No newline at end of file |