Skip to content

[flashinfer] Pass window_left at plan time for the SWA paged prefill wrapper - #31501

Merged
merrymercy merged 1 commit into
sgl-project:mainfrom
luccafong:flashinfer-swa-paged-window-left
Jul 18, 2026
Merged

merrymercy merged 1 commit into
sgl-project:mainfrom
luccafong:flashinfer-swa-paged-window-left

Conversation

@luccafong

@luccafong luccafong commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What

sglang's FlashInfer backend plans the sliding-window paged prefill wrapper without window_left, so flashinfer selects the fa2 module with use_sliding_window=False — the per-element left-window mask is compiled out. The window_left passed later at forward() silently overwrites flashinfer's plan/run consistency check and only drives the coarse per-CTA-tile KV-start skip, so every token past the window attends to stale keys on SWA layers in paged-only prefill mode. On sm100 the plan/run mismatch is worse than the tile-granular leak: outputs are grossly wrong from the first positions, not just past the window.

Paged-only prefill (use_ragged=False) is reached via SGLANG_FLASHINFER_USE_PAGED=1, --enable-deterministic-inference, piecewise CUDA-graph prefill, multimodal models (e.g. Gemma3 VLMs), and multi-item scoring — any SWA model served through one of these paths is affected.

Fix: pass window_left for the SWA paged wrapper at plan time — normal extend only (ragged mode keeps its exact custom prefix mask; spec-verify keeps its pre-existing tree-mask behavior). This also makes flashinfer's plan/run consistency assert genuinely hold.

Verification

New regression test in test/registered/attention/unittests/swa/test_flashinfer.py (test_projected_swa_attention_cases_paged_mode): the existing SWA window-edge cases plus a long no-prefix above-window case (extend 6/8/12, window 4), run under SGLANG_FLASHINFER_USE_PAGED=1 against the exact SDPA sliding-window reference.

cd test/registered/attention/unittests/swa
python test_flashinfer.py -k paged_mode   # regression test only
python test_flashinfer.py                 # full SWA flashinfer suite (7 tests)

Pre-fix check: same commands with the parent commit's flashinfer_backend.py swapped in (git checkout HEAD~1 -- .../flashinfer_backend.py).

pre-fix with fix
paged-mode SWA cases (sm100) FAILED — 30.3% mismatched elements, max abs diff 0.40 (tol 0.03) OK — full test file 7/7

E2E on google/gemma-3-1b-it (sliding_window=512), 1500-token prompt, per-position prompt logprobs vs the triton backend as exact-mask reference (GB300 / sm100):

# server under test (pre-fix vs fixed, otherwise identical):
SGLANG_FLASHINFER_USE_PAGED=1 python -m sglang.launch_server \
  --model-path google/gemma-3-1b-it --attention-backend flashinfer \
  --dtype bfloat16 --context-length 4096 --disable-cuda-graph --random-seed 0
# reference server: same flags, --attention-backend triton, no env flag
# probe: POST /generate with 1500 input_ids, max_new_tokens=64, temperature=0,
#        return_logprob=true, logprob_start_len=0; diff input_token_logprobs per position
comparison inside window (pos <512) past window greedy output
unfixed paged vs triton mean |Δlogp| 2.3, max 17.9 mean 8.6, max 33.3 diverges at token 0
fixed paged vs triton mean 0.045 (cross-backend bf16 noise) mean 0.040 identical

lm-eval on the same setup — gsm8k, 5-shot, limit 200 (GB300 / sm100):

lm_eval --model local-completions \
  --model_args model=google/gemma-3-1b-it,base_url=http://127.0.0.1:30111/v1/completions,num_concurrent=64,tokenized_requests=False \
  --tasks gsm8k --num_fewshot 5 --limit 200 --gen_kwargs max_gen_toks=256 --seed 0
server exact_match (strict)
flashinfer paged, pre-fix 0.130 ± 0.024
flashinfer paged, this PR 0.255 ± 0.031
triton (reference) 0.275 ± 0.032

Original commits

  • e306cd211
  • 23a53115a
  • c81195e62

CI States

Latest PR Test (Base): ✅ Run #29631972224
Latest PR Test (Extra): ❌ Run #29631972120

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@luccafong

Copy link
Copy Markdown
Contributor Author

/tag-and-rerun-ci

@luccafong
luccafong marked this pull request as ready for review July 16, 2026 23:05
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@luccafong

Copy link
Copy Markdown
Contributor Author

/tag-and-rerun-ci

@merrymercy

Copy link
Copy Markdown
Contributor

/tag-and-rerun-ci

…wrapper

Planning the SWA paged prefill wrapper without window_left selects the
fa2 module with use_sliding_window=False, so the per-element window mask
is compiled out; the window_left passed at forward() only drives the
coarse per-tile KV-start skip (and on sm100 the plan/run mismatch breaks
outputs broadly, not just past the window). Pass window_left at plan time
on the paged-only SWA prefill path (normal extend only; ragged keeps its
custom prefix mask, spec-verify keeps its tree-mask behavior), making
flashinfer's plan/run consistency check genuinely hold.

Add paged-mode SWA regression cases (existing window-edge cases plus a
long no-prefix above-window case) that fail without the fix.
@merrymercy
merrymercy force-pushed the flashinfer-swa-paged-window-left branch from d91ca12 to c3c1b52 Compare July 18, 2026 05:16
@merrymercy
merrymercy merged commit 99f5a6f into sgl-project:main Jul 18, 2026
203 of 221 checks passed
@vincentzed

Copy link
Copy Markdown
Contributor

Thank you! We observed this in Olmo3, and similar development variants as well.

Zhylkaaa pushed a commit to Zhylkaaa/sglang that referenced this pull request Jul 29, 2026
jinzhenfan pushed a commit to jinzhenfan/sglang that referenced this pull request Jul 29, 2026
Chronostasys pushed a commit to MindLab-Research/sglang that referenced this pull request Aug 24, 2026
jakki-amd pushed a commit to jakki-amd/sglang that referenced this pull request Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants