Fix simulation sent_time and add a test
It was hard-coded to the actual monotonic_clock::now() call, which
doesn't work well with actual simulation when you don't use fake time.
And we want to kill fake time.
Change-Id: If5785679d54100e5021bea86df763d98d44f7c3d
diff --git a/aos/events/BUILD b/aos/events/BUILD
index e0e6bad..dc5ac9c 100644
--- a/aos/events/BUILD
+++ b/aos/events/BUILD
@@ -56,20 +56,21 @@
)
cc_test(
- name = "simulated-event-loop_test",
+ name = "simulated_event_loop_test",
testonly = True,
srcs = ["simulated-event-loop_test.cc"],
deps = [
":event-loop_param_test",
- ":simulated-event-loop",
+ ":simulated_event_loop",
"//aos/testing:googletest",
],
)
cc_library(
- name = "simulated-event-loop",
+ name = "simulated_event_loop",
srcs = ["simulated-event-loop.cc"],
hdrs = ["simulated-event-loop.h"],
+ visibility = ["//visibility:public"],
deps = [
":event-loop",
"//aos:queues",
diff --git a/aos/events/event-loop.h b/aos/events/event-loop.h
index 908718d..2a3673e 100644
--- a/aos/events/event-loop.h
+++ b/aos/events/event-loop.h
@@ -67,9 +67,6 @@
// if the message was successfully sent, and false otherwise.
bool Send() {
RawSender *sender = &msg_.get_deleter();
- // TODO(austin): This lets multiple senders reorder messages since time
- // isn't acquired with a lock held.
- msg_->SetTimeToNow();
return sender->Send(
reinterpret_cast<RawSender::SendContext *>(msg_.release()));
}
diff --git a/aos/events/event-loop_param_test.cc b/aos/events/event-loop_param_test.cc
index efac8f9..aa03643 100644
--- a/aos/events/event-loop_param_test.cc
+++ b/aos/events/event-loop_param_test.cc
@@ -7,7 +7,10 @@
enum { kQueueLength = 100, kHash = 0x696c0cdc };
int msg_value;
- void Zero() { msg_value = 0; }
+ void Zero() {
+ ::aos::Message::Zero();
+ msg_value = 0;
+ }
static size_t Size() { return 1 + ::aos::Message::Size(); }
size_t Print(char *buffer, size_t length) const;
TestMessage() { Zero(); }
@@ -168,5 +171,37 @@
EXPECT_EQ(iteration_list.size(), 3);
}
+
+// Verify that the send time on a message is roughly right.
+TEST_P(AbstractEventLoopTest, MessageSendTime) {
+ auto loop1 = Make();
+ auto loop2 = Make();
+ auto sender = loop1->MakeSender<TestMessage>("/test");
+ auto fetcher = loop2->MakeFetcher<TestMessage>("/test");
+
+ auto test_timer = loop1->AddTimer([&sender]() {
+ auto msg = sender.MakeMessage();
+ msg->msg_value = 200;
+ msg.Send();
+ });
+
+ test_timer->Setup(loop1->monotonic_now() + ::std::chrono::seconds(1));
+
+ EndEventLoop(loop1.get(), ::std::chrono::seconds(2));
+ loop1->Run();
+
+ EXPECT_TRUE(fetcher.Fetch());
+
+ monotonic_clock::duration time_offset =
+ fetcher->sent_time - (loop1->monotonic_now() - ::std::chrono::seconds(1));
+
+ EXPECT_TRUE(time_offset > ::std::chrono::milliseconds(-500))
+ << ": Got " << fetcher->sent_time.time_since_epoch().count() << " expected "
+ << loop1->monotonic_now().time_since_epoch().count();
+ EXPECT_TRUE(time_offset < ::std::chrono::milliseconds(500))
+ << ": Got " << fetcher->sent_time.time_since_epoch().count()
+ << " expected " << loop1->monotonic_now().time_since_epoch().count();
+}
+
} // namespace testing
} // namespace aos
diff --git a/aos/events/shm-event-loop.cc b/aos/events/shm-event-loop.cc
index a70d6f3..c9ff6fd 100644
--- a/aos/events/shm-event-loop.cc
+++ b/aos/events/shm-event-loop.cc
@@ -71,6 +71,14 @@
bool Send(SendContext *msg) override {
assert(queue_ != NULL);
+ {
+ ::aos::Message *aos_msg = reinterpret_cast<Message *>(msg);
+ // TODO(austin): This lets multiple senders reorder messages since time
+ // isn't acquired with a lock held.
+ if (aos_msg->sent_time == monotonic_clock::min_time) {
+ aos_msg->sent_time = monotonic_clock::now();
+ }
+ }
return queue_->WriteMessage(msg, RawQueue::kOverride);
}
diff --git a/aos/events/simulated-event-loop.cc b/aos/events/simulated-event-loop.cc
index 5fe1bf5..02d15a6 100644
--- a/aos/events/simulated-event-loop.cc
+++ b/aos/events/simulated-event-loop.cc
@@ -35,7 +35,8 @@
class SimulatedSender : public RawSender {
public:
- SimulatedSender(SimulatedQueue *queue) : queue_(queue) {}
+ SimulatedSender(SimulatedQueue *queue, EventLoop *event_loop)
+ : queue_(queue), event_loop_(event_loop) {}
~SimulatedSender() {}
SendContext *GetContext() override {
@@ -48,6 +49,12 @@
}
bool Send(SendContext *context) override {
+ {
+ ::aos::Message *aos_msg = reinterpret_cast<Message *>(context);
+ if (aos_msg->sent_time == monotonic_clock::min_time) {
+ aos_msg->sent_time = event_loop_->monotonic_now();
+ }
+ }
queue_->Send(RefCountedBuffer(reinterpret_cast<aos::Message *>(context)));
return true; // Maybe false instead? :)
}
@@ -56,9 +63,114 @@
private:
SimulatedQueue *queue_;
+ EventLoop *event_loop_;
};
} // namespace
+class SimulatedTimerHandler : public TimerHandler {
+ public:
+ explicit SimulatedTimerHandler(EventScheduler *scheduler,
+ ::std::function<void()> fn)
+ : scheduler_(scheduler), fn_(fn) {}
+ ~SimulatedTimerHandler() {}
+
+ void Setup(monotonic_clock::time_point base,
+ monotonic_clock::duration repeat_offset) override {
+ Disable();
+ const ::aos::monotonic_clock::time_point monotonic_now =
+ scheduler_->monotonic_now();
+ base_ = base;
+ repeat_offset_ = repeat_offset;
+ if (base < monotonic_now) {
+ token_ = scheduler_->Schedule(monotonic_now, [this]() { HandleEvent(); });
+ } else {
+ token_ = scheduler_->Schedule(base, [this]() { HandleEvent(); });
+ }
+ }
+
+ void HandleEvent() {
+ const ::aos::monotonic_clock::time_point monotonic_now =
+ scheduler_->monotonic_now();
+ if (repeat_offset_ != ::aos::monotonic_clock::zero()) {
+ // Reschedule.
+ while (base_ <= monotonic_now) base_ += repeat_offset_;
+ token_ = scheduler_->Schedule(base_, [this]() { HandleEvent(); });
+ } else {
+ token_ = EventScheduler::Token();
+ }
+ fn_();
+ }
+
+ void Disable() override {
+ if (token_ != EventScheduler::Token()) {
+ scheduler_->Deschedule(token_);
+ token_ = EventScheduler::Token();
+ }
+ }
+
+ private:
+ EventScheduler *scheduler_;
+ EventScheduler::Token token_;
+ // Function to be run on the thread
+ ::std::function<void()> fn_;
+ monotonic_clock::time_point base_;
+ monotonic_clock::duration repeat_offset_;
+};
+
+
+class SimulatedEventLoop : public EventLoop {
+ public:
+ explicit SimulatedEventLoop(
+ EventScheduler *scheduler,
+ ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue>
+ *queues)
+ : scheduler_(scheduler), queues_(queues) {}
+ ~SimulatedEventLoop() override {};
+
+ ::aos::monotonic_clock::time_point monotonic_now() override {
+ return scheduler_->monotonic_now();
+ }
+
+ ::std::unique_ptr<RawSender> MakeRawSender(
+ const ::std::string &path, const QueueTypeInfo &type) override;
+
+ ::std::unique_ptr<RawFetcher> MakeRawFetcher(
+ const ::std::string &path, const QueueTypeInfo &type) override;
+
+ void MakeRawWatcher(
+ const ::std::string &path, const QueueTypeInfo &type,
+ ::std::function<void(const ::aos::Message *message)> watcher) override;
+
+ TimerHandler *AddTimer(::std::function<void()> callback) override {
+ timers_.emplace_back(new SimulatedTimerHandler(scheduler_, callback));
+ return timers_.back().get();
+ }
+
+ void OnRun(::std::function<void()> on_run) override {
+ scheduler_->Schedule(scheduler_->monotonic_now(), on_run);
+ }
+ void Run() override {
+ set_is_running(true);
+ scheduler_->Run();
+ }
+ void Exit() override {
+ set_is_running(false);
+ scheduler_->Exit();
+ }
+
+ SimulatedQueue *GetSimulatedQueue(
+ const ::std::pair<::std::string, QueueTypeInfo> &);
+
+ void Take(const ::std::string &path);
+
+ private:
+ EventScheduler *scheduler_;
+ ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue>
+ *queues_;
+ ::std::vector<std::string> taken_;
+ ::std::vector<std::unique_ptr<TimerHandler>> timers_;
+};
+
EventScheduler::Token EventScheduler::Schedule(
::aos::monotonic_clock::time_point time, ::std::function<void()> callback) {
return events_list_.emplace(time, callback);
@@ -91,7 +203,7 @@
const std::string &path, const QueueTypeInfo &type) {
Take(path);
::std::pair<::std::string, QueueTypeInfo> key(path, type);
- return GetSimulatedQueue(key)->MakeRawSender();
+ return GetSimulatedQueue(key)->MakeRawSender(this);
}
std::unique_ptr<RawFetcher> SimulatedEventLoop::MakeRawFetcher(
@@ -117,8 +229,9 @@
watchers_.push_back(watcher);
}
-std::unique_ptr<RawSender> SimulatedQueue::MakeRawSender() {
- return std::unique_ptr<RawSender>(new SimulatedSender(this));
+std::unique_ptr<RawSender> SimulatedQueue::MakeRawSender(
+ EventLoop *event_loop) {
+ return std::unique_ptr<RawSender>(new SimulatedSender(this, event_loop));
}
std::unique_ptr<RawFetcher> SimulatedQueue::MakeRawFetcher() {
@@ -136,4 +249,10 @@
taken_.emplace_back(path);
}
}
+
+::std::unique_ptr<EventLoop> SimulatedEventLoopFactory::MakeEventLoop() {
+ return ::std::unique_ptr<EventLoop>(
+ new SimulatedEventLoop(&scheduler_, &queues_));
+}
+
} // namespace aos
diff --git a/aos/events/simulated-event-loop.h b/aos/events/simulated-event-loop.h
index b5c94bf..9a0aa6e 100644
--- a/aos/events/simulated-event-loop.h
+++ b/aos/events/simulated-event-loop.h
@@ -95,7 +95,7 @@
void Exit() { is_running_ = false; }
- ::aos::monotonic_clock::time_point now() { return now_; }
+ ::aos::monotonic_clock::time_point monotonic_now() const { return now_; }
private:
::aos::monotonic_clock::time_point now_ = ::aos::monotonic_clock::epoch();
@@ -109,17 +109,18 @@
EventScheduler *scheduler)
: type_(type), name_(name), scheduler_(scheduler){};
- std::unique_ptr<RawSender> MakeRawSender();
+ ::std::unique_ptr<RawSender> MakeRawSender(EventLoop *event_loop);
- std::unique_ptr<RawFetcher> MakeRawFetcher();
+ ::std::unique_ptr<RawFetcher> MakeRawFetcher();
- void MakeRawWatcher(std::function<void(const aos::Message *message)> watcher);
+ void MakeRawWatcher(
+ ::std::function<void(const ::aos::Message *message)> watcher);
void Send(RefCountedBuffer message) {
index_++;
latest_message_ = message;
for (auto &watcher : watchers_) {
- scheduler_->Schedule(scheduler_->now(),
+ scheduler_->Schedule(scheduler_->monotonic_now(),
[watcher, message]() { watcher(message.get()); });
}
}
@@ -141,116 +142,21 @@
EventScheduler *scheduler_;
};
-class SimulatedTimerHandler : public TimerHandler {
- public:
- explicit SimulatedTimerHandler(EventScheduler *scheduler,
- ::std::function<void()> fn)
- : scheduler_(scheduler), fn_(fn) {}
- ~SimulatedTimerHandler() {}
-
- void Setup(monotonic_clock::time_point base,
- monotonic_clock::duration repeat_offset) override {
- Disable();
- auto now = scheduler_->now();
- base_ = base;
- repeat_offset_ = repeat_offset;
- if (base < now) {
- token_ = scheduler_->Schedule(now, [this]() { HandleEvent(); });
- } else {
- token_ = scheduler_->Schedule(base, [this]() { HandleEvent(); });
- }
- }
-
- void HandleEvent() {
- auto now = scheduler_->now();
- if (repeat_offset_ != ::aos::monotonic_clock::zero()) {
- // Reschedule.
- while (base_ <= now) base_ += repeat_offset_;
- token_ = scheduler_->Schedule(base_, [this]() { HandleEvent(); });
- } else {
- token_ = EventScheduler::Token();
- }
- fn_();
- }
-
- void Disable() override {
- if (token_ != EventScheduler::Token()) {
- scheduler_->Deschedule(token_);
- token_ = EventScheduler::Token();
- }
- }
-
- private:
- EventScheduler *scheduler_;
- EventScheduler::Token token_;
- // Function to be run on the thread
- ::std::function<void()> fn_;
- monotonic_clock::time_point base_;
- monotonic_clock::duration repeat_offset_;
-};
-
-class SimulatedEventLoop : public EventLoop {
- public:
- explicit SimulatedEventLoop(
- EventScheduler *scheduler,
- ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue>
- *queues) : scheduler_(scheduler), queues_(queues){};
- ~SimulatedEventLoop() override{};
-
- ::aos::monotonic_clock::time_point monotonic_now() override {
- return scheduler_->now();
- }
-
- std::unique_ptr<RawSender> MakeRawSender(const std::string &path,
- const QueueTypeInfo &type) override;
-
- std::unique_ptr<RawFetcher> MakeRawFetcher(
- const std::string &path, const QueueTypeInfo &type) override;
-
- void MakeRawWatcher(
- const std::string &path, const QueueTypeInfo &type,
- std::function<void(const aos::Message *message)> watcher) override;
-
- TimerHandler *AddTimer(::std::function<void()> callback) override {
- timers_.emplace_back(new SimulatedTimerHandler(scheduler_, callback));
- return timers_.back().get();
- }
-
- void OnRun(std::function<void()> on_run) override {
- scheduler_->Schedule(scheduler_->now(), on_run);
- }
- void Run() override {
- set_is_running(true);
- scheduler_->Run();
- }
- void Exit() override {
- set_is_running(false);
- scheduler_->Exit();
- }
-
- SimulatedQueue *GetSimulatedQueue(
- const ::std::pair<::std::string, QueueTypeInfo> &);
-
- void Take(const ::std::string &path);
-
- private:
- EventScheduler *scheduler_;
- ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue>
- *queues_;
- ::std::vector<std::string> taken_;
- ::std::vector<std::unique_ptr<TimerHandler>> timers_;
-};
-
class SimulatedEventLoopFactory {
public:
- ::std::unique_ptr<EventLoop> CreateEventLoop() {
- return ::std::unique_ptr<EventLoop>(
- new SimulatedEventLoop(&scheduler_, &queues_));
+ ::std::unique_ptr<EventLoop> MakeEventLoop();
+
+ void Run() { scheduler_.Run(); }
+
+ monotonic_clock::time_point monotonic_now() const {
+ return scheduler_.monotonic_now();
}
private:
EventScheduler scheduler_;
::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue> queues_;
};
+
} // namespace aos
+
#endif //_AOS_EVENTS_TEST_EVENT_LOOP_H_
diff --git a/aos/events/simulated-event-loop_test.cc b/aos/events/simulated-event-loop_test.cc
index 7c11b4a..f652fd9 100644
--- a/aos/events/simulated-event-loop_test.cc
+++ b/aos/events/simulated-event-loop_test.cc
@@ -5,10 +5,12 @@
namespace aos {
namespace testing {
+namespace chrono = ::std::chrono;
+
class SimulatedEventLoopTestFactory : public EventLoopTestFactory {
public:
- std::unique_ptr<EventLoop> Make() override {
- return event_loop.CreateEventLoop();
+ ::std::unique_ptr<EventLoop> Make() override {
+ return event_loop.MakeEventLoop();
}
private:
SimulatedEventLoopFactory event_loop;