Merge "Simpleperf: report lost record count and warn if 10% records are lost."
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 352361e..1695542 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -148,7 +148,8 @@
dump_symbols_(false),
perf_mmap_pages_(0),
record_filename_("perf.data"),
- sample_record_count_(0) {
+ sample_record_count_(0),
+ lost_record_count_(0) {
signaled = false;
scoped_signal_handler_.reset(
new ScopedSignalHandler({SIGCHLD, SIGINT, SIGTERM}, signal_handler));
@@ -210,6 +211,7 @@
std::unique_ptr<ScopedSignalHandler> scoped_signal_handler_;
uint64_t sample_record_count_;
+ uint64_t lost_record_count_;
};
bool RecordCommand::Run(const std::vector<std::string>& args) {
@@ -306,7 +308,21 @@
return false;
}
}
- LOG(VERBOSE) << "Record " << sample_record_count_ << " samples.";
+
+ // 8. Show brief record result.
+ LOG(INFO) << "Samples recorded: " << sample_record_count_
+ << ". Samples lost: " << lost_record_count_ << ".";
+ if (sample_record_count_ + lost_record_count_ != 0) {
+ double lost_percent = static_cast<double>(lost_record_count_) /
+ (lost_record_count_ + sample_record_count_);
+ constexpr double LOST_PERCENT_WARNING_BAR = 0.1;
+ if (lost_percent >= LOST_PERCENT_WARNING_BAR) {
+ LOG(WARNING) << "Lost " << (lost_percent * 100) << "% of samples, "
+ << "consider increasing mmap_pages(-m), "
+ << "or decreasing sample frequency(-f), "
+ << "or increasing sample period(-c).";
+ }
+ }
return true;
}
@@ -772,6 +788,8 @@
return false;
}
}
+ } else if (record->type() == PERF_RECORD_LOST) {
+ lost_record_count_ += static_cast<LostRecord*>(record)->lost;
}
bool result = record_file_writer_->WriteData(record->BinaryFormat());
return result;
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index a7f6a84..4b1f3e8 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -368,6 +368,31 @@
return record;
}
+LostRecord::LostRecord(const perf_event_attr& attr,
+ const perf_event_header* pheader)
+ : Record(pheader) {
+ const char* p = reinterpret_cast<const char*>(pheader + 1);
+ const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
+ MoveFromBinaryFormat(id, p);
+ MoveFromBinaryFormat(lost, p);
+ CHECK_LE(p, end);
+ sample_id.ReadFromBinaryFormat(attr, p, end);
+}
+
+std::vector<char> LostRecord::BinaryFormat() const {
+ std::vector<char> buf(size());
+ char* p = buf.data();
+ MoveToBinaryFormat(header, p);
+ MoveToBinaryFormat(id, p);
+ MoveToBinaryFormat(lost, p);
+ sample_id.WriteToBinaryFormat(p);
+ return buf;
+}
+
+void LostRecord::DumpData(size_t indent) const {
+ PrintIndented(indent, "id %" PRIu64 ", lost %" PRIu64 "\n", id, lost);
+}
+
SampleRecord::SampleRecord(const perf_event_attr& attr,
const perf_event_header* pheader)
: Record(pheader) {
@@ -857,6 +882,8 @@
return std::unique_ptr<Record>(new ExitRecord(attr, pheader));
case PERF_RECORD_FORK:
return std::unique_ptr<Record>(new ForkRecord(attr, pheader));
+ case PERF_RECORD_LOST:
+ return std::unique_ptr<Record>(new LostRecord(attr, pheader));
case PERF_RECORD_SAMPLE:
return std::unique_ptr<Record>(new SampleRecord(attr, pheader));
case PERF_RECORD_TRACING_DATA:
diff --git a/simpleperf/record.h b/simpleperf/record.h
index f145e80..3afee73 100644
--- a/simpleperf/record.h
+++ b/simpleperf/record.h
@@ -286,6 +286,20 @@
uint64_t event_id);
};
+struct LostRecord : public Record {
+ uint64_t id;
+ uint64_t lost;
+
+ LostRecord() {
+ }
+
+ LostRecord(const perf_event_attr& attr, const perf_event_header* pheader);
+ std::vector<char> BinaryFormat() const override;
+
+ protected:
+ void DumpData(size_t indent) const override;
+};
+
struct SampleRecord : public Record {
uint64_t sample_type; // sample_type is a bit mask determining which fields
// below are valid.
@@ -394,6 +408,7 @@
std::vector<char> BinaryFormat() const override;
static TracingDataRecord Create(std::vector<char> tracing_data);
+
protected:
void DumpData(size_t indent) const override;
};