Signed-off-by: Thanaji Rao Thakkalapelli <thanaji.rao.thakkalapelli@intel.com> Co-authored-by: Chendi.Xue <chendi.xue@intel.com>
154 lines
5.7 KiB
Python
154 lines
5.7 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
|
|
import os
|
|
|
|
import torch
|
|
from vllm.config import VllmConfig
|
|
from vllm.config.kernel import IrOpPriorityConfig
|
|
from vllm.logger import init_logger
|
|
from vllm.platforms.xpu import XPUPlatform
|
|
|
|
from vllm_omni.diffusion.attention.backends.registry import DiffusionAttentionBackendEnum
|
|
from vllm_omni.platforms.interface import OmniPlatform, OmniPlatformEnum
|
|
|
|
logger = init_logger(__name__)
|
|
|
|
|
|
# Use the native query; vLLM's XPU custom op reports free=0 in spawned workers.
|
|
torch.accelerator.get_memory_info = lambda device=None: torch.xpu.mem_get_info(device)
|
|
|
|
# The XPU sampler kernel is broken for omni on the current vLLM; use the native path.
|
|
os.environ.setdefault("VLLM_XPU_USE_SAMPLER_KERNEL", "0")
|
|
|
|
|
|
class XPUOmniPlatform(OmniPlatform, XPUPlatform):
|
|
"""XPU/Intel GPU implementation of OmniPlatform.
|
|
|
|
Inherits all XPU-specific implementations from vLLM's XPUPlatform,
|
|
and adds Omni-specific interfaces from OmniPlatform.
|
|
"""
|
|
|
|
_omni_enum = OmniPlatformEnum.XPU
|
|
|
|
@classmethod
|
|
def get_omni_ar_worker_cls(cls) -> str:
|
|
return "vllm_omni.platforms.xpu.worker.xpu_ar_worker.XPUARWorker"
|
|
|
|
@classmethod
|
|
def get_omni_generation_worker_cls(cls) -> str:
|
|
return "vllm_omni.platforms.xpu.worker.xpu_generation_worker.XPUGenerationWorker"
|
|
|
|
@classmethod
|
|
def get_diffusion_attn_backend_cls(
|
|
cls,
|
|
selected_backend: str | None,
|
|
head_size: int,
|
|
allow_trtllm_default: bool = False,
|
|
) -> str:
|
|
# XPU has no TRTLLM backend; arg accepted for signature parity but unused.
|
|
compute_capability = torch.xpu.get_device_capability()
|
|
# Intel Max 1100 and 1550 will not support flash_attn currently
|
|
flash_attn_supported = compute_capability["architecture"] not in [13136561920]
|
|
|
|
if selected_backend is not None:
|
|
backend_upper = selected_backend.upper()
|
|
cls.validate_diffusion_attn_backend(backend_upper)
|
|
if backend_upper in ("FLASH_ATTN_HUB", "FLASH_ATTN_3_HUB"):
|
|
logger.warning(
|
|
"HuggingFace kernels-backed FlashAttention is "
|
|
"not supported on XPU. Falling back to local "
|
|
"FLASH_ATTN."
|
|
)
|
|
backend_upper = "FLASH_ATTN"
|
|
|
|
backend = DiffusionAttentionBackendEnum[backend_upper]
|
|
logger.debug("Using diffusion attention backend '%s'", backend_upper)
|
|
return backend.get_path()
|
|
|
|
if flash_attn_supported:
|
|
logger.debug("Defaulting to diffusion attention backend FLASH_ATTN")
|
|
return DiffusionAttentionBackendEnum.FLASH_ATTN.get_path()
|
|
|
|
logger.debug("Defaulting to diffusion attention backend SDPA")
|
|
return DiffusionAttentionBackendEnum.TORCH_SDPA.get_path()
|
|
|
|
@classmethod
|
|
def supports_torch_inductor(cls) -> bool:
|
|
return True
|
|
|
|
@classmethod
|
|
def get_default_stage_config_path(cls) -> str:
|
|
return "vllm_omni/platforms/xpu/stage_configs"
|
|
|
|
@classmethod
|
|
def get_torch_device(cls, local_rank: int | None = None) -> torch.device:
|
|
if local_rank is None:
|
|
return torch.device("xpu")
|
|
return torch.device("xpu", local_rank)
|
|
|
|
@classmethod
|
|
def get_device_count(cls) -> int:
|
|
return torch.xpu.device_count()
|
|
|
|
@classmethod
|
|
def get_device_version(cls) -> str | None:
|
|
# XPU does not have a version string like CUDA
|
|
return None
|
|
|
|
@classmethod
|
|
def synchronize(cls) -> None:
|
|
torch.xpu.synchronize()
|
|
|
|
@classmethod
|
|
def record_device_event(cls) -> torch.Event | None:
|
|
"""Record an XPU event on the current stream to mark tensor readiness.
|
|
|
|
Deliberately a device-agnostic ``torch.Event`` rather than a
|
|
``torch.xpu.Event``. The consumer (the async diffusion output thread)
|
|
waits with ``torch.Stream.wait_event`` on a generic ``torch.Stream``,
|
|
and that C-level binding silently no-ops for a ``torch.xpu.Event``
|
|
instead of enqueuing the dependency — the side stream then starts its
|
|
D2H copy while the compute stream is still writing the tensor, so the
|
|
host reads a partially-written image (garbage rows at the bottom of the
|
|
output). ``torch.Event`` dispatches through the accelerator hooks and
|
|
the wait is honored, which is the actual fix.
|
|
"""
|
|
try:
|
|
event = torch.Event()
|
|
event.record()
|
|
return event
|
|
except Exception:
|
|
logger.warning("Failed to record XPU device event for cross-stream sync")
|
|
return None
|
|
|
|
@classmethod
|
|
def get_free_memory(cls, device: torch.device | None = None) -> int:
|
|
free, _ = torch.xpu.mem_get_info(device)
|
|
return free
|
|
|
|
@classmethod
|
|
def get_device_memory(cls, device: torch.device | None = None) -> tuple[int, int]:
|
|
free, total = torch.xpu.mem_get_info(device)
|
|
return free, total
|
|
|
|
@classmethod
|
|
def get_profiler_cls(cls) -> str:
|
|
"""Return XPU-specific profiler that handles XPU events."""
|
|
return "vllm_omni.platforms.xpu.profiler.XPUTorchProfilerWrapper"
|
|
|
|
@classmethod
|
|
def get_default_ir_op_priority(cls, vllm_config: VllmConfig) -> IrOpPriorityConfig:
|
|
"""Copied from upstream XPUPlatform with inductor-aware logic.
|
|
|
|
When inductor is active (compiling) use native as the default;
|
|
otherwise prefer vllm_c where available.
|
|
"""
|
|
from vllm.config.compilation import CompilationMode
|
|
|
|
cc = vllm_config.compilation_config
|
|
using_inductor = cc.backend == "inductor" and cc.mode != CompilationMode.NONE
|
|
default = ["native"] if using_inductor else ["vllm_c", "native"]
|
|
|
|
return IrOpPriorityConfig.with_default(default)
|