Skip to content

perf(qwen3.6): fuse decode kernel launches — shared-expert + GDN conv/L2-norm#239

Open
minion1227 wants to merge 2 commits into
gittensor-ai-lab:mainfrom
minion1227:minion_shared_expert_fusion
Open

perf(qwen3.6): fuse decode kernel launches — shared-expert + GDN conv/L2-norm#239
minion1227 wants to merge 2 commits into
gittensor-ai-lab:mainfrom
minion1227:minion_shared_expert_fusion

Conversation

@minion1227

@minion1227 minion1227 commented Jul 5, 2026

Copy link
Copy Markdown

Summary

Reduce decode kernel-launch count on the Qwen3.6 path with two bit-identical kernel fusions (decode here is CUDA-graph / launch-bound, so per-layer launches cost real time):

  1. Shared expert — fuse gate + up GEMVs and the SwiGLU into one one-warp-per-row kernel (hn staged once, both dot-products in one pass): 3 launches → 1 per layer (40 layers). down stays a separate GEMV.
  2. GDN linear-attn layers (30 of 40) — fuse conv_split + the two per-head l2_norm_heads kernels into one block-per-head kernel (causal conv + SiLU, then the q/k L2-norm reduced in-block): 3 launches → 1 per GDN layer.

Both are bit-identical to main (same arithmetic and reduction order; projection/SiLU values rounded to bf16 exactly as the unfused paths do), so the accuracy gate is trivial. Both are no-ops for Qwen3-30B (no shared expert, no GDN layers) → the guard cannot regress. Only kernels/ + runtime/; touches no crowded/attempted file.

Proof of speedup

  • Tested on RTX 5090 (sm_120)

Decode tok/s (end-to-end, Qwen3.6-35B-A3B-UD-Q4_K_M, n=256, ctx=0, bs=1):

decode tok/s
before (main, cc356a5) 171.31
after (this PR) 176.37

+2.95% decode on the Qwen3.6 primary model.

# sparkinfer decode bench (qwen3_gguf_bench <model> 256 0), RTX 5090 sm_120, idle GPU, 3 runs each:
before (main):  171.27  171.32  171.33   -> 171.31 tok/s
after  (PR):    176.37  176.37  176.37   -> 176.37 tok/s
delta: +2.95%

# correctness gate (qwen3_gguf_score, this PR vs main, same input):
# per-token argmax + top-k logprobs bit-identical -> 100% top-1, KL = 0

@minion1227 minion1227 changed the title perf(qwen3.6): fuse shared-expert gate+up+SwiGLU into one kernel perf(qwen3.6): fuse decode kernel launches — shared-expert + GDN conv/L2-norm Jul 5, 2026
@ai-hpc ai-hpc added area:kernels subsystem (emission weight 0.42) area:runtime subsystem (emission weight 0.26) test-on-5090 Maintainer-approved to evaluate on RTX 5090 (greenlight) eval:REJECT sparkinfer auto-eval verdict: REJECT 4k-context UI-only: strongest measured context in sparkinfer eval regression-128 sparkinfer eval regression marker for this context regression-512 sparkinfer eval regression marker for this context regression-4k sparkinfer eval regression marker for this context labels Jul 6, 2026
@ai-hpc

ai-hpc commented Jul 6, 2026

Copy link
Copy Markdown
Member
(wrong baseline — re-run)

@ai-hpc

ai-hpc commented Jul 6, 2026

Copy link
Copy Markdown
Member

Auto-closed by sparkinfer eval: no single context cleared the 2% improvement gate and at least one context regressed.

@ai-hpc ai-hpc closed this Jul 6, 2026
ai-hpc added a commit that referenced this pull request Jul 6, 2026
inference2026 pushed a commit to inference2026/sparkinfer that referenced this pull request Jul 6, 2026
- Qwen3-MoE frontier: 493.56 (unchanged, verified)
- Qwen3.6 frontier: 261.30 (both gittensor-ai-lab#230 + gittensor-ai-lab#229 merged, measured on RTX 5090)
- Qwen3.6 journey: baseline(23) -> gittensor-ai-lab#230(171) -> gittensor-ai-lab#229(261)
- Qwen3.6 status: 261/258/244 tok/s (128/512/4k), ~95% of llama.cpp
- PR table: gittensor-ai-lab#234 updated to REJECT (was stale XL), added gittensor-ai-lab#237/gittensor-ai-lab#239/gittensor-ai-lab#241/gittensor-ai-lab#243
inference2026 pushed a commit to inference2026/sparkinfer that referenced this pull request Jul 6, 2026
…lab#239/gittensor-ai-lab#241/gittensor-ai-lab#243

Each PR has a real bot eval comment with the full verdict table.
Link to the PR comment as proof (runs were killed before log site POST).
@ai-hpc ai-hpc reopened this Jul 6, 2026
@ai-hpc

ai-hpc commented Jul 6, 2026

Copy link
Copy Markdown
Member

🔄 Evaluation was run against a wrong baseline — re-evaluating

The bot's same-box baseline measurement had two bugs during your PR's evaluation run:

  1. The box was checked out to a stale PR branch (not origin/main), inflating the baseline to ~232-260 tok/s instead of the actual main speed (~172 tok/s without GDN_FAST, ~225 tok/s with it).
  2. The Gated-DeltaNet fast kernel (merged in feat(qwen36): add optimized Gated-DeltaNet AR state update kernel wit… #229) was opt-in via SPARKINFER_GDN_FAST=1 env var — the eval bot never set it, so both main and PRs were measured on the slow path.

The correct Qwen3.6 main baseline (with GDN_FAST=1) is now:

context correct main baseline
128-token 225.24 tok/s
512-context 222.86 tok/s
4k-context 212.42 tok/s

Your PR will be re-evaluated against this correct same-box main baseline once you rebase onto main. No code change needed on your side — the bot just needs a clean slate to measure against.

Apologies for the confusion — this was an eval pipeline error, not an issue with your submission.

@minion1227

Copy link
Copy Markdown
Author

Rebased onto main (2a2ebde) as requested — ready for re-evaluation against the corrected same-box baseline (225.24 / 222.86 / 212.42, with GDN_FAST=1). No code changes; the two fusions are unchanged and bit-identical to the unfused paths (100% top-1, KL=0). Thanks for catching the eval-pipeline issue and re-running.

@ai-hpc ai-hpc added eval:XS sparkinfer auto-eval verdict: XS 512-context UI-only: strongest measured context in sparkinfer eval and removed eval:REJECT sparkinfer auto-eval verdict: REJECT 4k-context UI-only: strongest measured context in sparkinfer eval regression-512 sparkinfer eval regression marker for this context regression-4k sparkinfer eval regression marker for this context regression-128 sparkinfer eval regression marker for this context labels Jul 6, 2026
@ai-hpc ai-hpc added the needs-rebase Verified speedup but not the round winner — rebase after merge-first lands label Jul 6, 2026
@minion1227 minion1227 force-pushed the minion_shared_expert_fusion branch from 2a2ebde to a711cd5 Compare July 6, 2026 09:18
ai-hpc added a commit that referenced this pull request Jul 6, 2026
#241 -> L (was stale REJECT), #243 -> S, #239 -> XS, #240 -> XS.
All from the first fair evaluation run with GDN_FAST=1 default.
@ai-hpc ai-hpc added eval:L sparkinfer auto-eval verdict: L 128-context UI-only: strongest measured context in sparkinfer eval re-evaluate Winner merged — rebase onto main; bot re-evaluates on push and removed eval:XS sparkinfer auto-eval verdict: XS 512-context UI-only: strongest measured context in sparkinfer eval needs-rebase Verified speedup but not the round winner — rebase after merge-first lands labels Jul 6, 2026
@ai-hpc

ai-hpc commented Jul 6, 2026

Copy link
Copy Markdown
Member

✅ sparkinfer auto-eval — a711cd5

metric value
label eval:L
scored decode (128 ctx · 128-context · Qwen3.6) 259.09 tok/s
vs same-box main 225.24 tok/s → +15.0% (+33.9)
correctness (Qwen3.6 vs llama.cpp) top-1 95.9% · KL 0.0207
Qwen3.6 128-token no-regression gate 259.09 tok/s vs main 225.24 tok/s · pass
Qwen3.6 512-context no-regression gate 256.08 tok/s vs main 222.86 tok/s · pass
Qwen3.6 4k-context no-regression gate 242.49 tok/s vs main 212.42 tok/s · pass
Qwen3-30B-A3B guard — accuracy top-1 96.9% · KL 0.0177 · pass
Qwen3-30B-A3B guard — 128-token 498.15 tok/s · pass
Qwen3-30B-A3B guard — 512-context 473.08 tok/s · pass
Qwen3-30B-A3B guard — 4k-context 395.62 tok/s · pass
Qwen3-30B-A3B guard — 16k-context 331.83 tok/s · pass
Qwen3-30B-A3B guard — 32k-context 262.0 tok/s · pass

Verified speedup over same-box origin/main — 259.09 tok/s (main was 225.24 tok/s).

RTX 5090 (sm_120) · 128/512/4k/16k/32k guarded · scored vs same-box main · strongest context scores · built from source · correctness vs llama.cpp. Automated — not merged; merge manually after review.

@ai-hpc ai-hpc added needs-rebase Verified speedup but not the round winner — rebase after merge-first lands and removed re-evaluate Winner merged — rebase onto main; bot re-evaluates on push labels Jul 6, 2026
@ai-hpc

ai-hpc commented Jul 6, 2026

Copy link
Copy Markdown
Member

The round's merge-first PR was just merged. Please rebase this branch onto main — the bot re-evaluates it on push (crediting your marginal gain on top of what merged).

@ai-hpc ai-hpc removed eval:L sparkinfer auto-eval verdict: L 128-context UI-only: strongest measured context in sparkinfer eval labels Jul 6, 2026
ai-hpc added a commit that referenced this pull request Jul 6, 2026
Qwen3.6 per-context: 276.26/272.93/257.73 (128/512/4k).
#239 PR row: label=L -> XS (correct run24 verdict).
minion1227 and others added 2 commits July 6, 2026 04:11
The Qwen3.6 shared expert ran four kernels per layer (gate GEMV, up GEMV,
SwiGLU, down GEMV). Decode is CUDA-graph/launch-bound, so those extra
launches cost real time: measured on an RTX 5090, removing the shared
expert entirely is +8.4% decode, ~70% of which is per-kernel overhead
rather than weight bandwidth.

This fuses the gate+up projections and the SwiGLU into a single
one-warp-per-row kernel — hn is staged into shared memory once and both
dot-products are computed in one pass — cutting three launches to one per
layer (down stays a separate GEMV). The per-lane reduction order matches
launch_gemv, and the projections are rounded to bf16 before SwiGLU exactly
as the unfused path does (sh_gate/sh_up are stored bf16), so the output is
bit-identical.

Qwen3.6-35B-A3B decode, RTX 5090 (sm_120): 171.3 -> 174.8 tok/s (+2.05%).
Correctness: 100% top-1 agreement, KL = 0 vs the prior build (bit-identical).
No-op for Qwen3-30B, which has no shared expert, so the guard cannot regress.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 30 GDN linear-attention layers ran conv_split + two l2_norm_heads
kernels per layer (3 launches; the two L2-norms were tiny 16-block kernels
serial on the GDN critical path). Fuse all three into one block-per-head
kernel — causal conv + SiLU per lane, then the per-head L2-norm of q/k
reduced in-block — and drop the two superseded kernels. Bit-identical:
same conv arithmetic and per-lane conv_state shift, and the L2 reduction
sees the same bf16-rounded SiLU values in the same warp/shared order.

Combined with the shared-expert fusion in this PR, Qwen3.6-35B-A3B decode
goes 171.3 -> 176.4 tok/s (+2.95%) on RTX 5090 (sm_120). Correctness:
100% top-1 agreement, KL=0 vs main (bit-identical). No-op for Qwen3-30B.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@minion1227 minion1227 force-pushed the minion_shared_expert_fusion branch from a711cd5 to 8868b7c Compare July 6, 2026 11:11
@ai-hpc ai-hpc added eval:M sparkinfer auto-eval verdict: M 128-context UI-only: strongest measured context in sparkinfer eval re-evaluate Winner merged — rebase onto main; bot re-evaluates on push and removed needs-rebase Verified speedup but not the round winner — rebase after merge-first lands labels Jul 6, 2026
@ai-hpc

ai-hpc commented Jul 6, 2026

Copy link
Copy Markdown
Member

✅ sparkinfer auto-eval — 8868b7c

metric value
label eval:M
scored decode (128 ctx · 128-context · Qwen3.6) 277.98 tok/s
vs same-box main 254.72 tok/s → +9.1% (+23.3)
correctness (Qwen3.6 vs llama.cpp) top-1 98.2% · KL 0.0154
Qwen3.6 128-token no-regression gate 277.98 tok/s vs main 254.72 tok/s · pass
Qwen3.6 512-context no-regression gate 274.03 tok/s vs main 251.87 tok/s · pass
Qwen3.6 4k-context no-regression gate 258.85 tok/s vs main 239.0 tok/s · pass
Qwen3-30B-A3B guard — accuracy top-1 96.5% · KL 0.015 · pass
Qwen3-30B-A3B guard — 128-token 481.38 tok/s · pass
Qwen3-30B-A3B guard — 512-context 458.09 tok/s · pass
Qwen3-30B-A3B guard — 4k-context 385.21 tok/s · pass
Qwen3-30B-A3B guard — 16k-context 326.97 tok/s · pass
Qwen3-30B-A3B guard — 32k-context 254.61 tok/s · pass

Verified speedup over same-box origin/main — 277.98 tok/s (main was 254.72 tok/s).

RTX 5090 (sm_120) · 128/512/4k/16k/32k guarded · scored vs same-box main · strongest context scores · built from source · correctness vs llama.cpp. Automated — not merged; merge manually after review.

ai-hpc added a commit that referenced this pull request Jul 6, 2026
@ai-hpc ai-hpc added needs-rebase Verified speedup but not the round winner — rebase after merge-first lands and removed re-evaluate Winner merged — rebase onto main; bot re-evaluates on push labels Jul 6, 2026
@ai-hpc

ai-hpc commented Jul 6, 2026

Copy link
Copy Markdown
Member

The round's merge-first PR was just merged. Please rebase this branch onto main — the bot re-evaluates it on push (crediting your marginal gain on top of what merged).

@ai-hpc

ai-hpc commented Jul 6, 2026

Copy link
Copy Markdown
Member

The round's merge-first PR was just merged. Please rebase this branch onto main — once you push the rebase the bot re-evaluates it against the new frontier (crediting your marginal gain on top of what merged).

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

Labels

128-context UI-only: strongest measured context in sparkinfer eval area:kernels subsystem (emission weight 0.42) area:runtime subsystem (emission weight 0.26) eval:M sparkinfer auto-eval verdict: M needs-rebase Verified speedup but not the round winner — rebase after merge-first lands test-on-5090 Maintainer-approved to evaluate on RTX 5090 (greenlight)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants