summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2017-07-31 15:08:27 -0700
committerYabin Cui <yabinc@google.com>2017-08-03 16:04:57 -0700
commit20663f5fece4082531567d5268130186e40e7f9a (patch)
tree83f8f0509b29027bfabeab3a85c6043a6ddf464a
parent2ad09b2ffda41e7974666bbed848ee32fdbbee81 (diff)
downloadextras-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.cpp75
-rw-r--r--simpleperf/cmd_report_sample_test.cpp12
-rw-r--r--simpleperf/event_selection_set.cpp2
-rw-r--r--simpleperf/event_type.cpp4
-rw-r--r--simpleperf/event_type.h2
-rw-r--r--simpleperf/report_sample.proto23
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