Skip to content

feat(npu): switch Ascend KDA extend to fused chunk_kda_fwd - #30

Merged
zhaozx-cn merged 2 commits into
a5-k3-0828from
add_chunk_kda_fwd
Sep 7, 2026
Merged

zhaozx-cn merged 2 commits into
a5-k3-0828from
add_chunk_kda_fwd

Conversation

@sherdavincl9

@sherdavincl9 sherdavincl9 commented Sep 7, 2026 •

Copy link
Copy Markdown
Collaborator

Replace the multi-kernel Ascend KDA extend path (chunk_local_cumsum, chunk_kda_scaled_dot_kkt_fwd, solve_tril_npu, recompute_w_u_fwd_npu, chunk_gated_delta_rule_fwd_h_npu, chunk_gla_fwd_o_gk_npu) with a single torch.ops.npu.chunk_kda_fwd call.

The fused op takes one initial state per logical sequence in contiguous [N, H, V, K] layout, while SGLang owns a slot-indexed persistent pool, so the wrapper gathers the active slots before the call and scatters final_state back afterwards. chunk_states comes back in the layout the tracker already expects, which drops the transpose on the intermediate-state path.

Forward metadata uses -1 in cache_indices for a padded request. The gather would turn that into a read of the last cache slot, and index_copy_ would then write the padded row's final_state back over that same slot, corrupting the state of whichever live sequence owned it. Clamp the gather indices to 0 so a padded row reads a harmless placeholder, and filter padded rows out of the writeback entirely.

Drop the speculative-decoding-only NPU transpose of temporal_state in MambaPool. It presented the pool as a transposed view so the stride-aware verify kernel and state movers saw the canonical [pool, HV, V, K] logical shape; the fused extend path consumes the pool directly in that layout, so every consumer now agrees on one contiguous representation. The adjacent shape comment described the swapped layout and is corrected with it.

Also rewrite the conv_states copy for non-tracked entries as a no-op self-copy, so it no longer runs bool-mask indexing (aten::nonzero) or a host numel check on every step.

Motivation

Modifications

Accuracy Tests

Speed Tests and Profiling

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 #34102103992
Latest PR Test (Extra): ❌ Run #34102103633
Latest PR Test (AMD ROCm 7.2): ❌ Run #34102103904

Replace the multi-kernel Ascend KDA extend path (chunk_local_cumsum,
chunk_kda_scaled_dot_kkt_fwd, solve_tril_npu, recompute_w_u_fwd_npu,
chunk_gated_delta_rule_fwd_h_npu, chunk_gla_fwd_o_gk_npu) with a single
torch.ops.npu.chunk_kda_fwd call.

The fused op takes one initial state per logical sequence in contiguous
[N, H, V, K] layout, while SGLang owns a slot-indexed persistent pool, so
the wrapper gathers the active slots before the call and scatters
final_state back afterwards. chunk_states comes back in the layout the
tracker already expects, which drops the transpose on the
intermediate-state path.

Forward metadata uses -1 in cache_indices for a padded request. The gather
would turn that into a read of the last cache slot, and index_copy_ would
then write the padded row's final_state back over that same slot,
corrupting the state of whichever live sequence owned it. Clamp the gather
indices to 0 so a padded row reads a harmless placeholder, and filter
padded rows out of the writeback entirely.

Drop the speculative-decoding-only NPU transpose of temporal_state in
MambaPool. It presented the pool as a transposed view so the stride-aware
verify kernel and state movers saw the canonical [pool, HV, V, K] logical
shape; the fused extend path consumes the pool directly in that layout, so
every consumer now agrees on one contiguous representation. The adjacent
shape comment described the swapped layout and is corrected with it.

Also rewrite the conv_states copy for non-tracked entries as a no-op
self-copy, so it no longer runs bool-mask indexing (aten::nonzero) or a
host numel check on every step.
Copilot AI lite review requested due to automatic review settings September 7, 2026 08:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new fused-op wrapper unconditionally indexes outputs[10] even when intermediate output is disabled, which can crash or behave inconsistently depending on the op’s return signature.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR updates the Ascend (NPU) KDA “extend” path to use a fused torch.ops.npu.chunk_kda_fwd operator instead of a multi-kernel decomposition, and aligns state layouts/handling around that change (including safer padded-row handling and removal of a speculative-only temporal-state transpose).

Changes:

  • Replace the Ascend KDA extend decomposition with a single fused torch.ops.npu.chunk_kda_fwd call, including gather/scatter between SGLang’s slot-indexed pool and the op’s per-sequence initial/final state.
  • Remove the speculative-only NPU transpose of temporal_state in the Mamba pool and update the documented intermediate-state shape accordingly.
  • Adjust K3 shared-experts attention-TP comm eligibility and refine speculative conv-state copy behavior for non-tracked entries.
File summaries
File Description
python/sglang/srt/models/kimi_k3.py Tweaks the condition enabling shared-experts attention-TP communication.
python/sglang/srt/mem_cache/memory_pool.py Removes NPU-only speculative temporal-state transpose; updates intermediate-state shape comment.
python/sglang/srt/hardware_backend/npu/attention/ascend_kda_backend.py Switches Ascend KDA extend to fused chunk_kda_fwd; gathers/scatters state; adjusts intermediate-state return and conv-state handling.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +97 to +102
use_gate_in_kernel=False,
state_v_first=True,
output_h=return_intermediate_states,
)
del query_key, new_values
out, final_state, chunk_states = outputs[0], outputs[1], outputs[10]
valid_positions = valid_state_mask.nonzero(as_tuple=False).flatten()
Comment on lines +599 to 603
# No-op self-copy for non-tracked entries so we never run
# bool-mask indexing (aten::nonzero) or a host numel check.
track_mask = mamba_steps_to_track >= 0
src_slots = torch.where(
track_mask, dst_indices_tensor, mamba_track_indices
@zhaozx-cn
zhaozx-cn merged commit 6b712e9 into a5-k3-0828 Sep 7, 2026
79 of 89 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants