This commit is contained in:
firestar5683
2026-07-01 11:50:57 -05:00
parent ae3792c683
commit 08df283511
5 changed files with 142 additions and 29 deletions
+72 -7
View File
@@ -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"
+13 -10
View File
@@ -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()
+47 -8
View File
@@ -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()
+7 -3
View File
@@ -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
@@ -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):