Conversation
Co-authored-by: zjy0516 <riverclouds.zhu@qq.com> Co-authored-by: KungYork <firelikest@163.com> Co-authored-by: Thien Tran <gau.nernst@yahoo.com.sg> Co-authored-by: Jiangyun Zhu <riverclouds.zhu@qq.com> Co-authored-by: Yifan Qiao <yifanqiao@inferact.ai> Co-authored-by: andyluo7 <43718156+andyluo7@users.noreply.github.com> Co-authored-by: Isotr0py <mozf@inferact.ai> Assisted-by: OpenAI Codex Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
Signed-off-by: huanghaoyan.hhy <huanghaoyan.hhy@alibaba-inc.com>
|
Third topology, and a measurement that I think changes what Box: 2× Intel Arc Pro B70 (32 GB), both behind one PCIe switch sharing a single Gen4 x16 1. The p50 is not PLE's cost. The D2H itself is 0.17 ms. ITL does not change — the wait moved earlier, it did not go 2. The drain tracks host streaming, not PLE. Dropping ITL and the drain move together, 1:1. PLE's real work does not move. 3. Demand paging is leaving 2.6× on the link. Same box, same card, 512 MiB H2D: What I am unsure about is the fix. Batched prefetch after routing would start earlier Nothing above looks XPU-specific to me: the misattribution comes from where the sync happens, |
Prepare mmap-backed PLE rows in Qwen4ExpModelState and copy them directly into stable, module-owned GPU buffers before compiled model execution. Captured forwards now read those buffers without host work, which removes the old whole-forward custom op and allows FULL cudagraph modes under Model Runner V2. Model Runner V1 is rejected because it does not prepare the required PLE inputs. Keep profile and dummy batches on a zero-only path, account for staging memory before KV-cache sizing, and validate mmap reloads before any model mutation. Transaction-scoped approvals handle repeated nested loader groups while preserving fail-closed shard and checkpoint validation. Rename the timing line to PLE mmap input prep. The IDs D2H field is now ids_d2h_wait_ms to state that it includes queued dependency work rather than measuring pure copy latency. Signed-off-by: Christopher Deodat <61226342+Trosfy@users.noreply.github.com> Assisted-by: Claude Code (AI assistant)
PLE mmap discovery previously scanned every safetensors file in a checkpoint directory. A consolidated or leftover export excluded by the weight index could therefore supply rows and scales that the normal loader never sees. Filter discovery through the loader's index helper, reject duplicate logical shards and scales, and key cached headers by the selected files' identity and metadata so same-path checkpoint updates cannot retain stale offsets. Reject unsupported scale dtypes during validation, before an in-place reload can mutate model weights. Signed-off-by: Christopher Deodat <61226342+Trosfy@users.noreply.github.com> Assisted-by: Claude Code (AI assistant)
|
@tomylin890 Thanks for running both follow-ups. The matched resident PIECEWISE result changes the attribution in the useful direction. Resident FULL at 15 ms versus resident PIECEWISE at 19 ms supports about 4 ms from graph mode. Mmap PIECEWISE at 28 ms leaves another 9 ms associated with the mmap path, but we cannot call all of that graph re-entry cost from this comparison alone. We have now reconciled the branch with merged #53896 and moved PLE hashing and mmap gathering into input preparation. Rows are copied into a stable GPU buffer before the model runs, the old whole-forward split op is gone, and FULL graph modes are supported under Model Runner V2. Upstream still supports PP1 only, so I am not asking you to port or rerun this on the TP2/PP4 stack yet. A future comparison needs to start from the reconciled implementation rather than the old split path. Your disk-KV follow-up also narrows that result. Two roughly 41 GB restores competing for a 32 GiB pool explain the concurrency pressure, while healthy single restores and intermittent dual behavior do not establish mmap as the cause. We will keep that observation scoped accordingly. Thanks for correcting the earlier attribution and closing both requested arms. |
|
@TSUMUGI-XE Thanks for running this. The explicit sync arm caught a mistake in how we were reading our timing line. We have renamed it to On your box, moving the 92 ms wait earlier left ITL unchanged and exposed the PLE path itself at under a millisecond. The experts versus declaration-order result puts the larger delay in generic parameter offload. We are keeping #54129 scoped to PLE mmap rather than adding XPU and MoE offload work, so I do not think you need to run anything else for this PR. Thanks for adding the control. Without it, we would have kept charging someone else's queue to PLE. |
|
This pull request has merge conflicts that must be resolved before it can be |
Reconcile the PLE mmap series with the fused PLE kernels merged by vllm-project#54517 and the FP8 scale validation from vllm-project#54722. Keep upstream's new ops.ple dispatch (ple_ngram_ids, ple_gate, ple_conv) and its removal of the NVIDIA positions_buffer/padded_buffer registrations and the max_total_tokens/max_num_reqs constructor parameters, then layer the mmap delta onto those seams. Resolves four hunks in ple_layer.py and model.py: union of the ple_mmap and ops.ple imports, the mmap embedding branch without the deleted buffers, the mmap short-circuit in forward without the duplicated ngram_ids allocation upstream removed, and the _HC_WEIGHTS_MAPPER to _EXTRA_WEIGHTS_MAPPER rename around the retained reload preflight. Adapt test_ple_mmap.py to the new Qwen4ExpNGramEmbedding signature. The CPU-driven equivalence test now copies compute_ngram_ids' result into the op's output buffer itself: the fused CUDA kernel writes in place, but the eager fallback returns a fresh tensor and leaves output untouched. Signed-off-by: Christopher Deodat <61226342+Trosfy@users.noreply.github.com> Assisted-by: Claude Code (AI assistant)
All four failed on import/setup, so they asserted nothing from the moment they landed. Commit b5fe6f4 described them as 'pre-existing and unrelated' -- they were inherited from the ported PR vllm-project#54129 suite, but the causes are the port-adaptation gaps that same commit documented and did not carry into the tests, and one of them guards this branch's own numerics. * test_hash_ngram_ids_matches_golden_ids called module._hash_ngram_ids; main renamed it compute_ngram_ids. The compat shim in ple_mmap.py covers the module-level op, not a direct method call, so the golden-value pin on the trigram hashing never executed. * test_env_on_off_forward_equivalence_fp8_and_dequantized died with 'Forward context is not set' on the stock arm. This is the ONLY test comparing mmap gather output against the stock table numerically -- the thing most worth having, and it had never run. Both arms now get a context. * test_default_off_forward_never_calls_the_mmap_gather_op, same cause, plus the context must hold a layer-shaped object: the op resolves the PLE layer and then its .ple_embedding. * test_default_off_load_weights_matches_the_stock_contract used a bare nn.Parameter, but the stock path calls embedding.weight.weight_loader(...). Added a double implementing the real contract -- intersect the shard's global row range with this rank's slice and copy the overlap -- so the test exercises the contract instead of raising AttributeError before its assertions. 138 passed, 6 skipped (GPU-only), up from 134 passed / 4 failed. Co-Authored-By: Claude Mythos <noreply@anthropic.com>
Retain checkpoint-native PLE shards as reclaimable safetensor mappings in the shared CPU offload worker. Deduplicate and sort row IDs, issue shard gathers through a bounded worker pool, and fan one exact FP8 result out to TP ranks. The worker-pool design is informed by upstream vLLM PR #54129 while preserving 1Cat single-compute TP4 topology and MADV_RANDOM behavior. Cold random TP4 prefill improves from 2382 to 4044 tok/s at 256K while avoiding the 47.7 GiB anonymous table and preserving output hashes. Inspired-by: vllm-project/vllm#54129 Signed-off-by: yangzhuxinyzx <153831768+yangzhuxinyzx@users.noreply.github.com>
|
This pull request has merge conflicts that must be resolved before it can be |
What this changes
Qwen3.8-Flash-Next has a 47.68 GiB FP8 PLE table. On machines with limited host memory, or one shared CPU and GPU memory pool, keeping that table resident can prevent the model from fitting.
VLLM_PLE_MMAP=1reads the required rows from the checkpoint's safetensors files through read-only mmap. Discovery followsmodel.safetensors.index.jsonwhen present and rejects missing, duplicate, malformed, or unsupported shards and scales.Model Runner V2 gathers PLE rows during input preparation and copies them into stable GPU buffers before the model runs. Captured code only reads those buffers, so FULL cudagraph modes work without the previous whole-forward splitting op.
The mapped files use Linux's normal file cache. Recently accessed pages may remain resident, but they are clean and file backed, so the kernel can reclaim them when memory is needed. Prewarm and readahead affect which pages enter the cache; they do not pin the complete table in RAM.
Configuration
VLLM_PLE_MMAP0VLLM_PLE_MMAP_WORKERS32VLLM_PLE_MMAP_CHUNK2048VLLM_PLE_MMAP_PREWARM0VLLM_PLE_MMAP_READAHEAD0posix_fadvise;0disables itVLLM_PLE_MMAP_PINNED0VLLM_PLE_MMAP_SERIAL0The rate-limited timing line is
PLE mmap input prep. Itsids_d2h_wait_msfield measures host time blocked at the IDs D2H boundary. This includes dependency-ordered accelerator work queued before the copy, so it is not pure transfer or exclusive PLE cost.Validation
Current branch:
pytest tests/models/qwen4_exp/test_ple_mmap.py -q: 204 passedpytest tests/v1/worker/ -q: 468 passed, 1 skippedpre-commit run mypy-3.12 --all-files --hook-stage manual: passedModel evaluation:
External performance reports also used the previous PIECEWISE split path:
An earlier GB10 run measured 39.7% of the PLE shard pages resident in file cache and no PLE table bytes resident on the GPU.
Scope
This does not duplicate #53899. That implementation keeps the complete PLE table in host memory and uses an offload worker. This PR keeps the checkpoint files as backing storage and has no PLE worker.
Model Runner V2 is required. Pipeline parallelism greater than one is not supported. The implementation assumes Linux file-cache semantics.
AI assistance was used. I reviewed every changed line, verified the reported tests and external evaluation, and take responsibility for the contribution.