Apple GPU C-ABI signature registry + off-device drift guard + bind_or_skip - #403
Conversation
…_skip
The graph audit surfaced ~19 Apple-GPU test files (and 8 production modules)
each hand-writing the ctypes signature at their bind_symbol() call site — 87
distinct C-ABI symbols with signature knowledge scattered across the tree, and
validated ONLY on a real Apple GPU (every such test skips off-device). A
renamed/removed export or a drifted signature was invisible to CI.
Fix 1 — APPLE_ABI registry (single source of truth). `_apple_gpu_dispatch.py`
now carries the canonical {symbol: (argtypes, restype)} for all 87 exports,
plus `bind_registered(symbol)` (bind by name, signature from the registry) and
`expected_symbols()`. Registry was mechanically extracted by AST-parsing every
bind_symbol() call site and verified conflict-free: every production + test-only
symbol resolves to exactly one evaluated ctypes signature (aliases like
runtime.py's `cf = POINTER(c_float)` / `ci = POINTER(c_int64)` resolved per file
— `ci` is int64, not int32, which a naive reader would get wrong).
Fix 2 — test_apple_gpu_abi_registry.py, two guards:
* off-device drift net (runs on ordinary CI, no GPU): AST-scans the tree and
asserts every literal bind_symbol("sym", ...) agrees with APPLE_ABI (symbol
registered + identical evaluated signature, resolving per-file ctypes
aliases). A drifted or unregistered signature now fails immediately instead
of silently skipping. (It already earned its keep: the rebase onto main
pulled in 4 new symbols — optimizer/scatter/sddmm/spmm_csr f32 — and this
guard flagged every one as unregistered.)
* on-device net (skips without the dylib, like the NVIDIA/ROCm symbol tests):
when the runtime loads, every registry symbol must resolve in it — one place
covering the whole ABI, catching a renamed/removed C export.
Fix 3 — bind_or_skip(symbol) test helper (tests/unit/_apple_gpu_abi_testutil.py):
binds by name via the registry, skipping off-device. Migrated the two clean
exemplars (commit_and_wait_timeout, row_major_strides) off inline signatures;
remaining files can adopt incrementally — the drift guard keeps their inline
signatures honest against the registry meanwhile.
Verified off-device: 3 new guard tests pass, on-device net skips; ruff + mypy
clean; full apple suite unchanged vs. base (same pre-existing tessera-opt build-
staleness failures with and without this change). The on-device dylib guard and
the migrated tests need an Apple-silicon run to confirm green — see the PR body.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b5d6b26152
ℹ️ 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".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if sym in txt: | ||
| referenced.add(sym) |
There was a problem hiding this comment.
Exclude the registry from the unused-symbol scan
When a symbol is added only to APPLE_ABI and never bound anywhere else, this test still marks it as referenced because _SCAN_ROOTS includes python/tessera, so _apple_gpu_dispatch.py itself is scanned and the registry definition contains every key as a string. That makes orphaned effectively unable to catch stale or mistyped registry entries; exclude the registry file or count references outside the APPLE_ABI definition.
Useful? React with 👍 / 👎.
…ified_jit prose (#404) Three related pieces of cleanup on top of the Apple GPU C-ABI registry (#403): 1. Reconcile the ABI registry with the runtime (the registry net now PASSES on-device). The registry listed two device-limit probe symbols the runtime never exported, so the strict net (test_dylib_exports_resolve_every_registry _symbol) failed. Add them to apple_gpu_runtime.mm (+ the non-Darwin stub): - tessera_apple_gpu_max_threadgroup_memory_length ([device maxThreadgroupMemoryLength]; 0 = "use static floor") - tessera_apple_gpu_family_integer (raw MTLGPUFamilyApple* value, e.g. Apple7 == 1007; -1 sentinel) Enum values + selectors grounded in the on-machine SDK headers (Decision #27). apple_target.probe_apple_runtime_limits already binds these defensively. 2. Fix 4 pre-existing stale tests (all test-side, not product regressions): - test_apple_gpu_tiny_decode..._kv_cache: diagnostic wording unified to "KV-cache mutation ..." in c53010c; Decision #21 contract still holds. - test_apple_gpu_simple_moe...: tessera.moe gained a native Apple GPU compute lane (_APPLE_GPU_MOE_COMPUTE_OPS) → now metal_runtime; assert that + numerical proof. Renamed to ..._runs_metal_runtime. - test_apple_gpu_multi_op_with_non_gpu_op_stays_metal_artifact: moe is no longer a non-lane op; swap to tessera.flip (+ lane_for self-guard) to keep the conservative-residency-gate guard meaningful. - test_compile_loads_real_metal_package (pk1): c53010c's blanket "compiled"→"device_verified_jit" rename clobbered a repr assertion + docstrings; revert to "compiled". 3. Repo-wide follow-on to (2): c53010c intentionally renamed the *status token* compiled→device_verified_jit but over-reached into English prose. Revert every word-usage back to "compiled" (diagnostic message strings, NVRTC-/ HIPRTC-compiled, emit/* local variable names, docstrings/comments) while preserving all genuine status-token references (quoted "device_verified_jit" values, backtick doc-refs, and status-name prose like `native/ device_verified_jit`, `= device_verified_jit`, `fused (x86) / device_verified_jit (rocm)`). Each reversion git-verified against the pre-c53010c image. Generated dashboards regenerated (new ABI symbols, reworded notes, flip test count); drift gate clean (22 in sync). Apple suite: 2060 passed, 3 skipped. The emit/* variable renames are covered by test_kernel_cache / test_dynamic_shape_emit / test_spectral_candidates / test_tpp_candidates. Retest target: CUDA (sm_120) + ROCm (gfx1151) — this branch touches the nvidia/rocm emit + manifest prose and needs the ROCm-enabled tessera-opt those boxes have (the local Mac build is CPU+Apple only). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
What & why
The graph audit of this repo surfaced that the whole Apple-GPU test suite fans
into one
bind_symbol()symbol-resolver, and on inspection 87 distinct C-ABIsymbols had their ctypes signatures hand-written at each of ~19 test files + 8
production modules — signature knowledge with no single source of truth, and
validated only on a real Apple GPU (every such test
skips off-device). Arenamed/removed C export or a drifted signature was invisible on ordinary CI.
This PR centralizes that surface and adds the CI-runnable guard that was missing.
Fix 1 —
APPLE_ABIregistry (single source of truth)python/tessera/_apple_gpu_dispatch.pynow holds the canonical{symbol: (argtypes, restype)}for all 87 exports, plus:bind_registered(symbol)— bind by name, signature pulled from the registry;expected_symbols()— the full declared ABI set.The registry was mechanically extracted by AST-parsing every
bind_symbol()call site and proven conflict-free (every symbol resolves to exactly one
evaluated ctypes signature). Per-file aliases were resolved — e.g. runtime.py's
cf = POINTER(c_float)andci = POINTER(c_int64)(noteciis int64, easyto get wrong by eye).
Fix 2 —
tests/unit/test_apple_gpu_abi_registry.py, two guardsasserts every literal
bind_symbol("sym", …)agrees withAPPLE_ABI(symbolregistered + identical evaluated signature, resolving per-file ctypes aliases).
A drift or an unregistered symbol now fails immediately instead of silently
skipping. It already earned its keep — rebasing onto
mainpulled in 4 newsymbols (
optimizer/scatter/sddmm/spmm_csrf32) and the guard flaggedevery one.
tests): when the runtime loads, every registry symbol must resolve in it — one
place covering the whole ABI, catching a renamed/removed C export.
Fix 3 —
bind_or_skip(symbol)test helpertests/unit/_apple_gpu_abi_testutil.py— bind by name via the registry, skipoff-device. Migrated the two clean exemplars (
commit_and_wait_timeout,row_major_strides) off inline signatures. The rest can adopt incrementally; thedrift guard keeps their inline signatures honest meanwhile.
Verification done here (Linux/WSL, no Apple GPU)
ruff+mypyclean on the changed module.tests/unit/test_apple*.pysuite: no new failures — identicalpre-existing count with and without this change (those are stale-
tessera-optbuild failures on this box, unrelated to ctypes; confirmed by stashing).
This branch was authored on a Linux/WSL box with no Apple GPU, so everything
gated on the runtime dylib is unproven. On an Apple-silicon Mac:
Then (optional follow-on, same pattern)
Finish Fix 3 by migrating the remaining exercise-and-skip sites to
bind_or_skip("sym")/bind_registered("sym"), one file at a time, runningeach on-device after. Do NOT migrate the presence-assertion tests (e.g.
test_apple_mlpkg_pk2.py, which doesassert fn is not None) or negative tests —bind_or_skipturns a missing symbol into a skip, which would weaken them. Thedrift guard already covers their inline signatures against the registry, so
leaving them is safe.
If the runtime adds/renames a C export, update
APPLE_ABIinpython/tessera/_apple_gpu_dispatch.py— the off-device drift guard will pointat any call site that disagrees.
🤖 Generated with Claude Code