DFLASH support added for XPU (#32798)

Co-authored-by: Ma Mingfei <mingfei.ma@intel.com>
This commit is contained in:
ANSHUMAN TRIPATHY
2026-09-11 10:39:37 +08:00
committed by GitHub
co-authored by Ma Mingfei
parent 690428b470
commit 0fadad8933
7 changed files with 192 additions and 19 deletions
+1
View File
@@ -111,6 +111,7 @@ DRAFT_ATTENTION_BACKEND_CHOICES = [
"triton",
"ascend",
"trtllm_mha",
"intel_xpu",
]
DETERMINISTIC_ATTENTION_BACKEND_CHOICES = [
@@ -5,6 +5,7 @@ import logging
import os
from typing import TYPE_CHECKING, Optional
from sglang.srt.arg_groups.choices import DRAFT_ATTENTION_BACKEND_CHOICES
from sglang.srt.arg_groups.overrides import (
_speculative_moe_runner_default,
attention_backends_of,
@@ -198,9 +199,11 @@ def handle_speculative_decoding(server_args: ServerArgs) -> None:
def _handle_dflash(server_args: ServerArgs) -> None:
cfg = resolving_view(server_args)
if not (cfg.device.startswith("cuda") or cfg.device == "npu"):
if not (
cfg.device.startswith("cuda") or cfg.device == "npu" or cfg.device == "xpu"
):
raise ValueError(
"DFLASH speculative decoding only supports CUDA and NPU devices."
"DFLASH speculative decoding only supports CUDA, NPU and XPU devices."
)
if resolved_view(server_args).enable_dp_attention:
@@ -722,16 +725,11 @@ def _resolve_dflash_draft_attention_backend(server_args: ServerArgs) -> None:
"""
cfg = resolving_view(server_args)
supported_draft_backends = (
"flashinfer",
"fa3",
"fa4",
"triton",
"trtllm_mha",
"ascend",
supported_draft_backends = DRAFT_ATTENTION_BACKEND_CHOICES
# FlashInfer is CUDA-only; fall back to triton on XPU and ROCm.
fallback_backend = (
"triton" if (get_platform().is_xpu or get_platform().is_hip) else "flashinfer"
)
# Use triton on ROCm (no FlashInfer), flashinfer on CUDA.
fallback_backend = "triton" if get_platform().is_hip else "flashinfer"
draft_backend = cfg.speculative_draft_attention_backend
if draft_backend is None:
@@ -12,6 +12,7 @@ from sglang.srt.layers.attention.flashattention_backend import (
merge_state_v2_wrapper,
prepare_swa_spec_page_table_triton,
)
from sglang.srt.layers.radix_attention import AttentionType
from sglang.srt.mem_cache.memory_pool import KVWriteLoc
from sglang.srt.mem_cache.swa_memory_pool import SWAKVPool
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, ForwardMode
@@ -553,7 +554,13 @@ class XPUAttentionBackend(AttentionBackend):
# q = q.to(self.kv_cache_dtype)
# q_rope = q_rope.to(self.kv_cache_dtype) if q_rope is not None else None
# k_rope = k_rope.to(self.kv_cache_dtype) if k_rope is not None else None
causal = not layer.is_cross_attention
# Mirror FlashAttentionBackend: ENCODER_ONLY / bidirectional layers
# (DFLASH draft full_attention) are non-causal, not just cross-attention.
causal = not (
layer.is_cross_attention
or layer.attn_type
in (AttentionType.ENCODER_ONLY, AttentionType.DECODER_BIDIRECTIONAL)
)
# Check if we should use local attention
use_local_attn = (
@@ -974,7 +981,13 @@ class XPUAttentionBackend(AttentionBackend):
if layer.sliding_window_size is not None and layer.sliding_window_size > -1
else (-1, -1)
)
causal = not layer.is_cross_attention
# Mirror FlashAttentionBackend: ENCODER_ONLY / bidirectional layers
# (DFLASH draft full_attention) are non-causal, not just cross-attention.
causal = not (
layer.is_cross_attention
or layer.attn_type
in (AttentionType.ENCODER_ONLY, AttentionType.DECODER_BIDIRECTIONAL)
)
# For fa3 interface version compatibility, we put new fields into conditional keyword args
kwargs = {}
@@ -36,6 +36,7 @@ _DFLASH_VERIFY_SKIP_CUSTOM_MASK_BACKENDS = frozenset(
"TritonAttnBackend",
"TRTLLMHAAttnBackend",
"TRTLLMMLABackend",
"XPUAttentionBackend",
}
)
@@ -82,7 +82,7 @@ from sglang.srt.speculative.spec_utils import (
assign_req_to_token_pool_func,
build_grammar_vocab_mask,
)
from sglang.srt.utils import is_cuda, is_hip, is_npu
from sglang.srt.utils import is_cuda, is_hip, is_npu, is_xpu
_is_npu = is_npu()
@@ -503,12 +503,12 @@ class DFlashWorkerV2(BaseSpecWorker):
self._draft_greedy_rank_index_buf: Optional[torch.Tensor] = None
self._draft_greedy_selected_ids_buf: Optional[torch.Tensor] = None
self._draft_greedy_index_cap: int = 0
self._use_fused_kv_materialize = is_cuda() or is_hip()
self._use_fused_kv_materialize = is_cuda() or is_hip() or is_xpu()
self._fused_kv_helper: Optional[object] = None
if self._use_fused_kv_materialize:
self._init_fused_kv_helper()
supports_gpu_triton = is_cuda() or is_hip()
supports_gpu_triton = is_cuda() or is_hip() or is_xpu()
self._use_triton_prepare_block = supports_gpu_triton
self._use_triton_accept_bonus = supports_gpu_triton
# The legacy compact-rebuild path host-syncs twice per step (masked
@@ -9,7 +9,7 @@ import torch
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
from sglang.srt.managers.tp_worker import TpModelWorker
from sglang.srt.model_executor.forward_batch_info import CaptureHiddenMode
from sglang.srt.runtime_context import attention_backends, get_spec
from sglang.srt.runtime_context import attention_backends, get_platform, get_spec
from sglang.srt.server_args import DRAFT_ATTENTION_BACKEND_CHOICES, ServerArgs
from sglang.srt.speculative.dflash_info import DFlashVerifyInput
from sglang.srt.speculative.dflash_info_v2 import DFlashDraftInputV2
@@ -36,13 +36,17 @@ def _resolve_draft_attention_backend_fallback(*, algo_label: str) -> str:
otherwise the process's prefill backend. Both are resolution's answers, so
they come from the bags.
"""
# FlashInfer is CUDA-only; fall back to triton on XPU and ROCm.
platform_fallback = (
"triton" if (get_platform().is_xpu or torch.version.hip) else "flashinfer"
)
draft_backend = get_spec().speculative_draft_attention_backend
if draft_backend is None:
draft_backend, _ = attention_backends()
if draft_backend is None:
return "triton" if torch.version.hip else "flashinfer"
return platform_fallback
if draft_backend not in DRAFT_ATTENTION_BACKEND_CHOICES:
fallback = "triton" if torch.version.hip else "flashinfer"
fallback = platform_fallback
logger.warning(
"%s draft worker only supports attention_backend in %s for now, "
"but got %r. Falling back to '%s'.",