Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docker/xpu.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,14 @@ RUN echo "Cloning ${SG_LANG_BRANCH} from ${SG_LANG_REPO}" && \
pip install --no-cache-dir . --extra-index-url https://download.pytorch.org/whl/xpu && \
pip install --no-cache-dir --no-deps xgrammar==0.1.33

# Install torch_memory_saver for release/resume_memory_occupation ("memory saver").
# XPU ships no prebuilt wheel: it is built from source against the local oneAPI +
# torch-XPU runtime (the .so links libsycl.so.<N>, which must match the installed
# intel-sycl-rt). TMS_PLATFORM=xpu forces the XPU backend; --no-build-isolation
# lets the build import the installed torch (above) so it can match the libsycl
# major to it -- under build isolation torch is absent and the match is skipped.
RUN . /opt/intel/oneapi/setvars.sh --force >/dev/null 2>&1 && \
TMS_PLATFORM=xpu pip install --no-cache-dir --no-build-isolation \
git+https://github.com/fzyzcjy/torch_memory_saver.git
Comment on lines +61 to +63

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To ensure reproducible builds and prevent future breaking changes on the main branch of torch_memory_saver from breaking the Docker image build, it is highly recommended to pin the installation to a specific commit hash or tag.

RUN . /opt/intel/oneapi/setvars.sh --force >/dev/null 2>&1 && \\
    TMS_PLATFORM=xpu pip install --no-cache-dir --no-build-isolation \\
    git+https://github.com/fzyzcjy/torch_memory_saver.git@YOUR_COMMIT_HASH


CMD ["bash", "-c", "source /opt/intel/oneapi/setvars.sh --force && exec bash"]
50 changes: 50 additions & 0 deletions docs/platforms/xpu.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,53 @@ curl http://127.0.0.1:8000/v1/completions \
```

> **Note:** `UCX_POSIX_USE_PROC_LINK=n` is required on Intel XPU to avoid UCX shared-memory transport issues.

## Memory Saver (release/resume memory occupation) on Intel XPU [Experimental]

SGLang can temporarily release most of the GPU memory it holds — model weights
and/or KV cache — and reclaim it later without restarting the process. This is
the same `release_memory_occupation` / `resume_memory_occupation` feature
available on CUDA, used for RL rollout/training hand-off and for freeing the
device between inference bursts.

This is backed by the [`torch_memory_saver`](https://github.com/fzyzcjy/torch_memory_saver)
package — the same package used on CUDA — which gained an Intel XPU backend
built natively on Level Zero (keeping virtual addresses fixed while
releasing/re-committing physical pages via `zeVirtualMemUnmap` /
`zeVirtualMemMap`).

**Install `torch_memory_saver`.** Unlike CUDA (prebuilt wheel), the XPU backend
is built from source against your local oneAPI + `torch+xpu` runtime (the `.so`
links `libsycl.so.<N>`, which must match the installed `intel-sycl-rt`).
`TMS_PLATFORM=xpu` forces the XPU backend, and `--no-build-isolation` lets the
build import your installed `torch` so it can match the `libsycl` major to it:

```bash
source /opt/intel/oneapi/setvars.sh
TMS_PLATFORM=xpu pip install --no-build-isolation \
git+https://github.com/fzyzcjy/torch_memory_saver.git
```

**Use it** by launching with `--enable-memory-saver` (the XPU backend is
selected automatically); optionally add `--enable-weights-cpu-backup` to keep
weights in host RAM across a release:

```bash
python -m sglang.launch_server --model-path Qwen/Qwen3-0.6B \
--trust-remote-code --device xpu --enable-memory-saver
```

```bash
# Release GPU memory while idle, then reclaim it (server must be idle).
curl -X POST http://127.0.0.1:30000/release_memory_occupation
curl -X POST http://127.0.0.1:30000/resume_memory_occupation
```

The Python engine API (`engine.release_memory_occupation(tags=...)` /
`engine.resume_memory_occupation(tags=...)`) and the `weights` / `kv_cache` tags
behave the same as on CUDA. Pauseable CUDA-graph capture is not used on XPU, so
the `cuda_graph` tag is a no-op there.

> **Verifying memory was freed:** `torch.xpu.memory_allocated()` reflects the
> allocator's accounting and does **not** drop when physical pages are released.
> Query actual device memory via sysman (`ZES_ENABLE_SYSMAN=1`) instead.
50 changes: 44 additions & 6 deletions python/sglang/srt/utils/torch_memory_saver_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@
from abc import ABC
from contextlib import contextmanager

from sglang.srt.utils.common import is_xpu

try:
import torch_memory_saver

# Intel XPU requires hook_mode="torch" (in-process pluggable allocator);
# the LD_PRELOAD-based preload mode is CUDA/HIP-only. Set it before the
# singleton is initialized on first use.
if is_xpu():
torch_memory_saver.torch_memory_saver.hook_mode = "torch"

_memory_saver = torch_memory_saver.torch_memory_saver
import_error = None
except ImportError as e:
Expand All @@ -18,11 +26,24 @@ class TorchMemorySaverAdapter(ABC):
@staticmethod
def create(enable: bool):
if enable and import_error is not None:
logger.warning(
"enable_memory_saver is enabled, but "
"torch-memory-saver is not installed. Please install it "
"via `pip3 install torch-memory-saver`. "
)
if is_xpu():
# XPU ships no prebuilt wheel; it is built from source against the
# local oneAPI + torch-XPU runtime. TMS_PLATFORM=xpu forces the XPU
# backend; --no-build-isolation lets the build see torch and match
# the libsycl ABI to it.
logger.warning(
"enable_memory_saver is enabled, but torch-memory-saver is "
"not installed. On Intel XPU, build it from source with Intel "
"oneAPI on PATH: `TMS_PLATFORM=xpu pip3 install "
"--no-build-isolation "
"git+https://github.com/fzyzcjy/torch_memory_saver.git`."
)
else:
logger.warning(
"enable_memory_saver is enabled, but "
"torch-memory-saver is not installed. Please install it "
"via `pip3 install torch-memory-saver`. "
)
raise import_error
return (
_TorchMemorySaverAdapterReal() if enable else _TorchMemorySaverAdapterNoop()
Expand Down Expand Up @@ -59,17 +80,34 @@ def enabled(self):


class _TorchMemorySaverAdapterReal(TorchMemorySaverAdapter):
"""Adapter for TorchMemorySaver with tag-based control"""
"""Adapter for TorchMemorySaver with tag-based control.

Backed by the upstream torch_memory_saver package (CUDA VMM, and Intel XPU
via Level Zero). On XPU the package uses an in-process pluggable allocator
(hook_mode="torch") rather than the CUDA LD_PRELOAD path, so
configure_subprocess() (nothing to preload) and cuda_graph() (no pauseable
graph-capture path) are no-ops there.
"""

def configure_subprocess(self):
if is_xpu():
# XPU uses an in-process pluggable allocator; nothing to preload.
return self._noop_context()
return torch_memory_saver.configure_subprocess()

def region(self, tag: str, enable_cpu_backup: bool = False):
return _memory_saver.region(tag=tag, enable_cpu_backup=enable_cpu_backup)

def cuda_graph(self, **kwargs):
if is_xpu():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can't we support this ?

# XPU does not support the memory-saver pauseable graph-capture path.
return self._noop_context()
return _memory_saver.cuda_graph(**kwargs)

@contextmanager
def _noop_context(self, **kwargs):
yield

def disable(self):
return _memory_saver.disable()

Expand Down
6 changes: 5 additions & 1 deletion python/sglang/test/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2479,7 +2479,11 @@ def get_gpu_memory_gb():
if is_cuda():
return torch.cuda.device_memory_used() / 1024**3
elif is_xpu():
return torch.xpu.memory_allocated() / 1024**3
# Use mem_get_info (real device free/total), NOT memory_allocated(): the
# latter is the allocator's bookkeeping and does not drop when the XPU
# memory saver releases physical pages via zeVirtualMemUnmap.
free, total = torch.xpu.mem_get_info()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this api working ?

return (total - free) / 1024**3
else:
return 0

Expand Down
Loading
Loading