Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,28 @@ Use the flexible P2P implementation, notice this will install `mooncake-transfer
pip install 'checkpoint-engine[p2p]'
```

### Intel XPU (build from source)

Intel XPU is supported for the **broadcast** update path. The cross-process weight handoff uses a native SYCL `ipc_memory` extension (the XPU counterpart of CUDA IPC) that is JIT-compiled at runtime. Install from source since XPU support is not yet in the released package. P2P is not supported on XPU (Mooncake has no Level Zero backend for XPU device memory).

Requirements:
- Intel XPU build of PyTorch — `torch.xpu.is_available()` returns `True`, `torch>=2.9` (for the device `.uuid` property). See the [PyTorch XPU install guide](https://pytorch.org/docs/stable/notes/get_start_xpu.html); this is not the default PyPI `torch`.
- Intel oneAPI 2026.0+ providing the `icpx` compiler with SYCL `ipc_memory` support. Needed at runtime (first weight update), not at `pip install` time.

```Bash
git clone https://github.com/MoonshotAI/checkpoint-engine.git
cd checkpoint-engine
pip install -e . # no [p2p] extra on XPU
```

Make `icpx` discoverable in the runtime environment, either by sourcing oneAPI (`source /opt/intel/oneapi/setvars.sh`) or by setting `CMPLR_ROOT`. If neither is set, `icpx` is auto-detected under `/opt/intel/oneapi/compiler/*/bin`. The extension then builds automatically on first use; `ParameterServer` also prebuilds it at startup so the one-time compile stays out of the update window.

Verify the build and the IPC path on the target machine:

```Bash
pytest tests/test_xpu_ipc.py # hardware-gated; skipped without an Intel GPU + buildable extension
```

## Getting Started

Prepare an H800 or H20 machine with 8 GPUs with vLLM. Be sure to include [/collective_rpc API endpoint](https://github.com/vllm-project/vllm/commit/f7cf5b512ee41f36613deb2471a44de5f304f70d) commit (available in main branch) since checkpoint-engine will use this endpoint to update weights. vLLM version `v0.10.2` is fully tested and recommended.
Expand Down
53 changes: 52 additions & 1 deletion checkpoint_engine/device_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ctypes
import gc
import os
import re
import socket
Expand Down Expand Up @@ -209,9 +210,20 @@ def _is_torch_npu_available(self) -> bool:
except ImportError:
return False

def _is_torch_xpu_available(self) -> bool:
try:
if hasattr(torch, "xpu") and callable(getattr(torch.xpu, "is_available", None)):
return torch.xpu.is_available()
else:
return False
except Exception: # noqa: BLE001
return False

def _detect_device_type(self) -> str:
if self._is_torch_npu_available():
return "npu"
elif self._is_torch_xpu_available():
return "xpu"
elif torch.cuda.is_available():
return "cuda"
else:
Expand All @@ -222,6 +234,8 @@ def _setup_device_module(self):
import torch_npu

self.device_module = torch_npu.npu
elif self.device_type == "xpu":
self.device_module = torch.xpu
elif self.device_type == "cuda":
self.device_module = torch.cuda
else:
Expand All @@ -231,6 +245,8 @@ def _setup_device_module(self):
def backend(self) -> str:
if self.device_type == "npu":
return "hccl"
elif self.device_type == "xpu":
return "xccl"
elif self.device_type == "cuda":
return "nccl"
else:
Expand All @@ -240,7 +256,7 @@ def backend(self) -> str:
def transfer_engine_protocol(self) -> str:
if self.device_type == "npu":
return "ascend_direct"
elif self.device_type == "cuda":
elif self.device_type in ("cuda", "xpu"):
if has_efa_pci():
return "efa"
else:
Expand All @@ -255,3 +271,38 @@ def rdma_device(self, rank: int) -> str:
return _get_my_rdma_device(rank, self.device_module.device_count(), _get_rdma_devices())
else:
raise TypeError("The current transfer engine protocol is not supported")

def ipc_collect(self) -> None:
"""Reclaim memory held by stale IPC handles where the backend supports it (no-op otherwise)."""
fn = getattr(self.device_module, "ipc_collect", None)
if callable(fn):
Comment thread
siju-samuel marked this conversation as resolved.
Outdated
fn()

def supports_inplace_pin(self) -> bool:
"""Whether in-place host-memory pinning (cudaHostRegister) is available -- CUDA only."""
return self.device_type == "cuda"

def supports_device_ipc(self) -> bool:
"""Whether cross-process IPC of *device* tensors works for this backend.

CUDA/NPU use ``torch.multiprocessing.reductions``; XPU uses the native SYCL
``ipc_memory`` extension, available when it can be built (oneAPI >= 2026.0).
"""
if self.device_type in ("cuda", "npu"):
return True
if self.device_type == "xpu":
from checkpoint_engine import xpu_ipc

return xpu_ipc.is_available()
return False

def supports_device_p2p(self) -> bool:
"""Whether P2P (Mooncake) transfer of *device* memory works for this backend (CUDA/NPU only)."""
return self.device_type in ("cuda", "npu")

def host_empty_cache(self) -> None:
"""Release cached pinned host memory (``_host_emptyCache`` on CUDA; else ``gc.collect``)."""
if self.device_type == "cuda":
torch._C._host_emptyCache()
else:
gc.collect()
7 changes: 6 additions & 1 deletion checkpoint_engine/distributed/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,12 @@ def use_backend(backend: str | None):
"vllm_hccl": ".vllm_hccl.DistributedHccl",
}
if backend not in mapping:
raise ValueError(f"Unsupported custom backend: {backend}")
# XPU has no custom backend; leave custom_dist unset to use the default xccl TorchBackend.
raise ValueError(
f"Unsupported custom backend: {backend}. "
f"Supported custom backends: {sorted(mapping)}. "
"XPU is not supported here; leave custom_dist unset to use the default xccl backend."
)

module_path, class_name = mapping[backend].rsplit(".", 1)
module = importlib.import_module(module_path, "checkpoint_engine.distributed")
Expand Down
Loading
Loading