Convert EventScheduler to use classes for callbacks

std::function is slow to construct and destroy.  Convert the hot path
over to use a class instead.

Change-Id: Ic7627da065576ef0c03bb09e07b60ee5a95b0c94
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/aos/events/event_scheduler.cc b/aos/events/event_scheduler.cc
index 6f2c2c8..c06638c 100644
--- a/aos/events/event_scheduler.cc
+++ b/aos/events/event_scheduler.cc
@@ -8,8 +8,8 @@
 
 namespace aos {
 
-EventScheduler::Token EventScheduler::Schedule(
-    monotonic_clock::time_point time, ::std::function<void()> callback) {
+EventScheduler::Token EventScheduler::Schedule(monotonic_clock::time_point time,
+                                               Event *callback) {
   return events_list_.emplace(time, callback);
 }
 
@@ -58,9 +58,9 @@
   CHECK_EQ(t.boot, boot_count_);
   CHECK_EQ(t.time, iter->first) << ": Time is wrong on node " << node_index_;
 
-  ::std::function<void()> callback = ::std::move(iter->second);
+  Event *callback = iter->second;
   events_list_.erase(iter);
-  callback();
+  callback->Handle();
 
   converter_->ObserveTimePassed(scheduler_scheduler_->distributed_now());
 }
diff --git a/aos/events/event_scheduler.h b/aos/events/event_scheduler.h
index cc70757..55c1cf8 100644
--- a/aos/events/event_scheduler.h
+++ b/aos/events/event_scheduler.h
@@ -85,8 +85,13 @@
 
 class EventScheduler {
  public:
-  using ChannelType =
-      std::multimap<monotonic_clock::time_point, std::function<void()>>;
+  class Event {
+   public:
+    virtual void Handle() noexcept = 0;
+    virtual ~Event() {}
+  };
+
+  using ChannelType = std::multimap<monotonic_clock::time_point, Event *>;
   using Token = ChannelType::iterator;
   EventScheduler(size_t node_index) : node_index_(node_index) {}
 
@@ -97,14 +102,11 @@
     converter_ = converter;
   }
 
-  UUID boot_uuid() {
-    return converter_->boot_uuid(node_index_, boot_count_);
-  }
+  UUID boot_uuid() { return converter_->boot_uuid(node_index_, boot_count_); }
 
   // Schedule an event with a callback function
   // Returns an iterator to the event
-  Token Schedule(monotonic_clock::time_point time,
-                 std::function<void()> callback);
+  Token Schedule(monotonic_clock::time_point time, Event *callback);
 
   // Schedules a callback when the event scheduler starts.
   void ScheduleOnRun(std::function<void()> callback) {
diff --git a/aos/events/simulated_event_loop.cc b/aos/events/simulated_event_loop.cc
index a43cb30..4ea7ebd 100644
--- a/aos/events/simulated_event_loop.cc
+++ b/aos/events/simulated_event_loop.cc
@@ -112,7 +112,7 @@
 
 // TODO(Brian): This should be in the anonymous namespace, but that annoys GCC
 // for some reason...
-class SimulatedWatcher : public WatcherState {
+class SimulatedWatcher : public WatcherState, public EventScheduler::Event {
  public:
   SimulatedWatcher(
       SimulatedEventLoop *simulated_event_loop, EventScheduler *scheduler,
@@ -123,6 +123,8 @@
 
   bool has_run() const;
 
+  void Handle() noexcept override;
+
   void Startup(EventLoop * /*event_loop*/) override {}
 
   void Schedule(std::shared_ptr<SimulatedMessage> message);
@@ -463,7 +465,8 @@
   bool fell_behind_ = false;
 };
 
-class SimulatedTimerHandler : public TimerHandler {
+class SimulatedTimerHandler : public TimerHandler,
+                              public EventScheduler::Event {
  public:
   explicit SimulatedTimerHandler(EventScheduler *scheduler,
                                  SimulatedEventLoop *simulated_event_loop,
@@ -475,6 +478,8 @@
 
   void HandleEvent() noexcept;
 
+  void Handle() noexcept override;
+
   void Disable() override;
 
  private:
@@ -487,7 +492,8 @@
   monotonic_clock::duration repeat_offset_;
 };
 
-class SimulatedPhasedLoopHandler : public PhasedLoopHandler {
+class SimulatedPhasedLoopHandler : public PhasedLoopHandler,
+                                   public EventScheduler::Event {
  public:
   SimulatedPhasedLoopHandler(EventScheduler *scheduler,
                              SimulatedEventLoop *simulated_event_loop,
@@ -500,6 +506,8 @@
 
   void Schedule(monotonic_clock::time_point sleep_time) override;
 
+  void Handle() noexcept override;
+
  private:
   SimulatedEventLoop *simulated_event_loop_;
   EventHandler<SimulatedPhasedLoopHandler> event_;
@@ -887,15 +895,17 @@
   }
 }
 
+void SimulatedWatcher::Handle() noexcept {
+  DCHECK(token_ != scheduler_->InvalidToken());
+  token_ = scheduler_->InvalidToken();
+  simulated_event_loop_->HandleEvent();
+}
+
 void SimulatedWatcher::DoSchedule(monotonic_clock::time_point event_time) {
   CHECK(token_ == scheduler_->InvalidToken())
       << ": May not schedule multiple times";
   token_ = scheduler_->Schedule(
-      event_time + simulated_event_loop_->send_delay(), [this]() {
-        DCHECK(token_ != scheduler_->InvalidToken());
-        token_ = scheduler_->InvalidToken();
-        simulated_event_loop_->HandleEvent();
-      });
+      event_time + simulated_event_loop_->send_delay(), this);
 }
 
 void SimulatedChannel::MakeRawWatcher(SimulatedWatcher *watcher) {
@@ -1085,15 +1095,17 @@
       simulated_event_loop_->monotonic_now();
   base_ = base;
   repeat_offset_ = repeat_offset;
-  token_ = scheduler_->Schedule(std::max(base, monotonic_now), [this]() {
-    DCHECK(token_ != scheduler_->InvalidToken());
-    token_ = scheduler_->InvalidToken();
-    simulated_event_loop_->HandleEvent();
-  });
+  token_ = scheduler_->Schedule(std::max(base, monotonic_now), this);
   event_.set_event_time(base_);
   simulated_event_loop_->AddEvent(&event_);
 }
 
+void SimulatedTimerHandler::Handle() noexcept {
+  DCHECK(token_ != scheduler_->InvalidToken());
+  token_ = scheduler_->InvalidToken();
+  simulated_event_loop_->HandleEvent();
+}
+
 void SimulatedTimerHandler::HandleEvent() noexcept {
   const monotonic_clock::time_point monotonic_now =
       simulated_event_loop_->monotonic_now();
@@ -1111,11 +1123,7 @@
   if (repeat_offset_ != monotonic_clock::zero()) {
     // Reschedule.
     while (base_ <= monotonic_now) base_ += repeat_offset_;
-    token_ = scheduler_->Schedule(base_, [this]() {
-      DCHECK(token_ != scheduler_->InvalidToken());
-      token_ = scheduler_->InvalidToken();
-      simulated_event_loop_->HandleEvent();
-    });
+    token_ = scheduler_->Schedule(base_, this);
     event_.set_event_time(base_);
     simulated_event_loop_->AddEvent(&event_);
   }
@@ -1171,6 +1179,12 @@
   }
 }
 
+void SimulatedPhasedLoopHandler::Handle() noexcept {
+  DCHECK(token_ != scheduler_->InvalidToken());
+  token_ = scheduler_->InvalidToken();
+  simulated_event_loop_->HandleEvent();
+}
+
 void SimulatedPhasedLoopHandler::Schedule(
     monotonic_clock::time_point sleep_time) {
   // The allocations in here are due to infrastructure and don't count in the no
@@ -1180,11 +1194,7 @@
     scheduler_->Deschedule(token_);
     token_ = scheduler_->InvalidToken();
   }
-  token_ = scheduler_->Schedule(sleep_time, [this]() {
-    DCHECK(token_ != scheduler_->InvalidToken());
-    token_ = scheduler_->InvalidToken();
-    simulated_event_loop_->HandleEvent();
-  });
+  token_ = scheduler_->Schedule(sleep_time, this);
   event_.set_event_time(sleep_time);
   simulated_event_loop_->AddEvent(&event_);
 }
diff --git a/aos/events/simulated_event_loop_test.cc b/aos/events/simulated_event_loop_test.cc
index 696c16e..71d4138 100644
--- a/aos/events/simulated_event_loop_test.cc
+++ b/aos/events/simulated_event_loop_test.cc
@@ -138,6 +138,16 @@
   aos::FlatbufferDetachedBuffer<aos::Configuration> config;
 };
 
+class FunctionEvent : public EventScheduler::Event {
+  public:
+   FunctionEvent(std::function<void()> fn) : fn_(fn) {}
+
+   void Handle() noexcept override { fn_(); }
+
+  private:
+   std::function<void()> fn_;
+};
+
 // Test that creating an event and running the scheduler runs the event.
 TEST(EventSchedulerTest, ScheduleEvent) {
   int counter = 0;
@@ -145,12 +155,12 @@
   EventScheduler scheduler(0);
   scheduler_scheduler.AddEventScheduler(&scheduler);
 
-  scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1),
-                     [&counter]() { counter += 1; });
+  FunctionEvent e([&counter]() { counter += 1; });
+  scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1), &e);
   scheduler_scheduler.Run();
   EXPECT_EQ(counter, 1);
-  auto token = scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(2),
-                                  [&counter]() { counter += 1; });
+  auto token =
+      scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(2), &e);
   scheduler.Deschedule(token);
   scheduler_scheduler.Run();
   EXPECT_EQ(counter, 1);
@@ -163,8 +173,9 @@
   EventScheduler scheduler(0);
   scheduler_scheduler.AddEventScheduler(&scheduler);
 
-  auto token = scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1),
-                                  [&counter]() { counter += 1; });
+  FunctionEvent e([&counter]() { counter += 1; });
+  auto token =
+      scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1), &e);
   scheduler.Deschedule(token);
   scheduler_scheduler.Run();
   EXPECT_EQ(counter, 0);
@@ -175,8 +186,7 @@
   TestMessage::Builder test_message_builder =
       builder.MakeBuilder<TestMessage>();
   test_message_builder.add_value(value);
-  ASSERT_EQ(builder.Send(test_message_builder.Finish()),
-            RawSender::Error::kOk);
+  ASSERT_EQ(builder.Send(test_message_builder.Finish()), RawSender::Error::kOk);
 }
 
 // Test that sending a message after running gets properly notified.