From 18db927fc1c6289f66ce1b8a8569ccc0bb9dad21 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 11 Mar 2025 14:58:05 -0700 Subject: [PATCH] test_models: convert can data to namedtuple (#34845) * stash * fastest * faster but not fastest * clean up * here too * fix that * revert * already sorted * rev * clean up * allow empty * lower tm time for cache miss --- .github/workflows/selfdrive_tests.yaml | 2 +- selfdrive/car/tests/test_models.py | 30 +++++++++---------- .../debug/check_can_parser_performance.py | 7 ++--- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index a91e9862ac..d9dc5dd455 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -227,7 +227,7 @@ jobs: - name: Build openpilot run: ${{ env.RUN }} "scons -j$(nproc)" - name: Test car models - timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.routes-cache.outputs.cache-hit == 'true') && 1 || 20 }} + timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.routes-cache.outputs.cache-hit == 'true') && 1 || 3 }} run: | ${{ env.RUN }} "MAX_EXAMPLES=1 $PYTEST selfdrive/car/tests/test_models.py && \ chmod -R 777 /tmp/comma_download_cache" diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 7f0cf4a979..9a042ed372 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -1,5 +1,4 @@ import time -import capnp import os import pytest import random @@ -67,7 +66,7 @@ class TestCarModelBase(unittest.TestCase): platform: Platform | None = None test_route: CarTestRoute | None = None - can_msgs: list[capnp.lib.capnp._DynamicStructReader] + can_msgs: list[tuple[int, list[CanData]]] fingerprint: dict[int, dict[int, int]] elm_frame: int | None car_safety_mode_frame: int | None @@ -82,7 +81,8 @@ class TestCarModelBase(unittest.TestCase): experimental_long = False for msg in lr: if msg.which() == "can": - can_msgs.append(msg) + can = can_capnp_to_list((msg.as_builder().to_bytes(),))[0] + can_msgs.append((can[0], [CanData(*can) for can in can[1]])) if len(can_msgs) <= FRAME_FINGERPRINT: for m in msg.can: if m.src < 64: @@ -146,13 +146,11 @@ class TestCarModelBase(unittest.TestCase): raise unittest.SkipTest raise Exception(f"missing test route for {cls.platform}") - car_fw, can_msgs, experimental_long = cls.get_testing_data() + car_fw, cls.can_msgs, experimental_long = cls.get_testing_data() # if relay is expected to be open in the route cls.openpilot_enabled = cls.car_safety_mode_frame is not None - cls.can_msgs = sorted(can_msgs, key=lambda msg: msg.logMonoTime) - cls.CarInterface, cls.CarController, cls.CarState, cls.RadarInterface = interfaces[cls.platform] cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False) assert cls.CP @@ -199,8 +197,8 @@ class TestCarModelBase(unittest.TestCase): CC = structs.CarControl().as_reader() for i, msg in enumerate(self.can_msgs): - CS = self.CI.update(can_capnp_to_list((msg.as_builder().to_bytes(),))) - self.CI.apply(CC, msg.logMonoTime) + CS = self.CI.update(msg) + self.CI.apply(CC, msg[0]) if CS.canValid: can_valid = True @@ -219,7 +217,7 @@ class TestCarModelBase(unittest.TestCase): # start parsing CAN messages after we've left ELM mode and can expect CAN traffic error_cnt = 0 for i, msg in enumerate(self.can_msgs[self.elm_frame:]): - rr: structs.RadarData | None = RI.update(can_capnp_to_list((msg.as_builder().to_bytes(),))) + rr: structs.RadarData | None = RI.update(msg) if rr is not None and i > 50: error_cnt += structs.RadarData.Error.canError in rr.errors self.assertEqual(error_cnt, 0) @@ -228,16 +226,16 @@ class TestCarModelBase(unittest.TestCase): if self.CP.dashcamOnly: self.skipTest("no need to check panda safety for dashcamOnly") - start_ts = self.can_msgs[0].logMonoTime + start_ts = self.can_msgs[0][0] failed_addrs = Counter() for can in self.can_msgs: # update panda timer - t = (can.logMonoTime - start_ts) / 1e3 + t = (can[0] - start_ts) / 1e3 self.safety.set_timer(int(t)) # run all msgs through the safety RX hook - for msg in can.can: + for msg in can[1]: if msg.src >= 64: continue @@ -389,8 +387,8 @@ class TestCarModelBase(unittest.TestCase): # warm up pass, as initial states may be different for can in self.can_msgs[:300]: - self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), ))) - for msg in filter(lambda m: m.src in range(64), can.can): + self.CI.update(can) + for msg in filter(lambda m: m.src < 64, can[1]): to_send = libsafety_py.make_CANPacket(msg.address, msg.src % 4, msg.dat) self.safety.safety_rx_hook(to_send) @@ -399,8 +397,8 @@ class TestCarModelBase(unittest.TestCase): checks = defaultdict(int) vehicle_speed_seen = self.CP.steerControlType == SteerControlType.angle and not self.CP.notCar for idx, can in enumerate(self.can_msgs): - CS = self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), ))).as_reader() - for msg in filter(lambda m: m.src in range(64), can.can): + CS = self.CI.update(can).as_reader() + for msg in filter(lambda m: m.src < 64, can[1]): to_send = libsafety_py.make_CANPacket(msg.address, msg.src % 4, msg.dat) ret = self.safety.safety_rx_hook(to_send) self.assertEqual(1, ret, f"safety rx failed ({ret=}): {(msg.address, msg.src % 4)}") diff --git a/selfdrive/debug/check_can_parser_performance.py b/selfdrive/debug/check_can_parser_performance.py index 61aff0244f..20987b3cf4 100755 --- a/selfdrive/debug/check_can_parser_performance.py +++ b/selfdrive/debug/check_can_parser_performance.py @@ -6,7 +6,6 @@ from tqdm import tqdm from cereal import car from opendbc.car.tests.routes import CarTestRoute from openpilot.selfdrive.car.tests.test_models import TestCarModelBase -from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.tools.plotjuggler.juggle import DEMO_ROUTE N_RUNS = 10 @@ -25,13 +24,11 @@ if __name__ == '__main__': CC = car.CarControl.new_message() ets = [] for _ in tqdm(range(N_RUNS)): - msgs = [m.as_builder().to_bytes() for m in tm.can_msgs] start_t = time.process_time_ns() - for msg in msgs: - can_list = can_capnp_to_list([msg]) + for msg in tm.can_msgs: for cp in tm.CI.can_parsers.values(): if cp is not None: - cp.update_strings(can_list) + cp.update_strings(msg) ets.append((time.process_time_ns() - start_t) * 1e-6) print(f'{len(tm.can_msgs)} CAN packets, {N_RUNS} runs')