Problem / Background
Four deterministic test failures occur on Apple M5 Max that do not occur on the M1 Ultra nightly runner. All four are numeric-agreement assertions on f32 computations. The observed error magnitudes cluster at fp16 epsilon scale (2^-10 = 9.77e-4), roughly three orders of magnitude larger than f32 epsilon, which indicates the f32 inputs are being computed at reduced internal precision on M5-class hardware.
The four failing tests
mlxcel-core layers::tests::chunked_causal_attention_matches_fast_causal at src/lib/mlxcel-core/src/layers.rs:6344. Message: q_len=4 k_len=4 chunk=1 diverged from do_causal SDPA. Measured max_abs_diff = 0.0009678602 against a tolerance of 1e-5. Fails only at chunk=1; chunk 2 and 3 pass.
mlxcel-core layers::tests::chunked_query_attention_matches_unchunked_with_mask at src/lib/mlxcel-core/src/layers.rs:6288. Message: chunk=1 diverged from unchunked SDPA. Measured max_abs_diff = 0.0009678602 against a tolerance of 1e-5. Fails only at chunk=1; chunks 2, 4 and 5 pass.
mlxcel-core mla::decode::decode_tests::absorbed_attention_respects_an_additive_causal_mask at src/lib/mlxcel-core/src/mla/decode_tests.rs:93. Message: masked absorbed attention drifted by 0.0014691837, against F32_TOL = 2e-5 (relative error).
mlxcel-core mla::decode::decode_tests::expand_latent_reproduces_the_up_projection at src/lib/mlxcel-core/src/mla/decode_tests.rs:132. Message: k_nope[0][0][1] 0.30357933044433594 != 0.3037950135765861, absolute tolerance 1e-4, observed absolute error 2.157e-4 (relative error about 7.1e-4).
Why this is a precision problem and not a test problem
- Test 4 compares the GPU result against a reference dot product accumulated in f64 in plain Rust, over
kv_lora_rank = 32 elements (the TINY fixture is num_heads: 4, kv_lora_rank: 32, qk_nope_head_dim: 16, qk_rope_head_dim: 8, v_head_dim: 12). A correctly executed f32 dot product of length 32 on values of order 1 should differ from the f64 reference by about 1e-6 or less. The observed 2.157e-4 is roughly two orders of magnitude larger than that, and sits at fp16 epsilon scale. The reference side is exact, so the GPU side is the imprecise one.
- Tests 1 and 2 both report the identical divergence 0.0009678602, which is just below 2^-10 = 0.0009765625, that is fp16 epsilon. Both fail only in the
chunk=1 configuration, which is the single-query path.
- Test 4 is a plain up-projection matmul, not attention, so the reduced precision is not confined to SDPA kernels.
Hardware dependence, established
- Failing host: Apple M5 Max, macOS 26.6, toolchain 1.93.1 (also reproduced under 1.97.1 with byte-identical values).
- Passing host: the
self-hosted-macos-26-arm64 nightly runner (M1 Ultra). In the last successful nightly-verify.yml run (run id 30939291504) all four tests report ... ok.
- The failures are fully deterministic on M5: three consecutive reruns produced byte-identical values.
- The repository already carries M5-specific routing at
src/lib/mlxcel-core/src/lib.rs:3178, which dispatches to layers::metal4_causal_attention when hw.has_neural_accelerator && hw.macos_supports_na. There is currently no environment variable to disable that path, so the hypothesis could not be isolated by toggling it off. Adding such an override would make this class of problem diagnosable.
Why it matters beyond the test suite
chunk=1 is the single-query shape, which is what every decode step uses in production. If the single-query path on M5 computes at fp16-level precision while the multi-token prefill path computes at f32, then prefill and decode disagree numerically on M5 by about 1e-3 per step. Test 3's failure is on the MLA decode path specifically. This should be assessed for output-quality impact on real checkpoints, not only fixed at the tolerance level.
Suggested investigation
- Determine whether MLX selects a neural-accelerator (NAX) kernel for f32 matmul and single-query SDPA on M5, and whether that kernel accumulates at reduced internal precision.
- Decide whether the reduced precision is intended behavior on M5. If it is, the affected tolerances need per-hardware calibration rather than a blanket loosening, and the divergence must be documented. If it is not, the dispatch needs to select a full-precision kernel for these shapes.
- Measure decode output quality on at least two real checkpoints on M5 versus M1 to establish whether the numeric difference is observable in generated tokens.
- Add an environment override to disable the M5 neural-accelerator routing so this class of divergence can be bisected locally.
Related test-quality gap (fold into the fix)
The assertions in tests 1 and 2 do not print the measured difference; the message says only "diverged". The divergence magnitude had to be obtained by patching the assertion locally. Those two assertions should include the measured value, the way tests 3 and 4 already do.
Not part of this issue
A fifth test, tests/mllama_parity.rs::sub_max_real_tiles_keep_the_legacy_real_rows_byte_identical, also fails on M5 but has a different and benign root cause: it asserts exact f32 bit equality and the observed difference is 5.9604645e-8 (2^-24), which is 0.5 ULP of the output's largest element (1.1521907). That is the same class as issue #939 and is being fixed separately by applying a tolerance, following the precedent set by PR #953 for its sibling test in src/models/mllama/text.rs.
Acceptance Criteria
Technical Considerations
- Affected files:
src/lib/mlxcel-core/src/layers.rs, src/lib/mlxcel-core/src/mla/decode.rs and its tests, src/lib/mlxcel-core/src/lib.rs (M5 routing at line 3178).
- Per the project's Apple Silicon precision rules, M5-specific code paths gate on
hw.has_neural_accelerator && hw.macos_supports_na. Any new override must respect that gate rather than bypassing hardware detection.
- Loosening tolerances alone would hide a real production-path divergence on the decode hot path, so it is not an acceptable standalone fix.
Problem / Background
Four deterministic test failures occur on Apple M5 Max that do not occur on the M1 Ultra nightly runner. All four are numeric-agreement assertions on f32 computations. The observed error magnitudes cluster at fp16 epsilon scale (2^-10 = 9.77e-4), roughly three orders of magnitude larger than f32 epsilon, which indicates the f32 inputs are being computed at reduced internal precision on M5-class hardware.
The four failing tests
mlxcel-corelayers::tests::chunked_causal_attention_matches_fast_causalatsrc/lib/mlxcel-core/src/layers.rs:6344. Message:q_len=4 k_len=4 chunk=1 diverged from do_causal SDPA. Measuredmax_abs_diff= 0.0009678602 against a tolerance of 1e-5. Fails only atchunk=1; chunk 2 and 3 pass.mlxcel-corelayers::tests::chunked_query_attention_matches_unchunked_with_maskatsrc/lib/mlxcel-core/src/layers.rs:6288. Message:chunk=1 diverged from unchunked SDPA. Measuredmax_abs_diff= 0.0009678602 against a tolerance of 1e-5. Fails only atchunk=1; chunks 2, 4 and 5 pass.mlxcel-coremla::decode::decode_tests::absorbed_attention_respects_an_additive_causal_maskatsrc/lib/mlxcel-core/src/mla/decode_tests.rs:93. Message:masked absorbed attention drifted by 0.0014691837, againstF32_TOL = 2e-5(relative error).mlxcel-coremla::decode::decode_tests::expand_latent_reproduces_the_up_projectionatsrc/lib/mlxcel-core/src/mla/decode_tests.rs:132. Message:k_nope[0][0][1] 0.30357933044433594 != 0.3037950135765861, absolute tolerance 1e-4, observed absolute error 2.157e-4 (relative error about 7.1e-4).Why this is a precision problem and not a test problem
kv_lora_rank = 32elements (theTINYfixture isnum_heads: 4, kv_lora_rank: 32, qk_nope_head_dim: 16, qk_rope_head_dim: 8, v_head_dim: 12). A correctly executed f32 dot product of length 32 on values of order 1 should differ from the f64 reference by about 1e-6 or less. The observed 2.157e-4 is roughly two orders of magnitude larger than that, and sits at fp16 epsilon scale. The reference side is exact, so the GPU side is the imprecise one.chunk=1configuration, which is the single-query path.Hardware dependence, established
self-hosted-macos-26-arm64nightly runner (M1 Ultra). In the last successfulnightly-verify.ymlrun (run id 30939291504) all four tests report... ok.src/lib/mlxcel-core/src/lib.rs:3178, which dispatches tolayers::metal4_causal_attentionwhenhw.has_neural_accelerator && hw.macos_supports_na. There is currently no environment variable to disable that path, so the hypothesis could not be isolated by toggling it off. Adding such an override would make this class of problem diagnosable.Why it matters beyond the test suite
chunk=1is the single-query shape, which is what every decode step uses in production. If the single-query path on M5 computes at fp16-level precision while the multi-token prefill path computes at f32, then prefill and decode disagree numerically on M5 by about 1e-3 per step. Test 3's failure is on the MLA decode path specifically. This should be assessed for output-quality impact on real checkpoints, not only fixed at the tolerance level.Suggested investigation
Related test-quality gap (fold into the fix)
The assertions in tests 1 and 2 do not print the measured difference; the message says only "diverged". The divergence magnitude had to be obtained by patching the assertion locally. Those two assertions should include the measured value, the way tests 3 and 4 already do.
Not part of this issue
A fifth test,
tests/mllama_parity.rs::sub_max_real_tiles_keep_the_legacy_real_rows_byte_identical, also fails on M5 but has a different and benign root cause: it asserts exact f32 bit equality and the observed difference is 5.9604645e-8 (2^-24), which is 0.5 ULP of the output's largest element (1.1521907). That is the same class as issue #939 and is being fixed separately by applying a tolerance, following the precedent set by PR #953 for its sibling test insrc/models/mllama/text.rs.Acceptance Criteria
src/lib/mlxcel-core/src/lib.rs:3178, and it is documented.chunked_causal_attention_matches_fast_causalandchunked_query_attention_matches_unchunked_with_maskprint the measured divergence in their failure messages.cargo test --releasepasses on both M5 and the nightly runner.Technical Considerations
src/lib/mlxcel-core/src/layers.rs,src/lib/mlxcel-core/src/mla/decode.rsand its tests,src/lib/mlxcel-core/src/lib.rs(M5 routing at line 3178).hw.has_neural_accelerator && hw.macos_supports_na. Any new override must respect that gate rather than bypassing hardware detection.