Skip to content

Reduce Basilisk cold-start overhead by consolidating native bindings - #1597

Merged
schaubh merged 20 commits into
developfrom
feature/bsk_startup
Oct 9, 2026
Merged

schaubh merged 20 commits into
developfrom
feature/bsk_startup

Conversation

@schaubh

@schaubh schaubh commented Oct 4, 2026

Copy link
Copy Markdown
Contributor
  • Review: By commit
  • Merge strategy: Merge (no squash)

Description

Reduce startup overhead by consolidating native extensions into separate libraries for messaging, core FSW, core simulation, MuJoCo, and OpenCV. Existing Python import paths, constructors, messages, and recorders remain compatible. Bindings initialize on demand, and individual source files and SWIG wrappers still compile separately.

Grouped bindings are the standard packaging layout. Optional dependencies remain optional, and core simulation does not acquire MuJoCo or OpenCV dependencies.

Prototype measurements on macOS arm64, using Release builds and Python 3.14.6, showed these cold-import improvements:

Binding group Separate libraries Grouped library Speedup
Core FSW 12.544 s 0.770 s 16.3×
Core simulation 12.432 s 1.212 s 10.3×
MuJoCo 2.004 s 0.603 s 3.3×
OpenCV 0.557 s 0.241 s 2.3×

These are medians of three trials, measuring group imports after Basilisk initialization. “Cold” means the first process after rebuilding or relinking the native files; no reboot or disk-cache flush was performed.

One 16-worker pytest collection comparison improved from 27.78 s to 21.11 s, approximately 24%, when only the simulation binding layout changed. This was a single comparison, and timings depend on the platform and cache state.

FSW native binaries also decreased from 32.65 MiB to 16.63 MiB. Binding-group rebuild times remained similar overall; simulation’s median increased approximately 4.2%, with overlapping trial ranges. Individual edits still rebuild one object and relink its group. Sparse imports can incur additional loading cost from the larger library.

The 18 commits separate packaging, benchmarks, and test organization from individual fixes. Independent fixes cover module defects, invalid configuration handling, build-generator compatibility, and test reliability. The robotic grappling example also records plotting data at 10 Hz.

Verification

  • Development CI passed on macOS, Linux, and Windows, including separate optional-wheel validation.
  • Additional checks passed for Visual Studio Release and Debug, Ninja Multi-Config, Unix Makefiles, and Visual Studio 2022. Local checks also exercised Xcode.
  • The latest local routine suite passed 8,614 tests, with two prerequisite-related skips. The separate build-integration suite passed 19 tests.
  • Regression coverage includes import compatibility, recorders, concurrent imports, binding-group transitions, SWIG directors, optional wheels, and incremental builds.
  • History cleanup passed 158 focused checks across selected commit boundaries. Final file contents exactly match the version before cleanup, and repository hooks passed.

Temporary diagnostic workflows were removed. Permanent build-integration tests run separately in CI to keep routine test runs faster. The linked CI runs precede the history rewrite; normal PR checks should complete on the submitted commits before merging.

Documentation

Updated developer benchmark instructions, build-integration test guidance, release notes, and affected module documentation. Archived benchmark reports and raw measurements document the prototype comparisons and their limitations.

Known-issue entries describe pre-existing defects addressed by this branch. Focused Sphinx validation passed with warnings treated as errors.

Future work

Optionally extend cold-start measurements to Linux and Windows and profile the remaining pytest collection overhead.

@schaubh schaubh self-assigned this Oct 4, 2026
@schaubh
schaubh requested a review from a team as a code owner October 4, 2026 18:36
@schaubh schaubh added documentation Improvements or additions to documentation enhancement New feature or request build Build system or compilation enhancement labels Oct 4, 2026
@schaubh schaubh added this to Basilisk Oct 4, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-04T18:42:41.458553Z 7e2a243 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

schaubh added a commit that referenced this pull request Oct 5, 2026
Register the Basilisk DLL directory in the isolated retry subprocess without importing Basilisk eagerly. Retain the directory handle across failed imports and retries, and surface early import errors instead of waiting for a misleading initialization timeout.

Validation: 29 related tests passed; all six retry cases passed with simulated Windows DLL-directory preconditions, and a negative control reported the underlying ImportError immediately.
Use a 0.1-second recorder interval for the spacecraft and arm outputs.
Keep the simulation task rate unchanged while reducing plot data volume.
Report invalid parent types before computing forces and torques instead of
continuing with uninitialized parent state. Document the validation behavior.
Use the state-sized scratch vector for covariance downdates. The previous
measurement-sized buffer could overflow when copying a full state column.
Record the pre-existing defect in the release notes and known issues.
schaubh added a commit that referenced this pull request Oct 9, 2026
Scale standard-normal samples by the configured noise levels so zero noise
does not violate the distribution precondition. Preserve random-generator
progression and cover noiseless output and repeatability in regression tests.
schaubh added a commit that referenced this pull request Oct 9, 2026
Apply a supported limb-message planet ID before selecting the radius, retain
the configured target for a zero ID, and reject unsupported IDs. Document
planet selection and add regression coverage for valid and invalid targets.
@schaubh
schaubh force-pushed the feature/bsk_startup branch from 728f715 to 13e56b8 Compare October 9, 2026 13:04
schaubh added a commit that referenced this pull request Oct 9, 2026
Initialize scenarioSmallBodyNav with the filter's 12-state vector. Reject
incorrect state, covariance, and noise matrix dimensions during reset and
update, with Python regression tests and module documentation.
schaubh added a commit that referenced this pull request Oct 9, 2026
Stop marking configure_file outputs as generated build outputs. This avoids
invalid Ninja Multi-Config dependencies and prevents native clean targets
from deleting C message interfaces. Test build, clean, and rebuild behavior.
schaubh added a commit that referenced this pull request Oct 9, 2026
Use a relative logical solution folder instead of an absolute filesystem
path. Extend the C-message build fixture to reject invalid IDE folder names.
schaubh added a commit that referenced this pull request Oct 9, 2026
…builds

Query CMake targets through the File API and normalize fixture paths for
Windows. Build benchmark smoke targets in the active configuration, capture
native warnings through OS pipes, and skip allocation-failure sweeps that
terminate inside noexcept MSVC Debug STL constructors. Retain generator and
warning regression coverage.
schaubh added a commit that referenced this pull request Oct 9, 2026
Allow cold Python and native-library startup before beginning the bounded
thread-lifecycle check. Preserve hang detection with readiness signaling,
traceback diagnostics, captured output, and cleanup of timed-out children.
schaubh added a commit that referenced this pull request Oct 9, 2026
Link separately compiled message wrappers into one native library to reduce
first-import overhead. Preserve existing imports, recorder behavior, and
message build targets through an on-demand loader. Isolate wrapper helper
symbols and verify compatibility, initializer regeneration, and single-message
incremental rebuilds.
schaubh added a commit that referenced this pull request Oct 9, 2026
Generate private import shims and load each extension under Python's import
locking so concurrent imports cannot expose partially initialized bindings.
Track shim outputs in CMake and add concurrent-import regression coverage.
schaubh added a commit that referenced this pull request Oct 9, 2026
Build core FSW wrapper objects into one native library and retain lazy imports,
public module identity, and convenience build targets. Isolate colliding C
symbols and leave custom dependency bindings separate. Make this the standard
layout and test imports, callbacks, cleanup, and incremental compilation.
schaubh added a commit that referenced this pull request Oct 9, 2026
Group core simulation, MuJoCo, and OpenCV bindings into separate native
libraries while preserving optional features and Python imports. Keep Vizard
and unrecognized custom dependencies separate, share the loader, and prepare
SWIG directors for combined linkage. Cover all groups, stale-layout cleanup,
and optional wheel selection with regression tests.
schaubh added a commit that referenced this pull request Oct 9, 2026
Accept both SWIG director-mutex definition forms without altering director
RTTI or callback behavior. Check the generated syntax and compile real SWIG
wrappers across threading and Python API configurations.
schaubh added a commit that referenced this pull request Oct 9, 2026
Write a shared inventory of active bindings so cleanup from the previous
group cannot delete the destination group's shim. Cover moves in both orders,
parallel cleanup, retirement, and native CMake reconfiguration. Account for
whole-second Make timestamps in the reconfiguration fixture.
schaubh added a commit that referenced this pull request Oct 9, 2026
Measure import and collection latency, no-change builds, incremental builds,
and native library sizes. Keep reproducible benchmark tooling and explicitly
label archived comparisons as prototype measurements. Document current usage
and test benchmark command construction and reporting.
schaubh added a commit that referenced this pull request Oct 9, 2026
Share native fixtures across binding groups and avoid redundant compiler
discovery and source inventory scans. Keep full SWIG API and threading
coverage on the primary generator and representative checks on others.
Mark native build integration tests separately and run them in dedicated
platform CI steps so routine pytestCI runs retain fast runtime regressions.
schaubh added a commit that referenced this pull request Oct 9, 2026
Register the Basilisk DLL directory in the isolated retry subprocess without importing Basilisk eagerly. Retain the directory handle across failed imports and retries, and surface early import errors instead of waiting for a misleading initialization timeout.

Validation: 29 related tests passed; all six retry cases passed with simulated Windows DLL-directory preconditions, and a negative control reported the underlying ImportError immediately.
Scale standard-normal samples by the configured noise levels so zero noise
does not violate the distribution precondition. Preserve random-generator
progression and cover noiseless output and repeatability in regression tests.
Apply a supported limb-message planet ID before selecting the radius, retain
the configured target for a zero ID, and reject unsupported IDs. Document
planet selection and add regression coverage for valid and invalid targets.
Build core FSW wrapper objects into one native library and retain lazy imports,
public module identity, and convenience build targets. Isolate colliding C
symbols and leave custom dependency bindings separate. Make this the standard
layout and test imports, callbacks, cleanup, and incremental compilation.
Group core simulation, MuJoCo, and OpenCV bindings into separate native
libraries while preserving optional features and Python imports. Keep Vizard
and unrecognized custom dependencies separate, share the loader, and prepare
SWIG directors for combined linkage. Cover all groups, stale-layout cleanup,
and optional wheel selection with regression tests.
Accept both SWIG director-mutex definition forms without altering director
RTTI or callback behavior. Check the generated syntax and compile real SWIG
wrappers across threading and Python API configurations.
Write a shared inventory of active bindings so cleanup from the previous
group cannot delete the destination group's shim. Cover moves in both orders,
parallel cleanup, retirement, and native CMake reconfiguration. Account for
whole-second Make timestamps in the reconfiguration fixture.
Measure import and collection latency, no-change builds, incremental builds,
and native library sizes. Keep reproducible benchmark tooling and explicitly
label archived comparisons as prototype measurements. Document current usage
and test benchmark command construction and reporting.
Share native fixtures across binding groups and avoid redundant compiler
discovery and source inventory scans. Keep full SWIG API and threading
coverage on the primary generator and representative checks on others.
Mark native build integration tests separately and run them in dedicated
platform CI steps so routine pytestCI runs retain fast runtime regressions.
Register the Basilisk DLL directory in the isolated retry subprocess without importing Basilisk eagerly. Retain the directory handle across failed imports and retries, and surface early import errors instead of waiting for a misleading initialization timeout.

Validation: 29 related tests passed; all six retry cases passed with simulated Windows DLL-directory preconditions, and a negative control reported the underlying ImportError immediately.
Use hasBuildFeature() for MuJoCo and OpenCV guards so installed optional
wheels enable their binding checks and incompatible versions raise errors.
@schaubh
schaubh force-pushed the feature/bsk_startup branch from 13e56b8 to a2c13cb Compare October 9, 2026 14:30
@schaubh
schaubh merged commit 1c89eed into develop Oct 9, 2026
7 checks passed
schaubh added a commit that referenced this pull request Oct 9, 2026
Use a 0.1-second recorder interval for the spacecraft and arm outputs.
Keep the simulation task rate unchanged while reducing plot data volume.
schaubh added a commit that referenced this pull request Oct 9, 2026
Report invalid parent types before computing forces and torques instead of
continuing with uninitialized parent state. Document the validation behavior.
schaubh added a commit that referenced this pull request Oct 9, 2026
Use the state-sized scratch vector for covariance downdates. The previous
measurement-sized buffer could overflow when copying a full state column.
Record the pre-existing defect in the release notes and known issues.
schaubh added a commit that referenced this pull request Oct 9, 2026
Scale standard-normal samples by the configured noise levels so zero noise
does not violate the distribution precondition. Preserve random-generator
progression and cover noiseless output and repeatability in regression tests.
schaubh added a commit that referenced this pull request Oct 9, 2026
Apply a supported limb-message planet ID before selecting the radius, retain
the configured target for a zero ID, and reject unsupported IDs. Document
planet selection and add regression coverage for valid and invalid targets.
schaubh added a commit that referenced this pull request Oct 9, 2026
Initialize scenarioSmallBodyNav with the filter's 12-state vector. Reject
incorrect state, covariance, and noise matrix dimensions during reset and
update, with Python regression tests and module documentation.
@schaubh
schaubh deleted the feature/bsk_startup branch October 9, 2026 15:36
schaubh added a commit that referenced this pull request Oct 9, 2026
Stop marking configure_file outputs as generated build outputs. This avoids
invalid Ninja Multi-Config dependencies and prevents native clean targets
from deleting C message interfaces. Test build, clean, and rebuild behavior.
schaubh added a commit that referenced this pull request Oct 9, 2026
Use a relative logical solution folder instead of an absolute filesystem
path. Extend the C-message build fixture to reject invalid IDE folder names.
schaubh added a commit that referenced this pull request Oct 9, 2026
…builds

Query CMake targets through the File API and normalize fixture paths for
Windows. Build benchmark smoke targets in the active configuration, capture
native warnings through OS pipes, and skip allocation-failure sweeps that
terminate inside noexcept MSVC Debug STL constructors. Retain generator and
warning regression coverage.
schaubh added a commit that referenced this pull request Oct 9, 2026
Allow cold Python and native-library startup before beginning the bounded
thread-lifecycle check. Preserve hang detection with readiness signaling,
traceback diagnostics, captured output, and cleanup of timed-out children.
schaubh added a commit that referenced this pull request Oct 9, 2026
Link separately compiled message wrappers into one native library to reduce
first-import overhead. Preserve existing imports, recorder behavior, and
message build targets through an on-demand loader. Isolate wrapper helper
symbols and verify compatibility, initializer regeneration, and single-message
incremental rebuilds.
schaubh added a commit that referenced this pull request Oct 9, 2026
Generate private import shims and load each extension under Python's import
locking so concurrent imports cannot expose partially initialized bindings.
Track shim outputs in CMake and add concurrent-import regression coverage.
schaubh added a commit that referenced this pull request Oct 9, 2026
Build core FSW wrapper objects into one native library and retain lazy imports,
public module identity, and convenience build targets. Isolate colliding C
symbols and leave custom dependency bindings separate. Make this the standard
layout and test imports, callbacks, cleanup, and incremental compilation.
schaubh added a commit that referenced this pull request Oct 9, 2026
Group core simulation, MuJoCo, and OpenCV bindings into separate native
libraries while preserving optional features and Python imports. Keep Vizard
and unrecognized custom dependencies separate, share the loader, and prepare
SWIG directors for combined linkage. Cover all groups, stale-layout cleanup,
and optional wheel selection with regression tests.
schaubh added a commit that referenced this pull request Oct 9, 2026
Accept both SWIG director-mutex definition forms without altering director
RTTI or callback behavior. Check the generated syntax and compile real SWIG
wrappers across threading and Python API configurations.
schaubh added a commit that referenced this pull request Oct 9, 2026
Write a shared inventory of active bindings so cleanup from the previous
group cannot delete the destination group's shim. Cover moves in both orders,
parallel cleanup, retirement, and native CMake reconfiguration. Account for
whole-second Make timestamps in the reconfiguration fixture.
schaubh added a commit that referenced this pull request Oct 9, 2026
Measure import and collection latency, no-change builds, incremental builds,
and native library sizes. Keep reproducible benchmark tooling and explicitly
label archived comparisons as prototype measurements. Document current usage
and test benchmark command construction and reporting.
schaubh added a commit that referenced this pull request Oct 9, 2026
Share native fixtures across binding groups and avoid redundant compiler
discovery and source inventory scans. Keep full SWIG API and threading
coverage on the primary generator and representative checks on others.
Mark native build integration tests separately and run them in dedicated
platform CI steps so routine pytestCI runs retain fast runtime regressions.
schaubh added a commit that referenced this pull request Oct 9, 2026
Register the Basilisk DLL directory in the isolated retry subprocess without importing Basilisk eagerly. Retain the directory handle across failed imports and retries, and surface early import errors instead of waiting for a misleading initialization timeout.

Validation: 29 related tests passed; all six retry cases passed with simulated Windows DLL-directory preconditions, and a negative control reported the underlying ImportError immediately.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Build system or compilation enhancement documentation Improvements or additions to documentation enhancement New feature or request

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

1 participant