Make LogReader own SimulatedEventLoopFactory
This reduces some code duplication and makes things easier once we start
need to be able to mess with the config from the LogReader.
Change-Id: Ia1c04f37865cfd284c3675ca138d38b3f4b7717f
diff --git a/aos/BUILD b/aos/BUILD
index e964066..80ba32a 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -302,6 +302,7 @@
tables = [
"Configuration",
"Channel",
+ "Connection",
"Map",
"Node",
],
diff --git a/aos/events/logging/log_cat.cc b/aos/events/logging/log_cat.cc
index 45f0811..1d1dd8b 100644
--- a/aos/events/logging/log_cat.cc
+++ b/aos/events/logging/log_cat.cc
@@ -28,12 +28,10 @@
aos::InitGoogle(&argc, &argv);
aos::logger::LogReader reader(FLAGS_logfile);
- aos::SimulatedEventLoopFactory log_reader_factory(reader.configuration(),
- reader.node());
- reader.Register(&log_reader_factory);
+ reader.Register();
std::unique_ptr<aos::EventLoop> printer_event_loop =
- log_reader_factory.MakeEventLoop("printer");
+ reader.event_loop_factory()->MakeEventLoop("printer");
printer_event_loop->SkipTimingReport();
bool found_channel = false;
@@ -88,9 +86,7 @@
LOG(FATAL) << "Could not find any channels";
}
- log_reader_factory.Run();
-
- reader.Deregister();
+ reader.event_loop_factory()->Run();
aos::Cleanup();
return 0;
diff --git a/aos/events/logging/logger.cc b/aos/events/logging/logger.cc
index 22c1a6e..3e790b6 100644
--- a/aos/events/logging/logger.cc
+++ b/aos/events/logging/logger.cc
@@ -225,7 +225,7 @@
}
LogReader::~LogReader() {
- CHECK(!event_loop_unique_ptr_) << ": Did you remember to call Deregister?";
+ Deregister();
}
const Configuration *LogReader::configuration() const {
@@ -242,9 +242,15 @@
return sorted_message_reader_.realtime_start_time();
}
+void LogReader::Register() {
+ event_loop_factory_unique_ptr_ =
+ std::make_unique<SimulatedEventLoopFactory>(configuration(), node());
+ Register(event_loop_factory_unique_ptr_.get());
+}
+
void LogReader::Register(SimulatedEventLoopFactory *event_loop_factory) {
- event_loop_unique_ptr_ = event_loop_factory->MakeEventLoop("log_reader");
event_loop_factory_ = event_loop_factory;
+ event_loop_unique_ptr_ = event_loop_factory_->MakeEventLoop("log_reader");
// We don't run timing reports when trying to print out logged data, because
// otherwise we would end up printing out the timing reports themselves...
// This is only really relevant when we are replaying into a simulation.
@@ -334,13 +340,16 @@
}
void LogReader::Deregister() {
+ // Make sure that things get destroyed in the correct order, rather than
+ // relying on getting the order correct in the class definition.
for (size_t i = 0; i < channels_.size(); ++i) {
channels_[i].reset();
}
- event_loop_factory_ = nullptr;
event_loop_unique_ptr_.reset();
event_loop_ = nullptr;
+ event_loop_factory_unique_ptr_.reset();
+ event_loop_factory_ = nullptr;
}
} // namespace logger
diff --git a/aos/events/logging/logger.h b/aos/events/logging/logger.h
index a35b453..e5b91ac 100644
--- a/aos/events/logging/logger.h
+++ b/aos/events/logging/logger.h
@@ -62,17 +62,24 @@
LogReader(std::string_view filename);
~LogReader();
+ // Registers everything, but also updates the real time time in sync. Runs
+ // until the log file starts.
+ // Note that if you use any call other than the Register() call with no
+ // arguments, the user is responsible for making sure that the config of the
+ // supplied event loop (factory) provides any necessary remapped configs.
+ void Register();
+ // Does the same as Register(), except it uses a pre-provided event loop
+ // factory.
+ void Register(SimulatedEventLoopFactory *event_loop_factory);
// Registers the timer and senders used to resend the messages from the log
// file.
void Register(EventLoop *event_loop);
- // Registers everything, but also updates the real time time in sync. Runs
- // until the log file starts.
- void Register(SimulatedEventLoopFactory *factory);
- // Unregisters the senders.
+ // Unregisters the senders. You only need to call this if you separately
+ // supplied an event loop or event loop factory and the lifetimes are such
+ // that they need to be explicitly destroyed before the LogReader destructor
+ // gets called.
void Deregister();
- // TODO(austin): Remap channels?
-
// Returns the configuration from the log file.
const Configuration *configuration() const;
@@ -83,6 +90,10 @@
monotonic_clock::time_point monotonic_start_time();
realtime_clock::time_point realtime_start_time();
+ SimulatedEventLoopFactory *event_loop_factory() {
+ return event_loop_factory_;
+ }
+
// TODO(austin): Add the ability to re-publish the fetched messages. Add 2
// options, one which publishes them *now*, and another which publishes them
// to the simulated event loop factory back in time where they actually
@@ -95,12 +106,17 @@
// Log chunk reader.
SortedMessageReader sorted_message_reader_;
+ std::unique_ptr<FlatbufferDetachedBuffer<Configuration>>
+ remapped_configuration_buffer_;
+
std::vector<std::unique_ptr<RawSender>> channels_;
- SimulatedEventLoopFactory *event_loop_factory_ = nullptr;
std::unique_ptr<EventLoop> event_loop_unique_ptr_;
EventLoop *event_loop_ = nullptr;
TimerHandler *timer_handler_;
+
+ std::unique_ptr<SimulatedEventLoopFactory> event_loop_factory_unique_ptr_;
+ SimulatedEventLoopFactory *event_loop_factory_ = nullptr;
};
} // namespace logger
diff --git a/aos/events/logging/logger_test.cc b/aos/events/logging/logger_test.cc
index 91190e7..d96d4c6 100644
--- a/aos/events/logging/logger_test.cc
+++ b/aos/events/logging/logger_test.cc
@@ -64,16 +64,16 @@
LOG(INFO) << "Config " << FlatbufferToJson(reader.configuration());
EXPECT_EQ(reader.node(), nullptr);
- SimulatedEventLoopFactory log_reader_factory(reader.configuration());
-
// This sends out the fetched messages and advances time to the start of the
// log file.
- reader.Register(&log_reader_factory);
+ reader.Register();
- EXPECT_EQ(log_reader_factory.node(), nullptr);
+ EXPECT_EQ(reader.node(), nullptr);
+
+ EXPECT_EQ(reader.event_loop_factory()->node(), nullptr);
std::unique_ptr<EventLoop> test_event_loop =
- log_reader_factory.MakeEventLoop("log_reader");
+ reader.event_loop_factory()->MakeEventLoop("log_reader");
int ping_count = 10;
int pong_count = 10;
@@ -93,10 +93,8 @@
EXPECT_EQ(ping_count, pong_count);
});
- log_reader_factory.RunFor(std::chrono::seconds(100));
+ reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
EXPECT_EQ(ping_count, 2010);
-
- reader.Deregister();
}
// Tests that a large number of messages per second doesn't overwhelm writev.
@@ -209,22 +207,22 @@
}
LogReader reader(logfile);
- ASSERT_NE(reader.node(), nullptr);
- EXPECT_EQ(reader.node()->name()->string_view(), "pi1");
// TODO(austin): Also replay as pi2 or pi3 and make sure we see the pong
// messages. This won't work today yet until the log reading code gets
// significantly better.
- SimulatedEventLoopFactory log_reader_factory(reader.configuration(),
- reader.node());
- log_reader_factory.set_send_delay(chrono::microseconds(0));
// This sends out the fetched messages and advances time to the start of the
// log file.
- reader.Register(&log_reader_factory);
+ reader.Register();
+
+ ASSERT_NE(reader.node(), nullptr);
+ EXPECT_EQ(reader.node()->name()->string_view(), "pi1");
+
+ reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
std::unique_ptr<EventLoop> test_event_loop =
- log_reader_factory.MakeEventLoop("test");
+ reader.event_loop_factory()->MakeEventLoop("test");
int ping_count = 10;
int pong_count = 10;
@@ -252,11 +250,9 @@
EXPECT_EQ(ping_count, pong_count);
});
- log_reader_factory.RunFor(std::chrono::seconds(100));
+ reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
EXPECT_EQ(ping_count, 2010);
EXPECT_EQ(pong_count, 2010);
-
- reader.Deregister();
}
} // namespace testing
diff --git a/frc971/analysis/py_log_reader.cc b/frc971/analysis/py_log_reader.cc
index 5a6fce4..6a002df 100644
--- a/frc971/analysis/py_log_reader.cc
+++ b/frc971/analysis/py_log_reader.cc
@@ -43,7 +43,6 @@
// All the objects that we need for managing reading a logfile.
struct LogReaderTools {
std::unique_ptr<aos::logger::LogReader> reader;
- std::unique_ptr<aos::SimulatedEventLoopFactory> event_loop_factory;
// Event loop to use for subscribing to buses.
std::unique_ptr<aos::EventLoop> event_loop;
std::vector<ChannelData> channel_data;
@@ -58,9 +57,6 @@
void LogReader_dealloc(LogReaderType *self) {
LogReaderTools *tools = self->tools;
- if (!tools->processed) {
- tools->reader->Deregister();
- }
delete tools;
Py_TYPE(self)->tp_free((PyObject *)self);
}
@@ -89,11 +85,10 @@
LogReaderTools *tools = CHECK_NOTNULL(self->tools);
tools->reader = std::make_unique<aos::logger::LogReader>(log_file_name);
- tools->event_loop_factory = std::make_unique<aos::SimulatedEventLoopFactory>(
- tools->reader->configuration());
- tools->reader->Register(tools->event_loop_factory.get());
+ tools->reader->Register();
- tools->event_loop = tools->event_loop_factory->MakeEventLoop("data_fetcher");
+ tools->event_loop =
+ tools->reader->event_loop_factory()->MakeEventLoop("data_fetcher");
tools->event_loop->SkipTimingReport();
return 0;
@@ -199,8 +194,7 @@
tools->processed = true;
- tools->event_loop_factory->Run();
- tools->reader->Deregister();
+ tools->reader->event_loop_factory()->Run();
Py_RETURN_NONE;
}