Repository navigation
Conversation
3 of 5 tasks
Collaborator
审核与实测意见我们审核了 #38( 结论:已握手的请求被中止后通知 D 的主路径,实测有效。还有两处建议修改:
1. 实测1P1D,P、D 均为 TP2;P 开 overlap 调度,chunked prefill 16K;D 的 waiting 超时设为 120 s。
本 PR 头上 2. 需要修改的问题(1) 多 rank 下,末块中止按本 rank 的排空状态决定是否进 inflight 队列(高,条件触发,代码分析)
(2) bootstrap 队列中止后,D 晚到的握手仍收不到通知(中,用真实状态机推演确认)
3. 建议同时处理
|
Collaborator
新提交
|
1 of 5 tasks
lihenga
pushed a commit
that referenced
this pull request
Nov 3, 2026
* fix(epd): skip encoder dispatch on decode node
In EPD disaggregation the router sends every multimodal request to both
prefill and decode. Both nodes run with --language-only --encoder-urls,
and _handle_epd_disaggregation_encode_request dispatches to the encoder
regardless of role, so the shared encoder ran a full preprocess + ViT
forward + mooncake transfer twice per image. Decode discards the
embeddings (it consumes prefill KV) and only needs input_ids / mrope
layout.
Skip encoder dispatch when disaggregation_mode is DECODE so decode builds
the multimodal metadata locally.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(epd): run decode-side image preprocessing on CPU
With encoder dispatch skipped on decode (0a815890d), the decode tokenizer
builds multimodal metadata locally. The fast image processor places that
work on cuda:{base_gpu_id}, so every decode tokenizer worker ran
resize/normalize kernels on the serving GPU of DP rank 0. With DP
attention + EP every decode step waits for the slowest rank
Decode only needs the image layout (input_ids / mrope) and never runs the
ViT, so resolve the fast image processor device to CPU when
disaggregation_mode is decode, and do not count it as competing with the
scheduler GPU.
* perf(encoder): coalesce same-turn GLM image parts into one ViT batch
GLM Mooncake splits one multi-image request into one /encode part per
image. Without yielding before dispatch, the batch worker takes the first
part alone and runs the rest separately (1+7 for eight images), adding a
full ViT launch. Enable same-turn coalescing for glm* models, and keep the
default max batch size clamp specific to kimi_k3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(encoder): propagate contextvars into the GPU executor worker
Run GPU work submitted via _run_gpu_work under a copy of the caller's
context so request-scoped context variables stay visible in the worker
thread.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* perf(epd): always use the per-part RDMA pipeline for GLM receives
Requests from older tokenizers omit encoder_part_routes and fell back to
the base receive path, which waits for every part's metadata before
allocating the landing buffer and posting any RDMA transfer. Derive the
routes from num_items_assigned (same modality-major part IDs) so each part
is received as soon as its embedding is ready.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* perf(epd): drop local MM features on language-only decode
Decode consumes Prefill's KV cache and never runs the vision encoder, so
shipping pixels/embeddings through tokenizer IPC and the DP controller
only delays KV receive allocation and the bootstrap handshake. After local
GLM preprocessing, keep layout/identity (materializing pad values first)
and strip the feature tensors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(epd): fall back to encoder dispatch when decode can't parse mm tokens locally
Decode's local mm-metadata path parses the prompt text for multimodal
special tokens and expects each token to have a matching data item.
Prefill's mooncake-based path never inspects the prompt text at all:
it just fills in embeddings at known placeholder positions once the
encoder returns them. The two sides therefore accept different sets of requests.
A request whose text contains a literal mm token with no matching data
(e.g. a random-text benchmark sampling "<|video|>" from the vocabulary, or
real user text that happens to include that token) is accepted by prefill
but raises ValueError on decode's local parser. The exception only
reaches the SSE stream for that one request; nothing logs it, and nothing
tells prefill. Prefill then waits on decode until
SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT and fails with KVTransferError,
which looks like a lost or stuck request with no visible cause.
Add BaseMultimodalProcessor.mm_tokens_match_data() to compare the mm
token count in the prompt against the data count per modality, and use it
in TokenizerManager._decode_can_build_mm_locally() to fall back to
encoder dispatch (the same path already used when adaptive dispatch
declines) whenever they disagree. Well-formed requests keep building mm
metadata locally.
Signed-off-by: Liang Xiaoxia <liangxiaoxia@hygon.cn>
* fix(epd): build GLM decode mm layout with prefill's get_mm_data
Decode built its multimodal metadata by running the HF processor on the
prompt text, while prefill rebuilds the layout from encoder metadata with
build_input_ids_with_timestamps. The two disagreed: decode rejected a
literal mm token with no matching data that prefill keeps as text, and
for resampled videos (e.g. 25/30 fps) decode produced a different
input_ids length than prefill.
Add Glm4vImageProcessor.process_mm_layout_async: compute image/video
grids and video timestamps from the media alone, sampling frames as the
encoder does, then lay out the prompt with the same get_mm_data prefill
runs. Decode tokenizes like prefill so both expand the same token IDs.
Share video sampling and glm_video_timestamps between the encoder and
the local path. Processors opt in via builds_epd_layout_from_media; for
them the mm_tokens_match_data encoder fallback is skipped.
Checked against prefill on GLM-5-Next for images, videos, image+video
and stray mm tokens: identical input_ids, offsets and M-RoPE, and the
same inputs rejected.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(epd): address PR review on decode mm layout and logging
Lay out decode media with the encoder config: process_mm_layout_async now reads mm_process_config["vision_config"], the source EncoderPreprocessor uses, instead of the top-level image/video keys, which would make decode grids disagree with prefill KV.
Skip the encoder on decode only for processors with builds_epd_layout_from_media. Other architectures have no local layout equivalent to prefill, so they keep dispatching. Remove the now unused _decode_can_build_mm_locally and mm_tokens_match_data.
Lower the per-part RDMA logs to debug: they sit on the receive hot path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Signed-off-by: Liang Xiaoxia <liangxiaoxia@hygon.cn>
Co-authored-by: Liang Xiaoxia <liangxiaoxia@hygon.cn>
Co-authored-by: Claude <noreply@anthropic.com>
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.
动机
修复 N10 / 禅道 2816528:P 已与 D 握手但尚未完成 KV 发送时取消请求,D 可能一直等到 waiting 超时。本 PR 让等待、bootstrap、inflight、运行中和 chunked 请求进入可重试的安全清理流程。
修改
DRAINED_ABORT并释放资源;保留原取消原因并避免重复响应。request_status、transfer_infos和failure_records等活动状态;用最多 4096 条的终态记录处理晚到握手。TTL 为 bootstrap/waiting timeout 与 300 秒的最大值。终态握手收到通知后不再重建活动传输状态。部署要求
P、D 必须同时升级到支持四段
DRAINED_ABORT消息的版本。 旧 D 不支持该协议;本 PR 未增加能力协商。终态记录有 TTL 和容量上限,超出保留窗口的迟到握手仍由原超时机制收尾。验证
指定环境:
10.211.10.10/ Dockersglang0518_0920_yb,独立源码目录,未替换安装包或重启服务。test_external_kv_abort_drain.py27 passed、23 subtests passed。包含真实双 rank Gloo:rank 0 已排空、rank 1 未排空,两个 rank 都入队,均在第二轮统一移出;以及真实 clear 状态机后的晚到通知、TTL 到期、4096 条容量限制。test_mooncake_final_chunk_poll.py20 passed、10 subtests passed,覆盖多 rank 协议、晚到目标、发送失败后的目标保留与重试,以及真实 bootstrap 登记路径在通知被阻塞时另一线程仍能完成终态清理(活动 Failed 和终态两种情况)。git diff --check。完整 pre-commit 未执行。日志:
/stortest/zhy_spcae/fixbug/review-pr38-20261021/review3-lock38-ast.log;/stortest/zhy_spcae/fixbug/t01-session-rpc-20261021/review3-lock38-protocol.log。AI 辅助:Codex 实现、测试与差异自查;维护者人工 review 仍待完成。