Skip to content

fix(ebsd): BandSimulator uploads take the device lock; wizard tests pin CPU - #125

Merged
CSSFrancis merged 1 commit into
mainfrom
fix/ebsd-mps-lock
Aug 8, 2026
Merged

fix(ebsd): BandSimulator uploads take the device lock; wizard tests pin CPU#125
CSSFrancis merged 1 commit into
mainfrom
fix/ebsd-mps-lock

Conversation

@CSSFrancis

Copy link
Copy Markdown
Owner

Fixes the reproducible macOS-CI crash: three identical Fatal Python error: Aborted (SIGABRT) today (py3.10/3.12/3.13), all at the first test_ebsd_wizard test.

Mechanism: test_ebsd_wizard.py is the only file in the migrated suite that ever resolves MPS (test_ebsd_refine/indexing/crystal_map pin device="cpu" on every call; this file pinned nothing, so default_device() -> mps on the M-series runners). BandSimulator.__init__ uploads the detector geometry to the device with no accelerator_lock, and both callers (simulate_dictionary, refine_orientations) construct it before their per-chunk locks — so it submitted to Metal concurrently with the band-overlay engine's locked matching (whose worker thread stop() never joins, carrying in-flight compute across the test boundary). One unlocked participant re-opens the crash, exactly as the device_lock.py contract documents. This is also a real-app crash path on a Mac wizard rebuild (the old overlay actively matches while the new build's ctor submits). Green on Aug 3 → fatal now is consistent with a macos-latest image roll turning the same corruption from latent into a caught Metal assertion.

Changes:

  • spyde/ebsd/refine.py: the four ctor uploads run under accelerator_lock(device) (null context off MPS; CUDA byte-for-byte unchanged).
  • spyde/tests/migrated/test_device_lock.py: roster additions — simulate_dictionary, the BandSimulator ctor (asserted through the real call chain), refine_orientations.
  • spyde/tests/migrated/test_ebsd_wizard.py: autouse SPYDE_EBSD_DEVICE=cpu (wiring tests, same policy as every sibling and the Windows-CUDA subprocess pattern), overridable for a Mac repro.

Validated on Windows/CPU: test_device_lock.py + test_ebsd_refine.py 37 passed; crash-bracketing wizard tests + TestWiring 6 passed.

Mac confirmation (one command):

SPYDE_EBSD_DEVICE=mps uv run pytest spyde/tests/migrated/test_ebsd_refine.py spyde/tests/migrated/test_ebsd_wizard.py -v -x

Unfixed tree: dies at/after the first TestBuildDictionary test. Fixed tree: runs clean — that flip confirms the locked ctor (not the CPU pin) removed the race.

Deliberately NOT included: joining the overlay engine thread in LiveOverlayEngine.stop() — that changes teardown semantics for every overlay and needs a reproduced bug on a Mac first. If the repro command still aborts at teardown with the ctor locked, a bounded join(timeout=5) is the next candidate.

…in CPU

Three identical macOS-CI SIGABRTs landed at the first test_ebsd_wizard test:
the only file in the suite that ever resolves MPS (every sibling pins cpu),
and BandSimulator.__init__ uploaded the detector geometry OUTSIDE
accelerator_lock — constructed by simulate_dictionary and refine_orientations
BEFORE their per-chunk locks, so it submitted to Metal concurrent with the
band-overlay engine's locked matching. One unlocked participant re-opens the
crash, exactly as the device_lock contract documents; also a real-app crash
on a Mac wizard rebuild (old overlay matches while the new build's ctor
submits).

Roster tests pin simulate_dictionary, the ctor and refine_orientations so the
next unlocked call site fails on every platform. test_ebsd_wizard gets an
autouse SPYDE_EBSD_DEVICE=cpu pin (wiring tests; accelerator work under
pytest belongs in a subprocess) with an env escape hatch for a Mac repro:
SPYDE_EBSD_DEVICE=mps uv run pytest spyde/tests/migrated/test_ebsd_refine.py spyde/tests/migrated/test_ebsd_wizard.py -v -x
@CSSFrancis
CSSFrancis marked this pull request as ready for review August 8, 2026 00:57
@CSSFrancis
CSSFrancis merged commit f0b08f3 into main Aug 8, 2026
23 of 24 checks passed
GHzytp pushed a commit to GHzytp/spyde that referenced this pull request Aug 9, 2026
…t, fold duplicate builds

- the two fixture time.sleep(0.8)s (ebsd_session / lazy_session) become
  conftest._settle -- the comment ('let the selector debounce timers fire')
  is literally _settle's use case.
- test_eager_data_still_gets_a_bounded_chunking rendered two 64x64-nav
  scans (~9 s) to feed pure bytes/shape math; a 16x16 grid proves the same
  three properties, with the budget shrunk to 1 MiB so both row counts stay
  bytes-derived rather than ny-clamped.
- merges (assertion union, same _build + payload): PC-adoption +
  caret-announce ride test_builds_a_wizard_with_a_resident_dictionary; the
  ebsd_match stream assert rides the band-draw call that produces it;
  hide/show rides the different-position overlay flow; the two-grain colour
  check rides test_indexes_the_scan_into_an_ipf_window's identical run.

Kept minimal around the file top / device handling (PR CSSFrancis#125 touches those
regions).  File now 22.8 s locally.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant