From 08df2835113f3d090f2091ced356bbfdcc39b017 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Wed, 1 Jul 2026 11:50:57 -0500 Subject: [PATCH] kachow --- launch_chffrplus.sh | 79 +++++++++++++++++-- system/manager/helpers.py | 23 +++--- system/manager/manager.py | 55 +++++++++++-- system/manager/process.py | 10 ++- .../test/test_launch_param_migrations.py | 4 +- 5 files changed, 142 insertions(+), 29 deletions(-) diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index 1fa0fcb0c..39ec1c291 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -6,6 +6,7 @@ source "$DIR/launch_env.sh" export SP_BOOT_TIMING_LOG="${SP_BOOT_TIMING_LOG:-/tmp/starpilot_boot_timing.log}" : > "$SP_BOOT_TIMING_LOG" 2>/dev/null || true +PREBUILT_COMPAT_CACHE="${SP_PREBUILT_COMPAT_CACHE:-/cache/starpilot_prebuilt_runtime_compatible_v1}" SP_LAUNCH_LAST_SECONDS=$SECONDS function sp_boot_timing_line { @@ -20,6 +21,54 @@ function sp_launch_timing { SP_LAUNCH_LAST_SECONDS=$now } +function launch_param_migrations_needed { + local marker_dir="/data/params/.starpilot_param_migrations/${OPENPILOT_PREFIX:-d}" + [ ! -f "$marker_dir/.starpilot_launch_param_migrations_v2" ] && return 0 + [ ! -f "$marker_dir/.starpilot_branch_defaults_migrations_v1" ] && return 0 + [ ! -f "$marker_dir/.starpilot_acceleration_profile_default_v1" ] && return 0 + return 1 +} + +function prebuilt_runtime_artifacts { + printf '%s\n' \ + "$DIR/common/params_pyx.so" \ + "$DIR/msgq/ipc_pyx.so" \ + "$DIR/msgq/visionipc/visionipc_pyx.so" \ + "$DIR/common/transformations/transformations.so" \ + "$DIR/selfdrive/modeld/models/driving_tinygrad.pkl" \ + "$DIR/selfdrive/modeld/models/dmonitoring_model_metadata.pkl" \ + "$DIR/selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl" \ + "$DIR/selfdrive/modeld/models/dm_warp_1928x1208_tinygrad.pkl" \ + "$DIR/selfdrive/modeld/models/dm_warp_1344x760_tinygrad.pkl" \ + "$DIR/selfdrive/pandad/pandad_api_impl.so" \ + "$DIR/selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so" \ + "$DIR/selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/libacados_ocp_solver_lat.so" \ + "$DIR/selfdrive/controls/lib/longitudinal_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so" \ + "$DIR/selfdrive/controls/lib/longitudinal_mpc_lib/c_generated_code/libacados_ocp_solver_long.so" \ + "$DIR/opendbc_repo/opendbc/dbc/gm_global_a_powertrain_generated.dbc" +} + +function prebuilt_compat_cache_valid { + [ -f "$PREBUILT_COMPAT_CACHE" ] || return 1 + [ -f "$DIR/prebuilt" ] || return 1 + [ "$DIR/prebuilt" -nt "$PREBUILT_COMPAT_CACHE" ] && return 1 + + while IFS= read -r artifact; do + [ -e "$artifact" ] || return 1 + [ "$artifact" -nt "$PREBUILT_COMPAT_CACHE" ] && return 1 + done < <(prebuilt_runtime_artifacts) + + return 0 +} + +function prebuilt_artifacts_present { + while IFS= read -r artifact; do + [ -e "$artifact" ] || return 1 + done < <(prebuilt_runtime_artifacts) + + return 0 +} + function agnos_init { sp_launch_timing "agnos_init_start" @@ -126,11 +175,15 @@ function launch { # start manager cd system/manager - sp_launch_timing "launch_param_migrations_start" - if ! python3 ./launch_param_migrations.py; then - echo "Launch param migrations failed; continuing boot." + if launch_param_migrations_needed; then + sp_launch_timing "launch_param_migrations_start" + if ! python3 ./launch_param_migrations.py; then + echo "Launch param migrations failed; continuing boot." + fi + sp_launch_timing "launch_param_migrations_done" + else + sp_launch_timing "launch_param_migrations_skipped" fi - sp_launch_timing "launch_param_migrations_done" # Bootstrap runtime (e.g. /usr/comma after reset/uninstall) must go straight # to manager/setup flow. Do not run StarPilot prebuilt checks/builds here. @@ -213,9 +266,21 @@ PY fi sp_launch_timing "prebuilt_decision_done" - if [ "$USE_PREBUILT" = "1" ] && [ -f $DIR/prebuilt ] && ! prebuilt_runtime_compatible; then - echo "Prebuilt runtime artifacts are incompatible on this device; rebuilding locally." - USE_PREBUILT=0 + if [ "$USE_PREBUILT" = "1" ] && [ -f $DIR/prebuilt ]; then + if prebuilt_compat_cache_valid; then + sp_launch_timing "prebuilt_compat_cache_hit" + elif [ "${SP_STRICT_PREBUILT_CHECK:-0}" != "1" ] && prebuilt_artifacts_present; then + sp_launch_timing "prebuilt_compat_fast_path" + mkdir -p "$(dirname "$PREBUILT_COMPAT_CACHE")" 2>/dev/null || true + touch "$PREBUILT_COMPAT_CACHE" 2>/dev/null || true + elif prebuilt_runtime_compatible; then + mkdir -p "$(dirname "$PREBUILT_COMPAT_CACHE")" 2>/dev/null || true + touch "$PREBUILT_COMPAT_CACHE" 2>/dev/null || true + else + echo "Prebuilt runtime artifacts are incompatible on this device; rebuilding locally." + rm -f "$PREBUILT_COMPAT_CACHE" 2>/dev/null || true + USE_PREBUILT=0 + fi fi sp_launch_timing "prebuilt_compat_done" diff --git a/system/manager/helpers.py b/system/manager/helpers.py index 047d0ac2d..32fdd538a 100644 --- a/system/manager/helpers.py +++ b/system/manager/helpers.py @@ -51,17 +51,20 @@ def write_onroad_params(started, params): def save_bootlog(): - # copy current params - tmp = tempfile.mkdtemp() - params_dirname = pathlib.Path(Params().get_param_path()).name - params_dir = os.path.join(tmp, params_dirname) - shutil.copytree(Params().get_param_path(), params_dir, dirs_exist_ok=True) - - def fn(tmpdir): + def fn(): + tmpdir = tempfile.mkdtemp() env = os.environ.copy() env['PARAMS_COPY_PATH'] = tmpdir - subprocess.call("./bootlog", cwd=os.path.join(BASEDIR, "system/loggerd"), env=env) - shutil.rmtree(tmpdir) - t = threading.Thread(target=fn, args=(tmp, )) + + try: + params = Params() + params_dirname = pathlib.Path(params.get_param_path()).name + params_dir = os.path.join(tmpdir, params_dirname) + shutil.copytree(params.get_param_path(), params_dir, dirs_exist_ok=True) + subprocess.call("./bootlog", cwd=os.path.join(BASEDIR, "system/loggerd"), env=env) + finally: + shutil.rmtree(tmpdir, ignore_errors=True) + + t = threading.Thread(target=fn) t.daemon = True t.start() diff --git a/system/manager/manager.py b/system/manager/manager.py index d3875f21b..995ef2d58 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -6,6 +6,7 @@ import shutil from pathlib import Path import signal import sys +import threading import time import traceback @@ -23,7 +24,6 @@ def _append_boot_timing_line(line: str) -> None: from cereal import car, log import cereal.messaging as messaging -import openpilot.system.sentry as sentry from openpilot.common.utils import atomic_write from openpilot.common.params import Params, ParamKeyFlag, ParamKeyType from openpilot.common.text_window import TextWindow @@ -83,6 +83,37 @@ def _log_boot_timing(scope: str, label: str, start: float, previous: float | Non return now +def _sync_params_cache_async(cache_params_path: str, values: list[tuple[bytes | str, object]]) -> None: + try: + params_cache = Params(cache_params_path, return_defaults=True) + for key, value in values: + if params_cache.get(key) != value: + params_cache.put(key, value) + except Exception: + cloudlog.exception("failed to sync params cache") + + +def _init_sentry_async() -> None: + def fn() -> None: + try: + import openpilot.system.sentry as sentry + + sentry.init(sentry.SentryProject.SELFDRIVE) + except Exception: + cloudlog.exception("failed to initialize sentry") + + threading.Thread(target=fn, daemon=True).start() + + +def _capture_manager_exception() -> None: + try: + import openpilot.system.sentry as sentry + + sentry.capture_exception() + except Exception: + cloudlog.exception("failed to capture manager exception") + + def _to_text(value): if value is None: return None @@ -810,6 +841,7 @@ def manager_init() -> None: last_timing = _log_boot_timing("manager_init", "starpilot_migrations", manager_init_start, last_timing) # set unset params to their default value + params_cache_updates = [] for k in params.all_keys(): current_value = params.get(k) if current_value is None: @@ -817,7 +849,9 @@ def manager_init() -> None: if cached_value is not None: params.put(k, cached_value) else: - params_cache.put(k, current_value) + params_cache_updates.append((k, current_value)) + if params_cache_updates: + threading.Thread(target=_sync_params_cache_async, args=(cache_params_path, params_cache_updates), daemon=True).start() last_timing = _log_boot_timing("manager_init", "params_defaults_cache_sync", manager_init_start, last_timing) # Create folders needed for msgq @@ -862,7 +896,6 @@ def manager_init() -> None: os.environ['CLEAN'] = '1' # init logging - sentry.init(sentry.SentryProject.SELFDRIVE) cloudlog.bind_global(dongle_id=dongle_id, version=build_metadata.openpilot.version, origin=build_metadata.openpilot.git_normalized_origin, @@ -870,12 +903,18 @@ def manager_init() -> None: commit=build_metadata.openpilot.git_commit, dirty=build_metadata.openpilot.is_dirty, device=HARDWARE.get_device_type()) + _init_sentry_async() last_timing = _log_boot_timing("manager_init", "logging_ready", manager_init_start, last_timing) - # preimport all processes - for p in managed_processes.values(): - p.prepare() - last_timing = _log_boot_timing("manager_init", "preimport_processes", manager_init_start, last_timing) + # Preimporting every process serializes a lot of import work before manager can + # start the always-on processes. Keep the old behavior available for debugging, + # but optimize normal boot by letting children import their modules in parallel. + if os.getenv("SP_MANAGER_PREIMPORT", "0").lower() in ("1", "true", "yes", "on"): + for p in managed_processes.values(): + p.prepare() + last_timing = _log_boot_timing("manager_init", "preimport_processes", manager_init_start, last_timing) + else: + last_timing = _log_boot_timing("manager_init", "preimport_processes_skipped", manager_init_start, last_timing) # StarPilot variables install_starpilot(build_metadata, params) @@ -1024,7 +1063,7 @@ def main() -> None: manager_thread() except Exception: traceback.print_exc() - sentry.capture_exception() + _capture_manager_exception() finally: manager_cleanup() diff --git a/system/manager/process.py b/system/manager/process.py index 516d34159..11e1cbdfc 100644 --- a/system/manager/process.py +++ b/system/manager/process.py @@ -16,7 +16,6 @@ from setproctitle import setproctitle from cereal import car, log import cereal.messaging as messaging -import openpilot.system.sentry as sentry from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params from openpilot.common.swaglog import cloudlog @@ -429,7 +428,6 @@ def launcher(proc: str, name: str, nice: int | None = None) -> None: # add daemon name tag to logs cloudlog.bind(daemon=name) - sentry.set_tag("daemon", name) # exec the process mod.main() @@ -438,7 +436,13 @@ def launcher(proc: str, name: str, nice: int | None = None) -> None: except Exception: # can't install the crash handler because sys.excepthook doesn't play nice # with threads, so catch it here. - sentry.capture_exception() + try: + import openpilot.system.sentry as sentry + + sentry.set_tag("daemon", name) + sentry.capture_exception() + except Exception: + cloudlog.exception(f"failed to capture exception for child {proc}") raise diff --git a/system/manager/test/test_launch_param_migrations.py b/system/manager/test/test_launch_param_migrations.py index 5f1701948..67d3fa356 100644 --- a/system/manager/test/test_launch_param_migrations.py +++ b/system/manager/test/test_launch_param_migrations.py @@ -50,7 +50,9 @@ class FileBackedFakeParams: def marker_path(tmp_path: Path, marker_name: str) -> Path: - return tmp_path / MARKER_DIRNAME / "params" / marker_name + path = tmp_path / MARKER_DIRNAME / "params" / marker_name + path.parent.mkdir(parents=True, exist_ok=True) + return path def test_apply_launch_param_migrations_sets_branch_defaults_once(tmp_path):