Skip to content

[Store] Add Intel XPU host-staging path to the Store client, Python e2e and vLLM-XPU smoke tests - #4270

Open
XinyuYe-Intel wants to merge 2 commits into
kvcache-ai:mainfrom
XinyuYe-Intel:feat/xpu-store-staging
Open

XinyuYe-Intel wants to merge 2 commits into
kvcache-ai:mainfrom
XinyuYe-Intel:feat/xpu-store-staging

Conversation

@XinyuYe-Intel

@XinyuYe-Intel XinyuYe-Intel commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Description

This is PR3 of the Intel XPU enablement series (RFC #4031; PR1 #4030 added
the TENT XPU platform, PR2 #4157 added the XPU transport, routing and
host-staging in the Transfer Engine). It brings the Mooncake Store client up on
Intel XPU and adds end-to-end acceptance tests against an unmodified vLLM-XPU.

Store

  • mooncake-store/src/device/xpu_accelerator_device.cpp (new, built only under
    USE_XPU): a SYCL-backed AcceleratorDevice (vendor kIntel). It
    classifies any USM pointer against the platform default context (the one
    PyTorch allocates from), so foreign device memory is recognised; copies run
    on queues bound to that context; pinned host memory comes from
    sycl::malloc_host. Linked in through EnsureXpuAcceleratorDeviceLinked().
  • accelerator_device.h / accelerator_registry.cpp: kIntel vendor and the
    registration hook.
  • mooncake-store/src/CMakeLists.txt: add the source and a USE_XPU branch in
    the D2H-staging block.

icpx compile fixes (behaviour-neutral for GCC)

  • vendored fmt 8.0.1 core.h: two upstream-equivalent fixes so the
    consteval FMT_STRING checks compile under clang-based compilers.
  • client_service.cpp: define Client::BatchUpsert after PutOperation is
    complete (std::vector<PutOperation> was instantiated on an incomplete type).

Engine selection is unchanged (per review on #4157): Intel XPU is only
supported by the TENT engine, so XPU deployments must set MC_USE_TENT=1. The
smoke scripts default it via os.environ.setdefault, the Python XPU test skips
unless it is set, and the MC_USE_TENT row in the store deployment guide notes
the requirement.

Tests

  • pybind_client_test: XpuDeviceBufferPutGetRoundTrips (put_from /
    get_into on sycl::malloc_device buffers, byte-equal), compiled with
    MOONCAKE_TEST_XPU_H2D under USE_XPU.
  • mooncake-wheel/tests/test_put_get_tensor.py: test_xpu_local_copy_paths
    (put_tensor / upsert_tensor from device="xpu", get_tensor_into_cuda
    into a registered XPU tensor, 4 MiB put_from / get_into round trip). The
    class now closes the store in tearDownClass: leaving it to the process-exit
    backstop tears the client down from a C atexit handler after the
    interpreter and the SYCL runtime have finalized, which on XPU intermittently
    aborted in free() while joining the client's worker threads.
  • scripts/xpu/vllm_store_smoke.py: one vLLM instance on an Intel XPU with
    vLLM's V1 MooncakeStoreConnector (kv_role=kv_both) and local prefix
    caching disabled. Request 1 prefills and the connector saves the KV blocks
    into Mooncake Store (XPU KV cache → host staging → segment); request 2 is
    identical, cannot hit vLLM's own prefix cache, so the connector loads the
    blocks back into the XPU KV cache and decode resumes from them. PASS requires
    identical non-empty greedy tokens and connector metrics showing
    save_put / load_get keys with zero failures.
  • scripts/xpu/vllm_store_pd_smoke.py: a vLLM kv_producer on one XPU
    (embedded Mooncake segment + master) and a kv_consumer on another
    (standalone-store, no segment), so every decode-side load is a real
    cross-device pull from the prefill segment. --role local spawns both on one
    node with ONEAPI_DEVICE_SELECTOR=level_zero:{0,1}; --role prefill /
    --role decode run the halves on separate nodes.
  • Both scripts carry two in-process shims for vLLM ≤ 0.29 code that is
    CUDA-specific rather than Mooncake-specific, to be dropped once fixed
    upstream: the connector's wait_for_save uses torch.cuda.Event (a raising
    dummy on XPU torch → aliased to torch.xpu.Event), and
    ChunkedTokenDatabase.prepare_values computes KV addresses in np.int64,
    which overflows on Level Zero USM pointers (≥ 2^63) → uint64 math (the
    Mooncake bindings already take uintptr_t). Because of the shims the engine
    core runs in-process (VLLM_ENABLE_V1_MULTIPROCESSING=0).

Module

  • Transfer Engine (mooncake-transfer-engine)
  • Mooncake Store (mooncake-store)
  • Mooncake Conductor (mooncake-conductor)
  • Reshard (mooncake-reshard)
  • Mooncake EP (mooncake-ep)
  • Mooncake PG (mooncake-pg)
  • Integration (mooncake-integration)
  • P2P Store (mooncake-p2p-store)
  • Python Wheel (mooncake-wheel)
  • Common (mooncake-common)
  • Mooncake RL (mooncake-rl)
  • CI/CD
  • Docs
  • Other

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Breaking change
  • Documentation update
  • Performance improvement
  • Other

How Has This Been Tested?

Test commands:

# XPU build (icpx, Intel Arc Pro B60)
. /opt/intel/oneapi/setvars.sh
cmake -G Ninja -S . -B build-xpu -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx \
  -DUSE_TENT=ON -DUSE_XPU=ON -DWITH_STORE=ON -DBUILD_UNIT_TESTS=ON \
  -DWITH_STORE_RUST=OFF -DWITH_P2P_STORE=OFF
cmake --build build-xpu
ctest --test-dir build-xpu -R 'pybind_client_test|runtime_accelerator_test' --output-on-failure

# Python e2e (against a live mooncake_master)
MC_USE_TENT=1 python -m unittest mooncake-wheel/tests/test_put_get_tensor.py -k xpu

# vLLM-XPU acceptance
python scripts/xpu/vllm_store_smoke.py --master-bin build-xpu/mooncake-store/src/mooncake_master
python scripts/xpu/vllm_store_pd_smoke.py --role local --master-bin build-xpu/mooncake-store/src/mooncake_master

# GCC CPU-only (USE_XPU=OFF, WITH_STORE=ON)
cmake -G Ninja -S . -B build -DUSE_TENT=ON -DUSE_XPU=OFF -DWITH_STORE=ON -DBUILD_UNIT_TESTS=ON
cmake --build build --target pybind_client_test runtime_accelerator_test
ctest --test-dir build -R 'pybind_client_test|runtime_accelerator_test'

Test results:

  • Unit tests pass
    • XPU (icpx, B60): pybind_client_test incl. XpuDeviceBufferPutGetRoundTrips
      and the basic put/get cases; test_put_get_tensor.py incl.
      test_xpu_local_copy_paths against a live mooncake_master.
    • GCC (USE_XPU=OFF): store builds, runtime_accelerator_test 9/9,
      pybind_client_test pass — no behaviour change for non-XPU builds.
  • Integration tests pass
    • vllm_store_smoke.py with vllm 0.29.0+xpu (torch 2.13.0+xpu),
      Qwen2.5-0.5B-Instruct: 525 prompt tokens, 8 keys / 6 MiB saved and loaded,
      0 failures, identical outputs.
    • vllm_store_pd_smoke.py on a single node (2 × B60) and across two nodes:
      8/8 KV blocks saved and loaded, decode tokens identical to the prefill
      reference.
  • Manual testing done (above)

Checklist

  • I have performed a self-review of my own code
  • I have formatted my code using ./scripts/code_format.sh
  • I have run pre-commit on the files changed in this PR and all hooks pass
  • I have updated the documentation (if applicable)
  • I have added tests to prove my changes are effective
  • For changes >500 LOC: I have filed an RFC issue ([RFC]: Add Intel XPU support to Transfer Engine & Mooncake Store #4031)

AI Assistance Disclosure

  • No AI tools were used
  • AI tools were used (specify below)

GitHub Copilot (Claude) assisted with drafting the SYCL accelerator device,
the test scaffolding, the vLLM smoke scripts and this description. All changes
were reviewed, built and run on real Intel XPU hardware by the submitter.

Copilot AI left a comment

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.

Copilot review overview

🟡 Changes recommended

Unresolved moderate issues affect XPU context safety, test configuration, and smoke-test orchestration and validation.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 Medium severity

Open (2)
What changed in this PR

Adds Intel XPU host-staging support to the Mooncake Store client, with Python and vLLM-XPU end-to-end coverage.

Changes:

  • Adds SYCL-based XPU acceleration, registration, and build wiring.
  • Adds native/Python round-trip tests and vLLM smoke tests.
  • Updates icpx compatibility and deployment documentation.
File Description
scripts/​xpu/​vllm_store_smoke.py Single-node vLLM-XPU Store smoke test
scripts/​xpu/​vllm_store_pd_smoke.py Prefill/decode XPU smoke test
mooncake-wheel/​tests/​test_put_get_tensor.py XPU tensor and buffer round-trip tests
mooncake-store/​tests/​pybind_client_test.cpp SYCL buffer round-trip test
mooncake-store/​tests/​CMakeLists.txt XPU test build definition
mooncake-store/​src/​device/​xpu_accelerator_device.cpp SYCL XPU accelerator implementation
mooncake-store/​src/​device/​accelerator_registry.cpp XPU registry linkage
mooncake-store/​src/​CMakeLists.txt XPU source and staging build wiring
mooncake-store/​src/​client_service.cpp icpx incomplete-type compatibility fix
mooncake-store/​include/​device/​accelerator_device.h Intel accelerator vendor definition
mooncake-store/​include/​cachelib_memory_allocator/​include/​fmt/​core.h icpx compatibility fixes
docs/​source/​deployment/​mooncake-store-deployment-guide.md TENT requirement documentation

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread mooncake-store/src/device/xpu_accelerator_device.cpp
Comment thread scripts/xpu/vllm_store_pd_smoke.py Outdated
…2e and vLLM-XPU smoke tests

Build-guarded (USE_XPU, icpx) VRAM<->host staging for mooncake-store so
PyTorch XPU tensors can be put/got through the existing accelerator
registry, plus end-to-end acceptance tests against an unmodified vLLM.

Store:
- device/xpu_accelerator_device.cpp: SYCL-backed AcceleratorDevice
  (vendor kIntel). Classifies any USM pointer against the platform default
  context (the one PyTorch allocates from) so foreign device memory is
  recognised; copies via queues on that context; pinned host via
  sycl::malloc_host. Linked in through EnsureXpuAcceleratorDeviceLinked().
- CMake: add the source and a USE_XPU branch in the D2H-staging block;
  pybind_client_test gets MOONCAKE_TEST_XPU_H2D.

icpx compile fixes (behaviour-neutral for GCC):
- vendored fmt 8.0.1 core.h: two upstream-equivalent fixes so consteval
  FMT_STRING checks compile under clang-based compilers.
- client_service.cpp: define Client::BatchUpsert after PutOperation is
  complete (std::vector<PutOperation> on an incomplete type).

Tests:
- pybind_client_test: XpuDeviceBufferPutGetRoundTrips (put_from/get_into on
  sycl::malloc_device buffers, byte-equal).
- mooncake-wheel/tests/test_put_get_tensor.py: test_xpu_local_copy_paths
  (put/upsert_tensor from device="xpu", get_tensor_into_cuda into a
  registered XPU tensor, 4 MiB put_from/get_into round trip). The class
  now closes the store in tearDownClass: leaving it to the process-exit
  backstop tears the client down from a C atexit handler after the
  interpreter and the SYCL runtime have finalized, which on XPU
  intermittently aborted in free() while joining the client's worker
  threads.

vLLM-XPU smoke tests (scripts/xpu/):
- vllm_store_smoke.py: one vLLM instance on an Intel XPU with vLLM's V1
  MooncakeStoreConnector (kv_role=kv_both) and local prefix caching
  disabled. The first request prefills and the connector saves the KV
  blocks into Mooncake Store (XPU KV cache -> host staging -> segment); the
  second, identical request cannot hit vLLM's own prefix cache, so the
  connector loads the blocks back into the XPU KV cache and decode resumes
  from them. PASS requires identical non-empty greedy tokens for both
  requests and connector metrics showing save_put/load_get keys with zero
  failures. This exercises Transfer Engine registration of PyTorch XPU
  tensors (register_buffer on the KV cache) and the store client's XPU
  host-staging copies (batch_put_from_multi_buffers /
  batch_get_into_multi_buffers on device pointers).
- vllm_store_pd_smoke.py: a vLLM kv_producer on one XPU (embedded Mooncake
  segment + master) and a kv_consumer on another (standalone-store, no
  segment) so every decode-side load is a real cross-device pull from the
  prefill segment. --role local spawns both on one node with
  ONEAPI_DEVICE_SELECTOR=level_zero:{0,1}; --role prefill / --role decode
  run the halves on separate nodes with a shared master address and a
  copied reference JSON.
- Both scripts carry two in-process shims for vLLM <= 0.29 code that is
  CUDA-specific rather than Mooncake-specific, to be dropped once fixed
  upstream: the connector's wait_for_save uses torch.cuda.Event, which is a
  raising dummy on XPU torch (aliased to torch.xpu.Event); and
  ChunkedTokenDatabase.prepare_values computes KV addresses in np.int64,
  which overflows on Level Zero USM pointers (>= 2^63) (uint64 math; the
  Mooncake bindings already take uintptr_t). Because of the shims the
  engine core runs in-process (VLLM_ENABLE_V1_MULTIPROCESSING=0).

Relies on the TENT XPU platform classifying externally allocated USM
(kvcache-ai#4157) so registerLocalMemory("xpu:N") accepts PyTorch tensors. Engine
selection is unchanged: XPU is only supported by TENT, so deployments must
set MC_USE_TENT=1. The smoke scripts default it via os.environ.setdefault,
test_xpu_local_copy_paths skips unless it is set (the store is created in
setUpClass), and the MC_USE_TENT row in the store deployment guide notes the
requirement.

Validated on Intel Arc Pro B60 (icpx, USE_TENT+USE_XPU+WITH_STORE):
pybind_client_test XPU + basic put/get; the Python unittest against a live
mooncake_master; vllm_store_smoke.py with vllm 0.29.0+xpu (torch
2.13.0+xpu) and Qwen2.5-0.5B-Instruct: 525 prompt tokens, 8 keys / 6 MiB
saved and loaded, 0 failures, identical outputs; vllm_store_pd_smoke.py on
a single node (2 XPUs) and across two nodes: 8/8 KV blocks saved and
loaded, decode tokens identical to the prefill reference. GCC CPU-only
build (USE_XPU=OFF, WITH_STORE=ON): store builds, runtime_accelerator_test
9/9, pybind_client_test pass.

Part of the XPU enablement plan (RFC kvcache-ai#4031); stacked on kvcache-ai#4157.
…fill segment in PD smoke

- XpuRuntime now picks one platform (Level Zero preferred) and creates all
  queues on its default context; pinned host buffers are allocated from that
  same context, so every queue can legally consume them.
- vllm_store_pd_smoke.py: --role prefill requires --result and --done-file and
  fails if the hold times out, so the producer segment stays mounted until the
  decode side is done; two-node instructions document the coordination.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation Installation run-ci Store Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants