From 1f312e16d492473a4d252c603f04ec7aff71cfd4 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 9 May 2025 15:13:52 -0400 Subject: [PATCH] messaging: cleanup zero-frequency service initialization (#35145) * messaging: fix bug with relaxed checks under simulation * refactor * cleanup * fix bug * Revert "fix bug" This reverts commit ea31f3ee83676c5b8ffe57500881557f7586998c. * that did need to be different * fix bug, add test coverage * retry CI --- cereal/messaging/__init__.py | 26 +++++++++---------- cereal/messaging/tests/test_pub_sub_master.py | 6 ++++- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/cereal/messaging/__init__.py b/cereal/messaging/__init__.py index 8ad956b61b..b03285f80a 100644 --- a/cereal/messaging/__init__.py +++ b/cereal/messaging/__init__.py @@ -145,12 +145,16 @@ class SubMaster: self.updated = {s: False for s in services} self.recv_time = {s: 0. for s in services} self.recv_frame = {s: 0 for s in services} - self.alive = {s: False for s in services} - self.freq_ok = {s: False for s in services} self.sock = {} self.data = {} - self.valid = {} - self.logMonoTime = {} + self.logMonoTime = {s: 0 for s in services} + + # zero-frequency / on-demand services are always alive and presumed valid; all others must pass checks + on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in services} + self.static_freq_services = set(s for s in services if not on_demand[s]) + self.alive = {s: on_demand[s] for s in services} + self.freq_ok = {s: on_demand[s] for s in services} + self.valid = {s: on_demand[s] for s in services} self.freq_tracker: Dict[str, FrequencyTracker] = {} self.poller = Poller() @@ -177,8 +181,6 @@ class SubMaster: data = new_message(s, 0) # lists self.data[s] = getattr(data.as_reader(), s) - self.logMonoTime[s] = 0 - self.valid[s] = False self.freq_tracker[s] = FrequencyTracker(SERVICE_LIST[s].frequency, self.update_freq, s == poll) def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader: @@ -215,14 +217,10 @@ class SubMaster: self.logMonoTime[s] = msg.logMonoTime self.valid[s] = msg.valid - for s in self.services: - if SERVICE_LIST[s].frequency > 1e-5 and not self.simulation: - # alive if delay is within 10x the expected frequency - self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency) - self.freq_ok[s] = self.freq_tracker[s].valid - else: - self.freq_ok[s] = True - self.alive[s] = self.seen[s] if self.simulation else True + for s in self.static_freq_services: + # alive if delay is within 10x the expected frequency; checks relaxed in simulator + self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency) or (self.seen[s] and self.simulation) + self.freq_ok[s] = self.freq_tracker[s].valid or self.simulation def all_alive(self, service_list: Optional[List[str]] = None) -> bool: return all(self.alive[s] for s in (service_list or self.services) if s not in self.ignore_alive) diff --git a/cereal/messaging/tests/test_pub_sub_master.py b/cereal/messaging/tests/test_pub_sub_master.py index e9bc7a85cb..e47e713393 100644 --- a/cereal/messaging/tests/test_pub_sub_master.py +++ b/cereal/messaging/tests/test_pub_sub_master.py @@ -6,6 +6,7 @@ import cereal.messaging as messaging from cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \ random_bytes, random_carstate, assert_carstate, \ zmq_sleep +from cereal.services import SERVICE_LIST class TestSubMaster: @@ -26,7 +27,9 @@ class TestSubMaster: sm = messaging.SubMaster(socks) assert sm.frame == -1 assert not any(sm.updated.values()) - assert not any(sm.alive.values()) + assert not any(sm.seen.values()) + on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in sm.services} + assert all(sm.alive[s] == sm.valid[s] == sm.freq_ok[s] == on_demand[s] for s in sm.services) assert all(t == 0. for t in sm.recv_time.values()) assert all(f == 0 for f in sm.recv_frame.values()) assert all(t == 0 for t in sm.logMonoTime.values()) @@ -83,6 +86,7 @@ class TestSubMaster: "cameraOdometry": (20, 10), "liveCalibration": (4, 4), "carParams": (None, None), + "userFlag": (None, None), } for service, (max_freq, min_freq) in checks.items():