Commit 0c9db70
Phase M4: matmul closeout -- sync tax measured + documented, offset-0 semantics verified, honest docs
Task 1 (per-call sync overhead): measured and decomposed, NOT optimized away --
torch exposes no safe handle to its MPS queue/stream, so the private-queue +
sync design stays, now with the cost precisely documented (MPS_STATUS.md 11.3).
- BNB_MPS_PROFILE=1 now decomposes each native matmul call into sched (commit
-> GPU start), gpu (kernel), and done (GPU end -> wait return), on the
mach_absolute_time timebase GPUStartTime uses. Steady-state fp16: the fixed
tax is ~0.15ms/call (~0.02 encode + ~0.07 sched + ~0.07 done); the pre-call
torch.mps.synchronize() itself is ~1us on an idle queue. That tax is ~52% of
a 4096x4096 gemv call and ~10% of an M=512 gemm.
- Queue sharing rejected with evidence: torch 2.12.1 exposes no stream handle
from Python; libtorch's at::mps::getCurrentMPSStream()/MPSStream internals
are reachable only via dlsym'd C++ mangled symbols + header-derived ivar
offsets (commandQueue()/queue() are inline, commit()/flush() private, encodes
must run on torch's private _serialQueue) -- an unguardable ABI trap. Sharing
only the queue would not even remove the pre-sync (command buffers execute in
commit order; torch batches into an uncommitted buffer). Future directions
(libtorch-linked extension, torch.mps.compile_shader) recorded with their
costs in 11.3.
- New test_sync_discipline_interleave_stress pins the discipline: dependent
torch writes interleaved with native matmuls on the same buffers, parity
every iteration. Verified to have teeth: fails 30/30 with the pre-sync
no-op'd, passes 100% with it.
Task 2 (offset-0 input copy): verified on this build, clone stays.
- A view's data_ptr() IS base + storage_offset*itemsize (raw arithmetic);
objc-probing such an interior pointer SIGSEGVs uncatchably, so casting it
would be silent corruption or a crash -- the clone in _ensure_native_buffer
is load-bearing.
- Better than NEXT_MATMUL_PLAN 5 feared: untyped_storage().data_ptr() DOES
recover the base MTLBuffer (passes the contract check), so offset binding is
possible; not implemented because steady-state matmul inputs are offset-0
(the clone ~never fires) and it would touch every ABI entry point for no
measured benefit. Recipe recorded in 11.4; semantics pinned by
test_view_data_ptr_is_base_plus_offset.
Task 3 (docs):
- MPS_STATUS.md: M2/M3 short notes consolidated into a proper 11 (fused gemv,
native gemm, the M4 sync/offset findings); op matrix rows for gemv/gemm
updated to native; header records the M4 harness result (328 passed + the
known unrelated lion strict-xfail XPASS).
- docs/apple_silicon/README.md: gemv_4bit -> native (fused, 3.4-6.2x);
gemm_4bit -> native for fp16/fp32 with the honest caveats (bf16 falls back --
MPSMatrixMultiplication has no bf16 on macOS 26.4.1; large-M ~ parity with
F.linear); Known limitations rewritten around the real remaining costs.
- README.md accelerator table, mps QLoRA 4-bit: 🐢 -> ✅ with a footnote.
Justification: "slow implementation" is no longer accurate (inference gemv is
fused native Metal at 3.4-6.2x; gemm is native fp16/fp32), but a bare ✅
would overclaim, so the footnote carries the bf16-fallback and large-M-parity
caveats inline in the README.
- "mis-cast" -> "miscast" (typos hook); _typos.toml learns the mach
timebase field `numer` so the hook stops rewriting it to `number`.
Parity gate: BNB_MPS_REQUIRE_NATIVE=1 pytest tests/test_mps_parity.py ->
328 passed; the only failure is the pre-existing, unrelated lion strict-xfail
XPASS that fails identically on clean HEAD (separate optimizer track).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent bdd3d9e commit 0c9db70
7 files changed
Lines changed: 323 additions & 92 deletions
File tree
- csrc
- docs/apple_silicon
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
182 | 182 | | |
183 | 183 | | |
184 | 184 | | |
185 | | - | |
| 185 | + | |
186 | 186 | | |
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
190 | 190 | | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
191 | 197 | | |
192 | 198 | | |
193 | 199 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
133 | 134 | | |
134 | 135 | | |
135 | 136 | | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
136 | 148 | | |
137 | 149 | | |
138 | 150 | | |
| |||
264 | 276 | | |
265 | 277 | | |
266 | 278 | | |
267 | | - | |
268 | | - | |
269 | 279 | | |
270 | | - | |
271 | | - | |
272 | | - | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
273 | 286 | | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
274 | 290 | | |
| 291 | + | |
| 292 | + | |
275 | 293 | | |
276 | | - | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
277 | 299 | | |
278 | 300 | | |
279 | 301 | | |
| |||
427 | 449 | | |
428 | 450 | | |
429 | 451 | | |
| 452 | + | |
| 453 | + | |
430 | 454 | | |
431 | 455 | | |
432 | | - | |
433 | | - | |
434 | 456 | | |
| 457 | + | |
| 458 | + | |
435 | 459 | | |
| 460 | + | |
436 | 461 | | |
437 | | - | |
438 | | - | |
| 462 | + | |
| 463 | + | |
439 | 464 | | |
440 | 465 | | |
441 | 466 | | |
| |||
0 commit comments