Populate error counts for all Send() overloads

Change-Id: I8280f501299e825bf16cdaf58724ea7f1817257d
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/events/event_loop.cc b/aos/events/event_loop.cc
index 3679062..df0390c 100644
--- a/aos/events/event_loop.cc
+++ b/aos/events/event_loop.cc
@@ -61,6 +61,24 @@
                 realtime_remote_time, remote_queue_index, source_boot_uuid);
 }
 
+void RawSender::RecordSendResult(const Error error, size_t message_size) {
+  switch (error) {
+    case Error::kOk: {
+      if (timing_.sender) {
+        timing_.size.Add(message_size);
+        timing_.sender->mutate_count(timing_.sender->count() + 1);
+      }
+      break;
+    }
+    case Error::kMessagesSentTooFast:
+      timing_.IncrementError(timing::SendError::MESSAGE_SENT_TOO_FAST);
+      break;
+    case Error::kInvalidRedzone:
+      timing_.IncrementError(timing::SendError::INVALID_REDZONE);
+      break;
+  }
+}
+
 RawFetcher::RawFetcher(EventLoop *event_loop, const Channel *channel)
     : event_loop_(event_loop),
       channel_(channel),
diff --git a/aos/events/event_loop.h b/aos/events/event_loop.h
index c2498b3..984a006 100644
--- a/aos/events/event_loop.h
+++ b/aos/events/event_loop.h
@@ -244,6 +244,8 @@
                        uint32_t remote_queue_index,
                        const UUID &source_boot_uuid);
 
+  void RecordSendResult(const Error error, size_t message_size);
+
   EventLoop *const event_loop_;
   const Channel *const channel_;
   const std::string ftrace_prefix_;
diff --git a/aos/events/event_loop_param_test.cc b/aos/events/event_loop_param_test.cc
index c8ceeb5..f9e673c 100644
--- a/aos/events/event_loop_param_test.cc
+++ b/aos/events/event_loop_param_test.cc
@@ -1918,6 +1918,63 @@
   }
 }
 
+// Tests that the RawSender::Send(void*, size_t) overload tracks things properly
+// in its timing report.
+TEST_P(AbstractEventLoopTest, CopySenderTimingReport) {
+  gflags::FlagSaver flag_saver;
+  FLAGS_timing_report_ms = 1000;
+  auto loop1 = Make();
+  auto loop2 = MakePrimary();
+
+  const FlatbufferDetachedBuffer<TestMessage> kMessage =
+      JsonToFlatbuffer<TestMessage>("{}");
+
+  std::unique_ptr<aos::RawSender> sender =
+      loop2->MakeRawSender(configuration::GetChannel(
+          loop2->configuration(), "/test", "aos.TestMessage", "", nullptr));
+
+  Fetcher<timing::Report> report_fetcher =
+      loop1->MakeFetcher<timing::Report>("/aos");
+  EXPECT_FALSE(report_fetcher.Fetch());
+
+  loop2->OnRun([&]() {
+    for (int ii = 0; ii < TestChannelQueueSize(loop2.get()); ++ii) {
+      EXPECT_EQ(sender->Send(kMessage.span().data(), kMessage.span().size()),
+                RawSender::Error::kOk);
+    }
+    EXPECT_EQ(sender->Send(kMessage.span().data(), kMessage.span().size()),
+              RawSender::Error::kMessagesSentTooFast);
+  });
+  // Quit after 1 timing report, mid way through the next cycle.
+  EndEventLoop(loop2.get(), chrono::milliseconds(1500));
+
+  Run();
+
+  if (do_timing_reports() == DoTimingReports::kYes) {
+    // Check that the sent too fast actually got recorded by the timing report.
+    FlatbufferDetachedBuffer<timing::Report> primary_report =
+        FlatbufferDetachedBuffer<timing::Report>::Empty();
+    while (report_fetcher.FetchNext()) {
+      if (report_fetcher->name()->string_view() == "primary") {
+        primary_report = CopyFlatBuffer(report_fetcher.get());
+      }
+    }
+
+    EXPECT_EQ(primary_report.message().name()->string_view(), "primary");
+
+    ASSERT_NE(primary_report.message().senders(), nullptr);
+    EXPECT_EQ(primary_report.message().senders()->size(), 3);
+    EXPECT_EQ(
+        primary_report.message()
+            .senders()
+            ->Get(0)
+            ->error_counts()
+            ->Get(static_cast<size_t>(timing::SendError::MESSAGE_SENT_TOO_FAST))
+            ->count(),
+        1);
+  }
+}
+
 // Tests that senders count correctly in the timing report.
 TEST_P(AbstractEventLoopTest, WatcherTimingReport) {
   FLAGS_timing_report_ms = 1000;
diff --git a/aos/events/event_loop_tmpl.h b/aos/events/event_loop_tmpl.h
index 1382332..b3c36cc 100644
--- a/aos/events/event_loop_tmpl.h
+++ b/aos/events/event_loop_tmpl.h
@@ -143,26 +143,13 @@
     uint32_t remote_queue_index, const UUID &uuid) {
   const auto err = DoSend(size, monotonic_remote_time, realtime_remote_time,
                           remote_queue_index, uuid);
-  switch (err) {
-    case Error::kOk: {
-      if (timing_.sender) {
-        timing_.size.Add(size);
-        timing_.sender->mutate_count(timing_.sender->count() + 1);
-      }
-      ftrace_.FormatMessage(
-          "%.*s: sent internal: event=%" PRId64 " queue=%" PRIu32,
-          static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
-          static_cast<int64_t>(
-              monotonic_sent_time().time_since_epoch().count()),
-          sent_queue_index());
-      break;
-    }
-    case Error::kMessagesSentTooFast:
-      timing_.IncrementError(timing::SendError::MESSAGE_SENT_TOO_FAST);
-      break;
-    case Error::kInvalidRedzone:
-      timing_.IncrementError(timing::SendError::INVALID_REDZONE);
-      break;
+  RecordSendResult(err, size);
+  if (err == Error::kOk) {
+    ftrace_.FormatMessage(
+        "%.*s: sent internal: event=%" PRId64 " queue=%" PRIu32,
+        static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
+        static_cast<int64_t>(monotonic_sent_time().time_since_epoch().count()),
+        sent_queue_index());
   }
   return err;
 }
@@ -179,11 +166,8 @@
     uint32_t remote_queue_index, const UUID &uuid) {
   const auto err = DoSend(data, size, monotonic_remote_time,
                           realtime_remote_time, remote_queue_index, uuid);
+  RecordSendResult(err, size);
   if (err == RawSender::Error::kOk) {
-    if (timing_.sender) {
-      timing_.size.Add(size);
-      timing_.sender->mutate_count(timing_.sender->count() + 1);
-    }
     ftrace_.FormatMessage(
         "%.*s: sent external: event=%" PRId64 " queue=%" PRIu32,
         static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
@@ -206,11 +190,8 @@
   const size_t size = data->size();
   const auto err = DoSend(std::move(data), monotonic_remote_time,
                           realtime_remote_time, remote_queue_index, uuid);
+  RecordSendResult(err, size);
   if (err == Error::kOk) {
-    if (timing_.sender) {
-      timing_.size.Add(size);
-      timing_.sender->mutate_count(timing_.sender->count() + 1);
-    }
     ftrace_.FormatMessage(
         "%.*s: sent shared: event=%" PRId64 " queue=%" PRIu32,
         static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),