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;
 };