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.