Skip to content

test(rocm): complete the #1809 matrix rows with Metal M5 traces - #2083

Merged
inureyes merged 6 commits into
mainfrom
update/issue-1809-metal-m5-rows
Sep 30, 2026
Merged

inureyes merged 6 commits into
mainfrom
update/issue-1809-metal-m5-rows

Conversation

@inureyes

@inureyes inureyes commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Part of #1809

Brings in the Apple M5 Max Metal traces for the five checkpoints PR #2059 traced on ROCm (commit 9830bd6 from data/issue-1809-metal-traces, cherry-picked with its authorship) and completes every row of docs/benchmark_results/rocm-correctness-gfx1151-2026-09-30.md against them, Metal as the reference, with the 2026-09-12 criterion (zero mismatches on positions decided at --decided 2.0). It also adds two w1ctx512 rows that cover Metal's fused SSM update kernel (commits d2043c9 and c570666 from the same branch for the Metal half, plus new ROCm traces).

Result

Pair Decided mismatches Verdict
qwen2.5-7b-instruct w1 / w8 / w256 0/19, 0/274, 0/204 pass
gemma-3-4b-it w1 / w8 / w256 / w8ctx1536 0/2, 0/320, 0/204, 0/189 pass
granite-4.0-h-tiny w1 / w8 / w256 0/112, 0/260, 0/208 pass
nemotron-3-nano-30b-a3b w1 0/0 inconclusive (no decided position)
nemotron-3-nano-30b-a3b w8 / w256 0/287, 0/216 pass
qwen2.5-vl-3b-instruct w1 / w8 / w256 0/49, 0/198, 0/154 pass
granite-4.0-h-tiny w1ctx512 0/60 pass
nemotron-3-nano-30b-a3b w1ctx512 0/71 pass

No pair fails. Over the first sixteen pairs top-1 disagrees at 155 of 6720 positions, 0 of 2696 decided; the largest reference gap at a disagreement is 1.250 (Nemotron-H w256, rank 2). The doc also has the logit delta percentiles, perplexity deltas, a 0.5/1.0/2.0 threshold sweep and the rank distribution.

The w1ctx512 rows

The earlier caveat "w1: Metal runs the fused SSM update kernel, ROCm runs the SSD graph" was wrong. The fused step needs seq_len == 1, ssm_kernel_available() and an existing ssm_state, and logit_trace builds fresh caches per chunk, so w1 without prefill runs the graph on both backends: w1 is graph against graph. w1ctx512 (1 128 8 512, MLXCEL_TRACE_START_TOKEN=512) prefills 512 tokens before each single-token forward, so Metal runs ssm_update_kernel (inside fused_mamba2_forward for Nemotron-H) and ROCm runs the SSD graph with state.

Not like-for-like (stated in the doc)

  • The reference is an M5 (generation 17, NAX kernels for multi-token matmul and prefill attention), not the M1 Ultra of the first run, so the two runs' bounds are against different Metal arithmetic.
  • Nemotron-H compares Metal fused_moe_forward with ROCm forward_nonfused at every width.
  • The VLM rows trace the language model only.

Findings for follow-up

  • src/models/nemotron_h.rs prints five loader lines to stdout, so every Nemotron-H trace (both backends) makes compare_logit_traces.py raise ValueError. Those pairs were compared on copies filtered with grep -v '^\[NemotronH\] '; committed traces are unchanged. The # device header line of newer traces is read as metadata and needs no filter.
  • granite w1 perplexity is +4.345% over 128 no-context positions (about 2.5 standard errors per position) with every top-1 in agreement.

Verification

On the gfx1151 host: sha256sum -c SHA256SUMS in all three new or updated trace directories; cargo build --release --features rocm --example logit_trace at 8e65051 and the two w1ctx512 ROCm traces (exit 0, 128 data rows, no NaN), each started with no other process in /sys/class/kfd/kfd/proc; all 18 comparisons run; make verify-versions verify-kernel-dtype-keys verify-kernel-port-dispatch verify-llama-compat verify-rocm-overlay verify-fmt verify-binary-assets pass; cargo test --features rocm --test dead_doc_pointers pass (2 tests).

Not verified: Metal and CUDA are not available on this host. The Metal traces were produced on the M5 Max and are taken on their METADATA.txt, RUNS.txt and checksums. No code on the Metal or CUDA paths changes.

inureyes and others added 2 commits September 30, 2026 19:00
Metal half of the #1809 correctness matrix: 16 default traces (five checkpoints at w1, w8, w256, plus gemma-3-4b-it at w8 behind a 1536-token context) on an Apple M5 Max (GPU gen 17) at d112826, with RUNS.txt, METADATA.txt and SHA256SUMS.
Compare the sixteen ROCm traces from PR #2059 against the Apple M5 Max traces with compare_logit_traces.py --decided 2.0, Metal as the reference, and fill in each row of the 2026-09-30 matrix doc: top-1 disagreement, decided mismatches, largest gap at a disagreement, logit delta percentiles, perplexity delta and verdict. Fifteen pairs pass with zero decided mismatches; nemotron-3-nano-30b-a3b w1 is inconclusive (0 / 0 decided positions). The largest gap at any disagreement is 1.250 (Nemotron-H w256).

The doc states what is not like-for-like: the M5 reference takes NAX kernels where the M1 Ultra of the first run could not, Nemotron-H compares fused_moe_forward with forward_nonfused, and the VLM rows cover the language model only. The expected fused-SSM-kernel against SSD-graph pairing at w1 does not occur, because logit_trace starts every chunk with an empty cache, so no trace reaches that kernel on Metal. The Nemotron-H traces carry five loader lines on stdout that the compare script rejects; those comparisons ran on filtered copies.

The ROCm trace README now points to ../metal_m5_d1128266/.

Part of #1809
@inureyes inureyes added type:test Test related changes priority:medium Medium priority area:inference Generation, sampling, decoding (incl. speculative, DRY) platform:linux Linux (CUDA / packaging) specific status:done Completed labels Sep 30, 2026
inureyes and others added 4 commits September 30, 2026 20:19
The w1 rows run every single-token forward on a fresh cache, so the hybrid SSM models take the SSD graph path and the fused ssm_update_kernel never runs on Metal. Add granite-4.0-h-tiny and nemotron-3-nano-30b-a3b traces at '1 128 8 512' with MLXCEL_TRACE_START_TOKEN=512, which prefill state before each single-token forward and therefore exercise the fused decode kernel.
Retrace the granite-4.0-h-tiny and nemotron-3-nano-30b-a3b w1ctx512 rows at 3c9edea, the commit the ROCm half of these rows is built at, so the pair shares a commit. Data rows are byte-identical to the d112826 traces.
The hybrid w1 rows run graph against graph: logit_trace builds a fresh cache per chunk, so without a prefill no single-token step has SSM state and Metal never takes ssm_update_kernel. The w1ctx512 rows (1 128 8 512 with MLXCEL_TRACE_START_TOKEN=512) prefill before each single-token forward, so Metal runs its fused SSM update and ROCm runs the SSD graph with state.

Adds benchmarks/logit_traces/rocm_gfx1151_3c9edea0/ with the granite-4.0-h-tiny and nemotron-3-nano-30b-a3b traces, built at 3c9edea on gfx1151 (logit_trace sha256 00686315...), and compares them with the Metal M5 traces at the same commit. Both pass at --decided 2.0 and are zero at 0.5 and 1.0: granite 0 / 60 decided mismatches, largest gap 0.125, perplexity 7.090 vs 7.234; nemotron 0 / 71, largest gap 0.250, 7.489 vs 7.489. The correctness doc and the c5fe9a1 README record the commit difference from the other sixteen rows, the ROCm fixes merged in between, and that Apple has no switch to A/B the fused kernel against the graph.

Refs #1809
@inureyes
inureyes merged commit 3c923a8 into main Sep 30, 2026
25 checks passed
@inureyes
inureyes deleted the update/issue-1809-metal-m5-rows branch September 30, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:inference Generation, sampling, decoding (incl. speculative, DRY) platform:linux Linux (CUDA / packaging) specific priority:medium Medium priority status:done Completed type:test Test related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant