Skip to content

[Feat] gdn: Add --enable-linear-lossless-verify for bit-exact tuple replay in spec verify - #42388

Open
hsthe29 wants to merge 12 commits into
sgl-project:mainfrom
hsthe29:lossless-gdn-tuple-verify
Open

hsthe29 wants to merge 12 commits into
sgl-project:mainfrom
hsthe29:lossless-gdn-tuple-verify

Conversation

@hsthe29

@hsthe29 hsthe29 commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

How it works today. On hybrid GDN models (Qwen3.5 / 3.6 / 3.8, Qwen3-Next), speculative target-verify runs the recurrent kernel with disable_state_update=True and writes a full [HV, V, K] SSM snapshot for every draft position into intermediate_ssm. After acceptance, scatter_mamba_states_after_mtp_verify copies two snapshots back into the persistent pool: the last accepted position, and, with the extra_buffer radix strategy, the position that crossed a mamba-track boundary. Every linear-chain algorithm goes through this path: EAGLE/MTP, DFLASH and DSPARK.

The problem. That buffer is large, and it grows with the draft width. On Qwen3.6-35B-A3B one snapshot is 60 MiB (30 GDN layers × 32 heads × 128 × 128 × fp32), so each request needs 60 MiB × D. _handle_max_mamba_cache reserves this for every request slot before the KV pool is sized, so all of it comes out of KV capacity:

setup (1× H100) intermediate_ssm
Qwen3.6-35B-A3B-FP8, MTP D=4, 25 requests 6.09 GB
Qwen3.6-35B-A3B-FP8, DFLASH block 16, 8 requests 8.44 GB
Qwen3.8-27B-FP8, DFlash2 / DSpark D=8, 8 requests 10.12 GB

In the first setup the KV pool ends up at 498,880 tokens. That is not enough for 25 concurrent 26k-token requests, so 7 of them sit in the queue.

--enable-linear-replayssm-spec already gets rid of these snapshots, but it changes how verify is computed: a frozen checkpoint plus a compact ring, a causal-masked window, and compensated materialization. Its results are therefore not bit-identical to the default verify. On Qwen3.6-35B-A3B with MTP (measured on v0.5.21), greedy outputs diverged from the default path after 23–143 tokens on 8 of 8 prompts. Many deployments can live with that. Some cannot: evals, A/B rollouts and regression testing all need the outputs to match the default path exactly.

The idea. Each recurrent step is

h_t = exp(g_t) * h_{t-1} + k_t ⊗ u_t,    u_t = beta_t * (v_t - (exp(g_t) * h_{t-1})^T k_t)

The verify kernel already computes u_t, the l2-normalized k_t and g_t. And h_0 is still in the pool, because verify does not update state. So instead of keeping every h_t, we can keep (u_t, k_t, g_t) and rebuild the accepted h_t at commit time. That costs HV * (V + K + 1) floats per step instead of HV * V * K, which is 63.8× less at K = V = 128.

The rebuild has to round exactly the way the verify kernel does. Inside the kernel the decayed state h * exp(g) is used twice, by the delta reduction and by the update. So the compiler keeps it as a separately rounded multiply and folds the update into a single FMA: fma(k, u, round(h * exp(g))). The replay writes out the same two instructions. A naive replay written as one expression lets the compiler contract a different multiply and drifts by 1–2 ULP. The tests include that case, to show they would catch it.

Modifications

Everything sits behind a new flag, --enable-linear-lossless-verify, off by default. With the flag off, no code path and no memory reservation changes.

Verify kernel (fused_sigmoid_gating_recurrent.py, gdn_triton.py)

  • New optional u_states_buffer / k_states_buffer / g_states_buffer arguments and a CACHE_U_TUPLES constexpr. For each draft step, the kernel stores u (after the beta scaling), the l2-normalized k, and g, at the row given by intermediate_state_indices. k and g do not depend on the V tile, so only the i_v == 0 program writes them.
  • The per-request pitch comes from the buffer shape, so it stays correct under --speculative-adaptive.
  • The tuple path picks the same launch config as the dense verify (target_verify=True, which includes the SM90 BV=4 tile). Verify outputs are therefore identical by construction, not just in testing.

Verify call site (gdn_backend.py)

  • When the pool has a tuple ring, the ring is passed to the kernel instead of intermediate_ssm.
  • A one-time check that the dispatcher picked the Triton verify kernel. The FlashInfer verify kernel accepts **kwargs: it would silently ignore the buffers, and the commit would replay zeros.
  • An assert that no tree metadata (retrieve_parent_token) reaches the tuple path.

Commit (hybrid_linear_attn_backend.py, mamba_state_scatter_triton.py)

  • _recon_kernel replays all GDN layers of a batch in one launch, starting from ssm_states[slot] and stopping at the accepted step.
    • On CUDA, the rounding is pinned with mul.rn.f32 / fma.rn.f32 inline PTX.
    • PTX does not exist on ROCm: the AMDGPU backend rejects the f register constraint. HIP builds instead use a plain multiply feeding tl.fma, which the compiler cannot contract.
    • Both forms are bit-exact against verify.
  • Rows with a negative step, or an out-of-range slot or row index, are skipped. This is the same validity rule fused_mamba_state_scatter_with_mask uses.
  • Order matters. The mamba-track replay runs before the in-place replay of the accepted state, because both must start from the pre-verify state. If the in-place replay runs first, the track replay starts from the already-advanced state and stores a wrong prefix-cache state. This bug does not show up in throughput benchmarks. It shows up as the second turn of a conversation diverging from the default path; the server-level test below covers it.
  • Conv windows still go through the existing scatter. scatter_mamba_states_after_mtp_verify gets a skip_ssm argument, so the SSM half is left to the replay.
  • PP spec stable rows (SGLANG_ENABLE_PP_SPEC) work: the replay reads the same rows verify wrote to (src_indices_raw).

Pool and memory accounting (memory_pool.py, kv_cache_configurator.py, disaggregation/decode.py, unified_memory_pool.py)

  • MambaPool.SpeculativeState gets intermediate_ssm_u / _k / _g, shaped [layers, spec_slots + 1, D, HV, V | K | -]. In this mode intermediate_ssm is None.
  • The ring is always fp32, whatever --mamba-ssm-dtype is, so bf16 state pools stay exact too.
  • The ring is excluded from state transfer, like the other spec-only buffers.
  • spec_intermediate_bytes_per_req computes the scratch size from the same shapes MambaPool allocates: the tuple ring plus the deduplicated conv window.
  • With the flag on, _handle_max_mamba_cache reserves exactly that in all three sizing branches, including the joint solve for max_mamba_cache_size. The freed memory becomes KV cache instead of an idle reservation. With the flag off, the existing formula is used unchanged.
  • The flag is plumbed through HybridReqToTokenPool and the PD decode pool. The unified memory pool rejects it.

Gating (attention_hook.py, pipeline.py)

The replay walks one linear chain, so the flag requires --speculative-eagle-topk 1. This is enforced in three places:

  • At startup: validate_linear_lossless_verify runs right after handle_speculative_decoding. It cannot live in handle_linear_attn_backend, because that runs earlier, before DFLASH and DSPARK pin topk to 1.
    • Accepted: EAGLE/MTP with topk 1, DFLASH, DSPARK.
    • Rejected with a clear message: tree EAGLE (topk > 1), NGRAM, no speculative decoding, either ReplaySSM flag, a non-Triton verify backend, --enable-unified-memory, and any SGLANG_RAGGED_VERIFY_MODE other than static.
  • In the pool: MambaPool rejects topk ≠ 1 and KDA layers, and the KV cache configurator rejects non-GDN models.
  • At runtime: forward_extend asserts that no tree metadata reaches the tuple path.

Tests: test/registered/attention/unittests/gdn/test_gdn_lossless_verify.py, registered for CUDA and AMD CI. Details below.

Not changed: the default verify path, KDA, tree verify, and ReplaySSM.

Accuracy Tests

Unit tests (test_gdn_lossless_verify.py, 8 tests). They drive the real MambaPool, the real verify kernel and the real commit entry point (HybridLinearAttnBackend.update_mamba_state_after_mtp_verify), and require torch.equal against the snapshot verify for:

  • verify outputs, every SSM slot, every conv slot and every mamba-track slot, for D ∈ {2, 3, 4, 8, 16} and heads (16, 32) and (4, 16);
  • a bf16 state pool;
  • PP stable request rows;
  • out-of-range rows, which must be left untouched;
  • the PTX and portable replay forms (CUDA);
  • the scratch-size helper against the real allocation, byte for byte;
  • rejection of tree verify;
  • a control: replaying the accepted state before the track state gives a wrong track state, so the ordering above is actually exercised.

On H100 these 8 pass, and so do the existing GDN tests: test_triton.py, test_gdn_replayssm_spec_fold.py, test_fused_verify_triton_gdn.py, test_gdn_noncontiguous_stride.py.

Server-level, greedy. Stock main (d75d5b3) against this branch with --enable-linear-lossless-verify, same flags otherwise (--max-running-requests 8 --max-mamba-cache-size 40 --kv-cache-dtype bf16 --page-size 64), 1× H100. Each workload runs twice per server, with a cache flush in between, so the server's own run-to-run determinism is measured too:

  • single: 8 prompts, one at a time, 300 tokens each.
  • multi-turn: turn 1 decodes 700 tokens, crossing the 256 and 512 mamba-track boundaries. Turn 2 is turn 1 plus a follow-up, so its prefill resumes from the state tracked during turn-1 decode (cached_tokens = 512). This is the workload that catches a wrong track state.
  • batched: the 8 prompts in one request, so the batch composition is fixed.
speculative setup single multi-turn (turn 1 · turn 2) batched
EAGLE/MTP 3/1/4, Qwen3.6-35B-A3B-FP8 8/8 4/4 · 4/4 8/8
DFLASH, Qwen3.6-35B-A3B-FP8 + z-lab/Qwen3.6-35B-A3B-DFlash (D=16) 8/8 4/4 · 4/4 8/8
DFLASH with a DFlash2 draft, Qwen3.8-27B-FP8 + z-lab/Qwen3.8-27B-DFlash2 (D=8) 8/8 4/4 · 4/4 8/8
DSPARK, Qwen3.8-27B-FP8 + RadixArk/Qwen3.8-27B-DSpark (D=8) 8/8 4/4 · 4/4 8/8

Every cell matched stock on both runs. When the same 8 prompts are fired from 8 threads instead, outputs occasionally differ in 2 of 8. Stock differs from itself in exactly the same way between runs, because arrival order changes how requests are batched; it is not specific to this change.

ROCm. The same kernels and commit logic, backported to v0.5.21 and run on an MI325X (gfx942, ROCm 7.15, Triton 3.8):

  • A standalone harness passed 144 of 144 exact checks with the portable replay.
  • Server-level, with --enable-deterministic-inference --attention-backend triton and SGLANG_USE_AITER=0, all four workloads matched stock on both runs.
  • With the default aiter backends, stock itself is not reproducible from run to run (even bs=1 greedy differs), so that configuration cannot be compared. Accept length was the same (2.852 vs 2.850).
  • gfx950: test_gdn_lossless_verify.py passes at this PR's head on an MI350X (gfx950, ROCm 10, Triton 3.8). Every check is bit-exact for one request and for a batch, which run gfx950's own verify tiles (BV=8 / 4 warps and BV=16 / 2 warps). Server-level runs on gfx950 are not done yet.

Speed Tests and Profiling

End to end. Qwen3.6-35B-A3B-FP8, MTP 3/1/4, 1× H100, with --mem-fraction-static 0.8 --kv-cache-dtype bf16 --page-size 64 --max-running-requests 25 --max-mamba-cache-size 150 --enable-hierarchical-cache. bench_serving on the random dataset, 25 requests × (26k in / 2k out), concurrency 25:

verify scratch max_total_num_tokens max running duration output tok/s accept length
main 6.09 GB 498,880 18 36.75 s 1,360.6 3.51
this PR, flag on 0.10 GB 788,224 (+58%) 24 33.03 s 1,513.7 (+11%) 3.45

Accept length is within run-to-run noise: it ranged from 3.45 to 3.51 across repeated runs of both configurations. That is expected, since the outputs are bit-identical.

Memory with other algorithms (8 requests, 40 mamba slots, so the absolute numbers are not comparable with the table above):

setup verify scratch max_total_num_tokens
MTP, Qwen3.6-35B-A3B-FP8 (D=4) 2.11 → 0.03 GB 1,007,680 → 1,107,776 (+10%)
DFLASH, Qwen3.6-35B-A3B-FP8 (D=16) 8.44 → 0.13 GB 390,208 → 591,040 (+51%)
DFlash2, Qwen3.8-27B-FP8 (D=8) 10.12 → 0.16 GB 176,640 → 302,464 (+71%)
DSpark, Qwen3.8-27B-FP8 (D=8) 10.12 → 0.16 GB 178,944 → 304,832 (+70%)

Per-step kernel cost. Microbenchmark on the Qwen3.6-35B-A3B GDN geometry (30 layers, 16/32 heads, 128 × 128), H100, CUDA events, about 25% of rows crossing a track boundary. The verify kernel gets cheaper, because it writes HV * (V + K + 1) instead of HV * V * K floats per step. The replay is cheaper than the scatter at D=4 and costs a little more at D=8 and D=16, where it walks a longer chain. Net, every configuration is faster per verify step:

requests × draft tokens verify, per GDN layer commit, 30 layers net per verify step
25 × 4 99.7 → 53.9 µs 1868 → 1489 µs −1.75 ms
8 × 4 41.0 → 41.8 µs 605 → 413 µs −0.17 ms
8 × 8 64.9 → 42.0 µs 527 → 548 µs −0.67 ms
8 × 16 120.9 → 60.3 µs 470 → 690 µs −1.60 ms

Checklist

Review and Merge Process

  1. Ping Merge Oncalls to start the process. See the PR Merge Process.
  2. Get approvals from CODEOWNERS and other reviewers.
  3. Trigger CI tests with comments or contact authorized users to do so.
    • Common commands include /tag-and-rerun-ci, /tag-run-ci-label, /rerun-failed-ci
  4. After green CI and required approvals, ask Merge Oncalls or people with Write permission to merge the PR.

CI States

Latest PR Test (Base): ⏳ Run #42155370412
Latest PR Test (Extra): ❌ Run #42155370523
Latest PR Test (AMD ROCm 10): ⏳ Run #42155370457

Tip

Base CI only covers the core cases, and its workload may not exercise your change. Use /rerun-test to run the tests your change touches, or copy this prompt for an agent:

Find the registered tests this PR affects and run them with /rerun-test, following https://github.com/sgl-project/sglang/blob/main/.agents/skills/rerun-test/SKILL.md

… spec verify

Speculative target-verify on GDN layers keeps one full [HV, V, K] SSM
snapshot per draft token so the commit can pick the accepted one. This adds
an opt-in mode that keeps each draft step's (u, k, g) tuple instead
(HV * (V + K + 1) floats per step, ~64x smaller at K = V = 128) and replays
the accepted prefix at commit with the verify kernel's exact rounding, so the
committed state and every output stay bit-identical to the snapshot verify.
The KV budget reserves the tuple ring's real size, so the freed memory becomes
KV cache instead of sitting idle.

- verify kernel: optional (u, k, g) stores; tiles exactly like the dense verify
- commit: _recon_kernel replay (inline-PTX rounding on CUDA, explicit fma on
  ROCm); the mamba-track replay runs before the in-place accepted-state replay
  so both start from the pre-verify state
- pool: fp32 tuple ring replaces intermediate_ssm; conv windows unchanged
- gating: --speculative-eagle-topk 1 (EAGLE/MTP, DFLASH, DSPARK), Triton
  verify kernel, GDN models; validated after the speculative hook and
  asserted again in the pool and at verify time
- tests: test_gdn_lossless_verify.py checks exact equality against the
  snapshot verify (fp32/bf16 pools, PP stable rows, track ordering, bounds,
  PTX vs portable replay)
@hsthe29

hsthe29 commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

Hi @hnyls2002 @yizhang2077 @Qiaolin-Yu and others, could one of you trigger CI on this PR when you have a moment?

It adds an opt-in --enable-linear-lossless-verify for GDN speculative verify: per-draft (u, k, g) tuples replace the full SSM snapshots, outputs stay bit-identical to the default verify, and the freed memory goes to the KV cache (+58% tokens on Qwen3.6-35B-A3B with MTP). I tested it on H100 with MTP, DFLASH (incl. a DFlash2 draft) and DSPARK, and the ROCm path on an MI325X; details are in the description. Thanks!

@hsthe29

hsthe29 commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Hi @hnyls2002 @yizhang2077 @Qiaolin-Yu, @ShangmingCai, @HaiShaw, @BBuf and others, could one of you trigger CI on this PR when you have a moment?

It adds an opt-in --enable-linear-lossless-verify for GDN speculative verify: per-draft (u, k, g) tuples replace the full SSM snapshots, outputs stay bit-identical to the default verify, and the freed memory goes to the KV cache (+58% tokens on Qwen3.6-35B-A3B with MTP). I tested it on H100 with MTP, DFLASH (incl. a DFlash2 draft) and DSPARK, and the ROCm path on an MI325X; details are in the description. Thanks!

- kv_cache_configurator: charge the default verify scratch from
  stage_per_req, so a fused draft's widened state entry is still priced
  (main switched the budget to it in sgl-project#43326).
- kv_cache_configurator: reject --enable-linear-lossless-verify when
  building the unified pools; the guard lived in
  UnifiedHybridReqToTokenPool, which main removed.
- test: import the verify kernel from ops/attention/linear and stub the
  commit hook's state_pool and layer_router.
- ruff format the moved verify kernel.
@github-actions

This comment has been minimized.

@BBuf BBuf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address the [P1] items, then re-ping.

Agent-assisted pre-review, findings verified against 24b47a2ce7ac.

intermediate_state_indices=intermediate_state_indices,
cache_steps=cache_steps,
retrieve_parent_token=retrieve_parent_token,
u_states_buffer=u_states_buffer,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] These keywords are passed even when lossless verify is disabled. On XPU this function is rebound to the platform wrapper, which accepts neither these arguments nor **kwargs, so ordinary GDN speculative verification now raises TypeError. Preserve the flag-off signature and gate tuple forwarding on backend support.

)
decode = cfg.linear_attn_decode_backend or cfg.linear_attn_backend
verify = cfg.linear_attn_verify_backend
if verify not in (None, "triton") or (verify is None and decode == "flashinfer"):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Checking the backend name does not exclude Ascend: this configuration passes validation, but the registry selects the Ascend verify and commit implementations. The pool removes intermediate_ssm while the Ascend commit still consumes it and accesses its shape, so the first commit fails. Reject unsupported platforms before allocating the tuple-only pool.

Preserve the flag-off XPU verify signature and reject lossless verification on unsupported platforms.
@BBuf

BBuf commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

@hsthe29 I pushed d1097b76 to your branch: Preserve the flag-off XPU verify signature and reject lossless verification on unsupported platforms.
Please pull before your next push. The review runs again on the new head.

Automated pre-review for 24b47a2ce7ac; it re-checks when the PR is updated.

@github-actions

This comment has been minimized.

@BBuf BBuf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address the [P1] items, then re-ping.

Agent-assisted pre-review, findings verified against d1097b76955e.

from sglang.test.test_utils import CustomTestCase

register_cuda_ci(est_time=40, stage="base-b", runner_config="1-gpu-large")
register_amd_ci(est_time=60, suite="stage-b-test-1-gpu-large-amd")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] This AMD lane defaults to MI300, so the (4, 16) case never reaches the gfx950-specific verify tiling. The flag admits MI35x, but the description says gfx950 is untested and the ROCm evidence comes from a v0.5.21 backport. Please register/run these parity checks on MI35x at this head, covering both N=1 and N>1, or gate that architecture out until validated.

@BBuf

BBuf commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

/tag-and-rerun-ci

@BBuf

BBuf commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

/rerun-test test/registered/attention/unittests/gdn/test_gdn_lossless_verify.py

Targeted validation for d1097b76955e.

@github-actions github-actions Bot added the run-ci CI: run the baseline test suite on this PR label Oct 31, 2026
@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

🚀 1-gpu-h100 (1 test): ✅ View workflow run

cd test/ && python3 registered/attention/unittests/gdn/test_gdn_lossless_verify.py

@hsthe29 hsthe29 changed the title [GDN] Add --enable-linear-lossless-verify: bit-exact tuple replay for spec verify [Feat] gdn: Add --enable-linear-lossless-verify for bit-exact tuple replay in spec verify Oct 31, 2026
@hsthe29

hsthe29 commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

@BBuf Thanks for the review, and for pushing d1097b7 to preserve the flag-off XPU verify signature and reject unsupported platforms.

I've renamed the PR to follow the title convention.

For the remaining P1 (running the parity checks on MI35x at this head, covering both N=1 and N>1), I don't have access to the MI35x machine over the weekend, so I'll pick it up on Monday. Sorry for the wait, and thanks for your patience.

@BBuf

BBuf commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

/rerun-failed-ci

2 similar comments
@BBuf

BBuf commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

/rerun-failed-ci

@BBuf

BBuf commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

/rerun-failed-ci

Keep the lossless (u, k, g) arguments next to main's new ring_indices and
replayssm_request_ring. Take main's rewritten _init_unified_pools without
the unified-memory guard: validate_linear_lossless_verify already rejects
--enable-unified-memory, and the guard broke test_unified_tri_pool, whose
mocked mamba args do not carry the flag.
…nal slot

Add the flag's row to server_arguments.mdx, and append the field to
POSITIONAL_FIELD_ORDER instead of inserting it next to the ReplaySSM
flags, so existing positional ServerArgs calls keep their slots.
…and a batch

gfx950 picks its own verify tiles for the (4, 16) heads: (BV=8, 4 warps)
for one request and (BV=16, 2 warps) for a batch. Register the test on the
MI35x suite and add a single-request sweep, since every other case runs a
batch of five.
@mintlify

mintlify Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Preview approval required

This pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit 413bdb6.

Approve preview

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Nov 6, 2026
@hsthe29

hsthe29 commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

@BBuf Pushed 413bdb6:

  • Merged main and fixed the three base-a-test-cpu failures: documented --enable-linear-lossless-verify in server_arguments.mdx, appended the field to POSITIONAL_FIELD_ORDER instead of inserting it mid-list, and dropped the unified-memory guard in _init_unified_pools (validate_linear_lossless_verify already rejects --enable-unified-memory, and the guard broke test_unified_tri_pool's mocked args).
  • MI35x: test_gdn_lossless_verify.py is now registered on stage-b-test-1-gpu-small-amd-mi35x, with a new single-request sweep. On an MI350X (gfx950, ROCm 10, Triton 3.8) at this head, the (4, 16) heads run gfx950's own tiles, (BV=8, 4 warps) for N=1 and (BV=16, 2 warps) for N=5. All 9 tests pass (the PTX check is skipped as CUDA-only), and every check is bit-exact (torch.equal) against the snapshot verify.

Could you take another look?

@BBuf

BBuf commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

[BBuf Review Agent] @hsthe29 The docs, positional-order and unified-pool fixes are in place, and the MI35x tests cover both gfx950 tile configurations. I’m fine with the reported parity results at this head.

@BBuf

BBuf commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

/rerun-test test/registered/kernels/ops/attention/test_fused_verify_triton_gdn.py

@github-actions

github-actions Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

🚀 1-gpu-h100 (1 test): ⏳ View workflow run

cd test/ && python3 registered/kernels/ops/attention/test_fused_verify_triton_gdn.py  # base-b-kernel-unit

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation jit-kernel memory-pool run-ci CI: run the baseline test suite on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants