Add realtime replay support to SimulatedEventLoopFactory
"realtime" is heavily overloaded here, but this adds support
for making it so that you can play a SimulatedEventLoopFactory at
realtime speed (rather than just "as fast as possible"). This
can be useful in a variety of situations (e.g., debugging
tooling that will run in realtime on a robot).
Adds a demonstration of using this in an piece of AOS tooling for
plotting (this change also makes it so that that binary no longer spins
at 100% CPU indefinitely by consequence of better integrating
the EPoll object into the log replay).
Change-Id: Ia01ecd850a50c9b78dd72bfb0e8862672a716067
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/network/log_web_proxy_main.cc b/aos/network/log_web_proxy_main.cc
index 1cc8e17..34e40a2 100644
--- a/aos/network/log_web_proxy_main.cc
+++ b/aos/network/log_web_proxy_main.cc
@@ -17,6 +17,9 @@
DEFINE_int32(buffer_size, -1, "-1 if infinite, in # of messages / channel.");
DEFINE_double(monotonic_start_time, -1.0, "Start time (sec)");
DEFINE_double(monotonic_end_time, -1.0, "End time (sec)");
+DEFINE_double(
+ replay_rate, -1,
+ "-1 to replay as fast as possible; 1.0 = realtime, 0.5 = half speed.");
int main(int argc, char **argv) {
aos::InitGoogle(&argc, &argv);
@@ -31,6 +34,12 @@
reader.Register();
+ // If going for "as fast as possible" don't actually use infinity, because we
+ // don't want the log reading blocking our use of the epoll handlers.
+ reader.SetRealtimeReplayRate(FLAGS_replay_rate == -1.0
+ ? std::numeric_limits<double>::max()
+ : FLAGS_replay_rate);
+
std::unique_ptr<aos::EventLoop> event_loop;
if (FLAGS_node.empty()) {
@@ -55,13 +64,12 @@
}
aos::web_proxy::WebProxy web_proxy(
- event_loop.get(), aos::web_proxy::StoreHistory::kYes, FLAGS_buffer_size);
+ event_loop.get(),
+ reader.event_loop_factory()->scheduler_epoll(),
+ aos::web_proxy::StoreHistory::kYes, FLAGS_buffer_size);
web_proxy.SetDataPath(FLAGS_data_dir.c_str());
- // Keep the web proxy alive past when we finish reading the logfile.
- reader.set_exit_on_finish(false);
-
if (FLAGS_monotonic_end_time > 0) {
event_loop->AddTimer([&web_proxy]() { web_proxy.StopRecording(); })
->Setup(aos::monotonic_clock::time_point(
@@ -70,4 +78,11 @@
}
reader.event_loop_factory()->Run();
+
+ // Keep the web proxy alive past when we finish reading the logfile, but crank
+ // down the replay rate so that we don't peg our entire CPU just trying to
+ // service timers in the web proxy code.
+ reader.set_exit_on_finish(false);
+ reader.SetRealtimeReplayRate(1.0);
+ reader.event_loop_factory()->Run();
}
diff --git a/aos/network/web_proxy.h b/aos/network/web_proxy.h
index 0c1d1dc..2b57c05 100644
--- a/aos/network/web_proxy.h
+++ b/aos/network/web_proxy.h
@@ -77,6 +77,8 @@
int per_channel_buffer_size_bytes);
WebProxy(aos::ShmEventLoop *event_loop, StoreHistory store_history,
int per_channel_buffer_size_bytes);
+ WebProxy(aos::EventLoop *event_loop, aos::internal::EPoll *epoll,
+ StoreHistory store_history, int per_channel_buffer_size_bytes);
~WebProxy();
void SetDataPath(const char *path) { server_.setStaticPath(path); }
@@ -85,9 +87,6 @@
void StopRecording();
private:
- WebProxy(aos::EventLoop *event_loop, aos::internal::EPoll *epoll,
- StoreHistory store_history, int per_channel_buffer_size_bytes);
-
aos::internal::EPoll internal_epoll_;
aos::internal::EPoll *const epoll_;
::seasocks::Server server_;