Repository navigation
FEAT: support Xavier P/D across vLLM and SGLang - #5639
Conversation
d0d21ac to
15bf602
Compare
rogercloud
left a comment
There was a problem hiding this comment.
Major
xinference/model/llm/xavier/backends/torch/pd.py:286— SGLang prefill to vLLM decode fails for prompts with len % 64 == 1 (page-count mismatch).xinference/model/llm/vllm/xavier/cross_engine.py:176— per-request failures raised in vLLM scheduler hooks kill EngineCore.xinference/model/llm/xavier/backends/torch/pd.py:262— hard-coded 120s receive deadline, busy-polling, missing lease_timeout and wait_done deadline.
Minor
xinference/model/llm/xavier/pd_contract.py:57—fingerprint_filesruns withoutcache_dir, so every cross-engine launch hashes all weights (alsoxinference/model/llm/sglang/xavier/config.py:156, which discards the contract built at :120-123).xinference/model/llm/xavier/backends/torch/pd.py:176—releaseRPC failure inpoll_direct_gpu_v1loses the finished set; rooms also leak when a direct lease expires.xinference/core/pd_model.py:351— any truthyresponse_formatis rejected, including{"type":"text"}.xinference/core/supervisor.py:3332—cfg.engine_configmerged without reserved-key checks.xinference/core/supervisor.py(add_model_replica(s)) — silently ignoresmodel_engine/engine_configfor non-PD models while launch rejects them.xinference/core/supervisor.py:3219— "does not yet support retained GPU history" message is misleading for vLLM/SGLang cross-engine; a context-length/tokenizer/weights mismatch surfaces as "KV namespaces differ" without naming the field.xinference/model/llm/xavier/tests/test_pd_cross_engine_gpu.py:19— no test that SGLangconfigure_xavierand vLLMconfigure_cross_engineyield the same fingerprint (different context keys); no CPU tests for CrossEngineGPUActor deadlines orpoll_direct_gpu_v1error handling; the GPU test is opt-in and not run in CI.
Blocking: yes — recommended event: COMMENT
xinference/model/llm/xavier/backends/torch/pd.py:286major — SGLang prefill to vLLM decode fails for prompts of 65/129/193... tokens [new]xinference/model/llm/vllm/xavier/cross_engine.py:176major — a single bad request kills the whole vLLM decode EngineCore [new]
|
Addressed the additional review-summary items in d0bc1f4:
Local validation: 1,058 passed / 46 skipped, 29 benchmark tests passed, whole-repository pre-commit passed, and all six two-GPU bitwise cases passed (both directions at 65/129/193 tokens with actual minimum target-page allocation). The two-GPU test remains opt-in because the existing GPU CI runner has one T4; it was executed on the reserved two-GPU host. Both directions also passed actual streaming/non-streaming boundary requests at 64/65/66/128/129/130/193 tokens, prefill-baseline output checks, transfer counters and cancellation cleanup. A one-token decode failure leaves the service able to answer fresh requests. Latest-head lint and hosted documentation checks passed; the test matrix is running. Performance samples were discarded because of concurrent foreign GPU workloads, so the PR retains the existing table with its measured revision explicitly identified; latest-head performance remains pending an isolated window. |
rogercloud
left a comment
There was a problem hiding this comment.
Minor
xinference/model/llm/vllm/xavier/cross_engine.py:302:_pending_abortsis written in the scheduler-role connector but only drained in the worker-role instance, so the abort retry never runs. When that happens, the request's prefill KV blocks stay pinned (inline).xinference/model/llm/xavier/backends/torch/pd.py:204:CrossEngineGPUActor.abortpops the room, so late producer calls raise bareKeyErrorand theabortedchecks are dead code. The related test seeds a state production never creates (inline).xinference/core/replica_config.py:185: the reservedengine_configkeys missn_worker,shardanddriver_info, son_worker>1can get past the supervisor rejection (inline).xinference/core/supervisor.py:3166: heterogeneous PD skips the model_format/quantization/n_worker pre-launch checks. Bad weights then fail only after side effects have started (inline).doc/source/user_guide/pd_separation.rst:141: the "supports no CPU fallback, ..." wording is ambiguous (inline).- Test coverage gaps: (a)
VLLMModel.set_xavier_config(None)keeping the heterogeneous config (vllm/core.py~550-557); (b)XavierEngineselectingCrossEngineConnectorwithkv_load_failure_policy="fail"for heterogeneous configs (vllm/xavier/engine.py~129-148); (c) heterogeneous PD rejectingxavier_gpu_cache_bytes>0/xavier_cache_bytes; (d)response_formatjson_object/json_schemastill being rejected on cross-engine PD (only the text-allowed case is tested).
(e) The vLLM decode receive tests pass exactly ceil((len-1)/64) destinations, but vLLM allocates ceil(len/64) when len%64==1. As a result thedestinations[:receive_pages]trim path is never exercised.
Simplification
xinference/model/llm/vllm/xavier/cross_engine.pyL87: delete:self._preparedis never added to and is only discarded (L305/L310). Remove the set, both discards and the test seeding (test_cross_engine.pyL39/L76).xinference/model/llm/vllm/xavier/cross_engine.pyL242: shrink: the_receive_pagestry/except duplicates the outer catch inreceive()(both log and returnset(destinations)). Inlineactor.receive(room, destinations, 0)and keep the single catch, moving its comment there. Tests that call_receive_pagesdirectly can go throughstart_load_kvinstead.
net: -15 lines possible
Blocking: no — recommended event: APPROVE
|
Addressed the second review in aef81e7. All five inline threads are fixed, replied to and resolved. The review-body suggestions are also covered: removed the unused Validation on this head: 1,085 passed / 49 skipped, whole-repository pre-commit passed, 9 two-GPU bitwise cases passed, and both heterogeneous directions passed real streaming/non-streaming API boundary and cancellation checks. All nine modified catalogs passed validation/compilation; 20 English/translated pages rendered successfully. Hosted English/Chinese docs and CI lint have passed; the remaining CI matrix is running. The PR description contains the final performance table with its measured revision |
Prefill and decode replicas can now use different engines: vLLM → SGLang and SGLang → vLLM. Per-replica
model_engine/engine_configselect each role, and Xavier converts canonical 64-token KV pages on GPU and transfers them directly through NIXL. Weight/tokenizer/context contracts and prompt token IDs must match; incompatible configurations and failed transfers raise request errors.The initial scope is unquantized FP16 full-attention Qwen2/Qwen3/Llama text models with TP=PP=DP=1 and
n=1, including streaming and non-streaming chat/completions. Cancellation drains GPU work and releases handoff state without terminating either engine. Documentation and all nine translations are updated.Dependencies
Based on
mainafter #5629, #5631 and #5638 merged; no unmerged PR dependencies. Homogeneous MLX support is preserved. Mixed-engine MLX P/D remains outside this PR.Final performance
Same Xinference API/router, Qwen2.5-0.5B-Instruct FP16, RTX 3090 Ti, vLLM 0.28.0 / SGLang 0.5.21, eager execution, 64-token pages, 32,768 KV tokens per replica and 8,192 context limit. Warmed mixed prompts of 40/173/733/2,833 tokens, fixed 32-token output, 128 requests at each concurrency. Ordinary replicas use one GPU; P/D uses two. GPU interference checks passed for every run. TTFT includes prefill, queueing, transfer/conversion and decode. Ordinary replicas remain faster on this small model. Runtime revision:
5c55e954a.Validation
test_block_trackerassertion also fails onmain: it expects an empty bucket that the shared tracker removes. Three optional vLLM chat tests also fail onmainin a local environment without installed vLLM. These are recorded separately from the passing regression sweep.