[XPU] Remove redundant xpu graph backend and make xpu graph opt-in by default (#29911)
This commit is contained in:
@@ -103,12 +103,23 @@ class XpuPlatform(Platform):
|
||||
if empty_cache:
|
||||
torch.xpu.empty_cache()
|
||||
|
||||
used_memory = float(torch.xpu.memory_allocated(device_id))
|
||||
total_gpu_memory = float(
|
||||
torch.xpu.get_device_properties(device_id).total_memory
|
||||
)
|
||||
|
||||
free_gpu_memory = max(0.0, total_gpu_memory - used_memory)
|
||||
# Use mem_get_info() with a sanity cap to avoid KV-cache over-allocation
|
||||
# on drivers that incorrectly return total memory as free memory.
|
||||
# Consistent with the fallback: free = max(0, total - allocated).
|
||||
try:
|
||||
free_gpu_memory, total_gpu_memory = torch.xpu.mem_get_info(device_id)
|
||||
used_memory = float(torch.xpu.memory_allocated(device_id))
|
||||
free_gpu_memory = min(
|
||||
float(free_gpu_memory),
|
||||
max(0.0, float(total_gpu_memory) - used_memory),
|
||||
)
|
||||
except Exception:
|
||||
# Fallback for devices/drivers that do not support querying free memory
|
||||
used_memory = float(torch.xpu.memory_allocated(device_id))
|
||||
total_gpu_memory = float(
|
||||
torch.xpu.get_device_properties(device_id).total_memory
|
||||
)
|
||||
free_gpu_memory = max(0.0, total_gpu_memory - used_memory)
|
||||
|
||||
if distributed:
|
||||
import torch.distributed as dist
|
||||
|
||||
@@ -22,7 +22,6 @@ import torch
|
||||
from torch.profiler import ProfilerActivity, profile
|
||||
|
||||
from sglang.srt.model_executor.runner import DecodeCudaGraphRunner
|
||||
from sglang.srt.speculative.spec_info import SpeculativeAlgorithm
|
||||
from sglang.srt.utils import register_xpu_device_properties_for_dynamo
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -144,9 +143,6 @@ class XPUGraphRunner(DecodeCudaGraphRunner):
|
||||
assert (
|
||||
not self.require_gathered_buffer
|
||||
), "XPUGraphRunner does not support gathered buffer yet."
|
||||
assert (
|
||||
model_runner.spec_algorithm == SpeculativeAlgorithm.NONE
|
||||
), "XPUGraphRunner does not support speculative inference yet."
|
||||
|
||||
def _init_profile_context_and_memory_record(self):
|
||||
profile_context = profile(
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
# Copyright 2023-2026 SGLang Team
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
"""XPUCudaGraphBackend — Intel XPU full-graph capture (torch.xpu.XPUGraph)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import contextmanager
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional
|
||||
|
||||
import torch
|
||||
|
||||
from sglang.srt.model_executor.runner_backend.base_cuda_graph_backend import (
|
||||
BaseCudaGraphBackend,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
|
||||
from sglang.srt.model_executor.runner.base_cuda_graph_runner import (
|
||||
BaseCudaGraphRunner,
|
||||
)
|
||||
|
||||
|
||||
class XPUCudaGraphBackend(BaseCudaGraphBackend):
|
||||
"""One torch.xpu.XPUGraph per shape; attention metadata is
|
||||
captured inside the graph.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
cuda_graph_runner: BaseCudaGraphRunner,
|
||||
) -> None:
|
||||
self._graphs: Dict[Any, torch.xpu.XPUGraph] = {}
|
||||
self._outputs: Dict[Any, Any] = {}
|
||||
self._pool = None
|
||||
self._device_module = cuda_graph_runner.device_module
|
||||
self._tp_group = cuda_graph_runner.model_runner.tp_group
|
||||
self._capture_stream: Optional[torch.xpu.Stream] = None
|
||||
|
||||
@contextmanager
|
||||
def capture_session(self, stream: torch.xpu.Stream):
|
||||
if self._pool is None:
|
||||
self._pool = self._device_module.graph_pool_handle()
|
||||
self._capture_stream = stream
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
self._capture_stream = None
|
||||
|
||||
def capture_one(
|
||||
self,
|
||||
shape_key: Any,
|
||||
forward_fn: Callable[[], Any],
|
||||
dummies: Optional[Any] = None,
|
||||
post_warmup_hook: Optional[Callable[[], None]] = None,
|
||||
) -> None:
|
||||
# Two warmups so kernels are loaded and one-time setup is paid before capture.
|
||||
# post_warmup_hook lets the attention backend reset state that warmup mutated.
|
||||
for _ in range(2):
|
||||
self._device_module.synchronize()
|
||||
self._tp_group.barrier()
|
||||
forward_fn()
|
||||
if post_warmup_hook is not None:
|
||||
post_warmup_hook()
|
||||
|
||||
graph = torch.xpu.XPUGraph()
|
||||
|
||||
# graph_ctx: Callable[..., AbstractContextManager]
|
||||
graph_ctx = self._device_module.graph
|
||||
|
||||
with graph_ctx(graph, pool=self._pool, stream=self._capture_stream):
|
||||
out = forward_fn()
|
||||
|
||||
self._graphs[shape_key] = graph
|
||||
self._outputs[shape_key] = out
|
||||
|
||||
def can_run(self, forward_batch: ForwardBatch, shape_key: Any) -> bool:
|
||||
return shape_key in self._graphs
|
||||
|
||||
@contextmanager
|
||||
def replay_session(self):
|
||||
yield
|
||||
|
||||
def replay(
|
||||
self,
|
||||
shape_key: Any,
|
||||
static_forward_batch: ForwardBatch,
|
||||
**kwargs,
|
||||
) -> Any:
|
||||
self._graphs[shape_key].replay()
|
||||
return self._outputs[shape_key]
|
||||
|
||||
def cleanup(self) -> None:
|
||||
self._graphs.clear()
|
||||
self._outputs.clear()
|
||||
self._pool = None
|
||||
@@ -72,13 +72,6 @@ def resolve_decode_backend(
|
||||
cuda_graph_runner, enable_memory_saver=enable_memory_saver
|
||||
)
|
||||
elif model_runner.device == "xpu":
|
||||
from sglang.srt.hardware_backend.xpu.xpu_cudagraph_backend import (
|
||||
XPUCudaGraphBackend,
|
||||
)
|
||||
|
||||
return XPUCudaGraphBackend(cuda_graph_runner)
|
||||
|
||||
if model_runner.device == "xpu":
|
||||
if backend_name not in (Backend.FULL, Backend.DISABLED):
|
||||
raise ValueError(
|
||||
f"XPU only supports cuda_graph_config decode backend 'full', got '{backend_name}'"
|
||||
|
||||
@@ -3054,6 +3054,22 @@ class ServerArgs:
|
||||
|
||||
def _handle_xpu_backends(self):
|
||||
if self.device == "xpu":
|
||||
# Decode graph is opt-in on XPU: unless the user explicitly set
|
||||
# --cuda-graph-backend-decode (or --cuda-graph-config), keep it
|
||||
# disabled so the default startup doesn't require graph capture.
|
||||
if (Phase.DECODE, "backend") not in self._cuda_graph_config_locked:
|
||||
self.cuda_graph_config.decode.backend = Backend.DISABLED
|
||||
elif self.cuda_graph_config.decode.backend not in (
|
||||
Backend.DISABLED,
|
||||
Backend.FULL,
|
||||
):
|
||||
logger.warning(
|
||||
"XPU platform only supports decode backend 'full'; "
|
||||
"disabling unsupported decode backend '%s'.",
|
||||
self.cuda_graph_config.decode.backend,
|
||||
)
|
||||
self.cuda_graph_config.decode.backend = Backend.DISABLED
|
||||
|
||||
if self.cuda_graph_config.prefill.backend not in (
|
||||
Backend.DISABLED,
|
||||
Backend.TC_PIECEWISE,
|
||||
|
||||
@@ -621,9 +621,23 @@ def get_available_gpu_memory(
|
||||
|
||||
if empty_cache:
|
||||
empty_device_cache(torch.xpu)
|
||||
# Use mem_get_info() to reflect true OS-level free memory
|
||||
# including graph pool reservations; avoids KV-cache over-allocation.
|
||||
free_gpu_memory, total_gpu_memory = torch.xpu.mem_get_info(gpu_id)
|
||||
# Use mem_get_info() with a sanity cap to avoid KV-cache over-allocation
|
||||
# on drivers that incorrectly return total memory as free memory.
|
||||
# Consistent with the fallback: free = max(0, total - allocated).
|
||||
try:
|
||||
free_gpu_memory, total_gpu_memory = torch.xpu.mem_get_info(gpu_id)
|
||||
used_memory = float(torch.xpu.memory_allocated(gpu_id))
|
||||
free_gpu_memory = min(
|
||||
float(free_gpu_memory),
|
||||
max(0.0, float(total_gpu_memory) - used_memory),
|
||||
)
|
||||
except Exception:
|
||||
# Fallback for devices/drivers that do not support querying free memory
|
||||
used_memory = float(torch.xpu.memory_allocated(gpu_id))
|
||||
total_gpu_memory = float(
|
||||
torch.xpu.get_device_properties(gpu_id).total_memory
|
||||
)
|
||||
free_gpu_memory = max(0.0, total_gpu_memory - used_memory)
|
||||
|
||||
elif device == "hpu":
|
||||
num_gpus = torch.hpu.device_count()
|
||||
|
||||
Reference in New Issue
Block a user