From 976bea3cccd5fc7453abd22fc9f9d8808cc78371 Mon Sep 17 00:00:00 2001 From: Fahrzin Hemmati Date: Mon, 23 Dec 2024 03:18:13 -0800 Subject: [PATCH] Improve get_interface_attr speed through caching --- opendbc/car/interfaces.py | 48 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/opendbc/car/interfaces.py b/opendbc/car/interfaces.py index 4b7a0956e8..8b1086725e 100644 --- a/opendbc/car/interfaces.py +++ b/opendbc/car/interfaces.py @@ -375,28 +375,42 @@ def update(self, CC: structs.CarControl, CS: CarStateBase, now_nanos: int) -> tu # interface-specific helpers +_brand_values = {} # attr_file => brand_name => module +_brand_names = None def get_interface_attr(attr: str, combine_brands: bool = False, ignore_none: bool = False) -> dict[str | StrEnum, Any]: + global _brand_names # read all the folders in opendbc/car and return a dict where: # - keys are all the car models or brand names # - values are attr values from all car folders result = {} - for car_folder in sorted([x[0] for x in os.walk(BASEDIR)]): - try: - brand_name = car_folder.split('/')[-1] - brand_values = __import__(f'opendbc.car.{brand_name}.{INTERFACE_ATTR_FILE.get(attr, "values")}', fromlist=[attr]) - if hasattr(brand_values, attr) or not ignore_none: - attr_data = getattr(brand_values, attr, None) - else: - continue - - if combine_brands: - if isinstance(attr_data, dict): - for f, v in attr_data.items(): - result[f] = v - else: - result[brand_name] = attr_data - except (ImportError, OSError): - pass + attr_file = INTERFACE_ATTR_FILE.get(attr, "values") + if _brand_names is None: + _brand_names = [folder.split('/')[-1] for folder in sorted(x[0] for x in os.walk(BASEDIR))] + if attr_file not in _brand_values: + _brand_values[attr_file] = {} + for brand_name in _brand_names: + try: + brand_values = __import__(f'opendbc.car.{brand_name}.{attr_file}', fromlist=[attr]) + _brand_values[attr_file][brand_name] = brand_values + except (ImportError, OSError): + pass + + for brand_name in _brand_names: + brand_values = _brand_values[attr_file].get(brand_name) + if brand_values is None: + # This was an ImportError or OSError, so we skip it + continue + if hasattr(brand_values, attr) or not ignore_none: + attr_data = getattr(brand_values, attr, None) + else: + continue + + if combine_brands: + if isinstance(attr_data, dict): + for f, v in attr_data.items(): + result[f] = v + else: + result[brand_name] = attr_data return result