Repository navigation
[KVOffload][P2P][CI] Add a fault slice to the P2P e2e matrix - #64511
Draft
liranschour wants to merge 13 commits into
Draft
liranschour wants to merge 13 commits into
liranschour wants to merge 13 commits into
Conversation
run_accuracy_test.sh could pass without proving the p2p tier moved any KV, and several deployments it advertised did not work: - Add test_p2p_transfer.py: send fully unique prompts through the proxy and assert the decoders' vllm:external_prefix_cache_hits grew by most of the prompts' full blocks. gsm8k alone passes when the decoder recomputes. - p2p_connector_proxy.py: --p2p-connector-host/--p2p-connector-port take one value per prefiller instance and the proxy injects the coordinates of the instance that ran the prefill. Previously every decode was pointed at the first prefiller, so NUM_PREFILL_INSTANCES>1 fetched from the wrong peer. - New knobs: PREFILLER_DP_SIZE (DP prefiller, proxy pins prefills per replica), P2P_MODE=pd|p2p (remote_prefiller vs remote_kv_source), ENFORCE_EAGER, --attention-backend, CHECK_TRANSFER. - Stride p2p control ports by instance so per-DP-rank ports (base + dp index) cannot collide; pin VLLM_PORT / VLLM_DP_MASTER_PORT per instance. - Cleanup escalates TERM->KILL, also reaps orphaned VLLM:: DP processes, removes stale /dev/shm/vllm_offload_*.mmap, waits for ports to free, and runs before each model and on exit. - Warm every DP rank before the accuracy run; wait on the proxy healthcheck. - MAX_MODEL_LEN 512 -> 2048 (gsm8k 5-shot prompts are longer than 512) and CPU_BYTES 200 MB -> 2 GiB so the source tier does not evict KV before the decoder pulls it at NUM_CONCURRENT=100. - Pick the first interpreter that can import vllm. Signed-off-by: Liran Schour <lirans@il.ibm.com>
config_sweep_accuracy_test.sh runs run_accuracy_test.sh (accuracy + KV transfer assertion) over a deployment matrix, one slice per CI step, mirroring nixl_integration/config_sweep_accuracy_test.sh: - default (L4 x4, Llama-3.2-1B): TP1/TP1 in both pd and p2p handshake modes, mixed TP 1->2 and 2->1, 2 prefillers x 2 decoders, decoder-first proxy. - DP_EP=1 (L4 x4): deepseek-vl2-tiny (MoE) TP prefiller -> DP-EP decoder, and a DP=2 dense prefiller. - MLA=1 (H100 x4, optional): DeepSeek-V2-Lite-Chat with mixed TP. The smaller deepseek-vl2-tiny has use_mla=false, so it does not cover MLA. Signed-off-by: Liran Schour <lirans@il.ibm.com>
Measured 0.332 (strict-match) on a single plain vLLM instance (H200, --enforce-eager --block-size 128 --max-model-len 2048), the baseline the p2p tier PD sweep's default model is checked against. Signed-off-by: Liran Schour <lirans@il.ibm.com>
…iver canonical_layout gives topology-free host pages, the supported route for a prefiller and decoder with different TP sizes to share KV. Signed-off-by: Liran Schour <lirans@il.ibm.com>
Matrix runs on 4x H200 showed that the direct host layout is not byte-identical across TP sizes: with the default (V2) model runner the tier refuses TP-mismatched peers (config fingerprint mismatch, decoder recomputes), and with VLLM_USE_V2_MODEL_RUNNER=0 it pairs them and the decoder decodes garbage (gsm8k 0.0). The FS tier shows the same corruption, so it is the shared parallelism-agnostic layout claim, not the p2p data plane. canonical_layout=true is correct on both runners. - Mixed-TP configs (dense, MoE DP-EP, MLA) now set CANONICAL_LAYOUT=1. - New EXPECT_TRANSFER=0 mode in test_p2p_transfer.py asserts no KV moved; one direct-layout TP1->TP2 config pins the safe fallback. Signed-off-by: Liran Schour <lirans@il.ibm.com>
…d flip Signed-off-by: Liran Schour <lirans@il.ibm.com>
… the p2p sweep New FEATURES=1 slice and L4 x4 Buildkite step, one config per cache type that takes a different offload path than plain attention: - Qwen3.5-0.8B (GatedDeltaNet hybrid): several KV cache groups and SSM state over p2p, in p2p handshake mode. - gemma-3-1b-it: sliding window of 512 tokens, shorter than the prompts, so out-of-window blocks are actually dropped. - Llama-3.2-1B with --kv-cache-dtype fp8 through the canonical mixed-TP path that the bf16 configs already cover. Signed-off-by: Liran Schour <lirans@il.ibm.com>
Measured 0.257 (strict-match) on a single plain vLLM instance (H200, --enforce-eager --block-size 128 --max-model-len 2048), consistent with the 0.25 in tests/entrypoints/llm/test_accuracy.py. Signed-off-by: Liran Schour <lirans@il.ibm.com>
test_p2p_transfer.py needs a running proxy and decoders, so the V1 KV Offload step's `pytest v1/kv_offload` collected it and failed it on its first request. Rename it to p2p_transfer_check.py: run_accuracy_test.sh passes it to pytest by path, which skips the test_*.py name filter. Signed-off-by: Liran Schour <lirans@il.ibm.com>
Resolve the disaggregated.yaml conflict with vllm-project#63609, which disables every step in the file until the KV connectors installation is locked. The P2P steps also run install-kv-connectors.sh, so land them commented out under the same note. Mark them optional and [Nightly] (vllm-project#61186) for when they are re-enabled, like the NixlConnector L4 steps. Signed-off-by: Liran Schour <lirans@il.ibm.com>
…ocesses Cleanup used pkill -f "vllm serve" / "VLLM[:]:" and removed every /dev/shm/vllm_offload_*.mmap, so it could kill or corrupt another job's servers on a shared host. Start each server and the proxy with setsid and record the session id; cleanup TERMs, then KILLs, only those sessions. A session also holds the DP API servers, which setpgrp() into their own process group. Give every instance an engine_id prefixed with a per-run id, which names its CPU tier shm file, and remove only files with that prefix. If a fixed port is still taken after cleanup, another job owns it, so fail instead of starting servers on top of it. Signed-off-by: Liran Schour <lirans@il.ibm.com>
The matrix only ran healthy peers. Add FAULTS=1: two prefillers act as p2p sources and one decoder pulls from both with remote_kv_source, while prefiller 0 is stalled (SIGSTOP 30 s), killed and restarted on the same ports, or removed. p2p_fault_check.py asserts time bounds and recovery instead of gsm8k: every request returns 200, requests naming the faulted source end within 15 s and, once the fault is detected, take <= 2 s at the median; pulls from the healthy source keep hitting within 5 s; pulls from the faulted source resume once it is back. run_accuracy_test.sh gets a FAULT_CASE knob that skips the proxy and gsm8k, records each prefiller's session and command so the check can signal and restart exactly that instance, and folds a restarted instance's session into cleanup. The CI step lands commented out with the rest of disaggregated.yaml (vllm-project#63609). On main the stall case fails (faulted-source requests p50 16.9 s, max 30.0 s, the handshake timeout); with vllm-project#64501 it passes. Signed-off-by: Liran Schour <lirans@il.ibm.com>
This was referenced Oct 29, 2026
Open
5 of 6 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Adds a fault slice (
FAULTS=1) to the P2P KV-offload e2e matrix: one of two p2p sources stalls, is killed and restarted, or is removed, while a decoder keeps pulling from both. Requested in #61846 (comment) and follows the cases of the #63602 reproducer.Stacked on #61846: only the last commit (
6cfc3e21d8) is new here. Review that commit; the rest lands with #61846.Claims
FAULTS=1slice inconfig_sweep_accuracy_test.shwith three cases on Llama-3.2-1B, p2p mode (remote_kv_source), 3 GPUs:stallkillremovep2p_fault_check.pyasserts time bounds and recovery rather than gsm8k:stallcase fails on current main and passes with [Bugfix][KV Offload][P2P] Prefill locally while a peer handshake is pending #64501.Validation
4× H200, one host, TCP (no RDMA), branch at merge base
fa3b9d1377with a precompiled wheel. Each case run once viaFAULT_CASE=<case> NUM_PREFILL_INSTANCES=2 bash tests/v1/kv_offload/tiering/p2p/run_accuracy_test.sh; the whole slice isFAULTS=1 bash tests/v1/kv_offload/tiering/p2p/config_sweep_accuracy_test.sh, about 7 minutes.Requests naming the faulted source during the fault (n ≈ 55–60 per row), and pulls from the healthy source:
The main
stallfailure:That is the gap reported in #63602 (comment): after the in-flight request ends on the 8 s lookup timeout, each new request reconnects and waits on a handshake until
VLLM_P2P_HANDSHAKE_TIMEOUT_S(30 s). With #64501 the 7.08 s max is the request that was already in flight when the stop hit.pre-commitpasses on the changed files (shellcheck, ruff, test tethering).Details
remote_prefilleris stopped, so a time-bound check would fail until that leg has its own fix. The p2p leg is fixed by [Bugfix][KV Offload][P2P] Prefill locally while a peer handshake is pending #64501.p2p_connector_proxy.pyruns the prefill on the source before calling the decoder, so a stopped source would stall the proxy. The check seeds each source directly and pulls into the decoder with aremote_kv_sourceblock, like the [Bug]: P2P KV offload tier does not fail fast on peer faults #63602 reproducer's probe. A pull counts as a hit when the decoder reportscached_tokens > 0(the driver adds--enable-prompt-tokens-details); every prefix is unique, so the cached tokens can only have come over the p2p tier.pkill -<SIG> -s <sid>. A restarted source is started in a new session whose id is written to a file the driver's cleanup reads, so cleanup still stops only this run's processes.p2p-kv-offload-source-faults-4-gpus(L4×4, nightly, optional, 30 min) lands commented out, like every step indisaggregated.yamlsince [CI] Disable jobs with unpinned runtime installs #63609. The slice needs 3 × 24 GB GPUs; L4 runtime is not measured.AI assistance (Claude Code) was used to write this change and run the validation. I reviewed the change and the results.
Pull Request Checklist
I used vLLM's
/pr-checklistskill. (Mandatory for agents, optional for humans).AI assistance was used during the creation of this PR.
Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.
Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.
Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.
Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.
🤖 Generated with Claude Code