Skip to content

test: slim unit tests and repair chat logprob semantics - #1724

Closed
sufubao wants to merge 7 commits into
ModelTC:mainfrom
sufubao:test/slim-unit-tests-4000
Closed

sufubao wants to merge 7 commits into
ModelTC:mainfrom
sufubao:test/slim-unit-tests-4000

Conversation

@sufubao

@sufubao sufubao commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

unit_tests/ had grown to 68,253 lines, with cloned autotune cases, repeated
literal/default checks, structure-only assertions, timing loops, and a 4,000-line
smoke suite that dropped too many ownership and lifecycle regressions. This
corrects the first pass by retaining the critical failure surfaces and removing
only tests that duplicate an existing, stronger check or cover code with no
production call path.

The suite goes from 314 files / 68,253 lines to 233 files / 56,109 lines: 81 fewer
files and 12,144 fewer lines (17.8%). It is no longer constrained by the 4,000-line
cap. For context, a review comparison put upstream vLLM at about 26.1 unit-test
lines per product line and SGLang at about 24.2%; the corrected LightLLM suite is
about 39.1% by the same Python-line metric; it remains higher, reflecting retained
LightLLM-specific PD and hybrid-state boundaries.

Retained coverage includes:

  • attention-state ownership, storage, copy, quantized layouts, and lifetime;
  • PD export/import, page transfer, multiprocess lifecycle, HAProxy handling, and
    stop/error contracts;
  • radix-cache eviction, request/page ownership, cache placement, and PD queueing;
  • linear-attention/ReplaySSM, MTP state, MoE routing/numerics, and autotuner
    lifecycle;
  • GLM5, DeepSeek V4, SenseNova, DSPARK/EAGLE model boundaries, and KV transfer;
  • server core objects, API responses, start arguments, detokenization, and
    reasoning token accounting.

Removed coverage is limited to clones such as int4 autotune and int8 stage
localization, defaults already exercised through the production API, class
inheritance checks, unused moe_align variants, and redundant selector or
role-transfer combinations.

Review follow-up also repairs the chat-completion logprob path exercised by the
retained suite:

  • every model token keeps its own entry, score, candidate list, and raw bytes;
  • visible content and logprobs use the same parser and final trimming decision;
  • reasoning, Harmony headers/commentary, tool arguments, fallback text, and
    trailing visible text map only through parser-returned source spans;
  • sampled scores remain raw in shared memory and TGI, while rank is separate and
    only the Chat representation maps candidates outside rank 20 to -9999;
  • SentencePiece candidates use prompt context, and ByteLevel/ByteFallback tokens
    retain their original bytes;
  • non-finite logits, large token IDs, and PD first-token rank/candidates have
    dedicated regressions.

The retained suite was initially validated on one H200 with the isolated
dependency image in 24 fresh processes: 5,836 passed, 195 skipped, 0 failed.
The skips require optional prerequisites such as a second CUDA device, Neo FA3,
DeepEP, DeepSeek vision reference processors, or HAProxy.

Validation on review-follow-up head b183ec080:

  • full chat/message, sampling, PD state/notification/transport suite:
    256 passed, 2 skipped;
  • broad retained affected suite: 444 passed, 7 deselected; the exclusions are
    two known baseline caplog families;
  • complete stop/TGI suite: 135 passed;
  • repository-pinned Black 21.12b0, Flake8 6.1.0, Python compilation for changed
    files, and git diff --check pass.

This validates the affected paths on one GPU and the current dependency image. It
does not claim a new full-suite run after the follow-up, production-service,
model-serving, multi-node PD, or optional-provider acceptance.

@sufubao sufubao changed the title test: slim unit test suite test: remove redundant unit tests while retaining critical coverage Nov 13, 2026
@sufubao sufubao changed the title test: remove redundant unit tests while retaining critical coverage test: slim unit tests and repair chat logprob semantics Nov 13, 2026
@sufubao

sufubao commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator Author

已更新到 b183ec080,按审查结论改成 parser 返回保留源区间,不再依赖独立分隔符状态机。

  • 每个模型 token 独立保留条目、分数、候选和 bytes;空解码增量不再合并分数。
  • 正文、reasoning、Harmony、工具 JSON、解析失败回退和最终裁剪走同一次解析结果。
  • sampled score 保持原始值,rank 独立传递;TGI 继续按真实 cumlogprob 选择 beam,-9999 只在 Chat 输出映射。
  • 候选按 tokenizer/decoder 和 prompt/pending 上下文解码,覆盖 ByteLevel、ByteFallback 与 SentencePiece 前导空格。
  • 自审补充了非有限 logits、大 token ID,以及 PD 首 token rank/候选跨 P→D 传递。

验证:完整 chat/sampling/PD 组合 256 passed, 2 skipped,保留相关面 444 passed, 7 deselected(仅两个已知 baseline caplog 家族),完整 stop/TGI 135 passed;固定版本 pre-commit 与 git diff --check 通过。

真实模型 tokenizer、真实 MTP、多机 PD 和可选 provider 仍未在本次跟进中跑端到端。

@sufubao sufubao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

结论:建议修改(request changes)。

审查到 b183ec080。logprob 主路径本身没有发现阻塞性错误,新增及保留的焦点测试也通过;阻塞点在“瘦身”实际删掉了远超描述范围的既有回归,其中多处是仍在生产调用的路径的唯一单测。

1. DeepSeek V4 paged cache 回归删得过多(高)

unit_tests/common/test_deepseek4_paged_cache.py 从 2,061 行、34 个 test 降到 433 行、5 个 test。被删的不只是参数组合,还包括独立的生命周期/边界:

  • SWA ring attention 在 speculative retry 后与完整 cache 对齐;
  • compressor checkpoint 续写与 full prefill 对齐;
  • hybrid radix hit/fork/pause/abort/eviction;
  • C4 indexer page table、metadata scoring 与 graph replay;
  • indexer 只写 closed group、prefill chunk 保留全部新 SWA 行;
  • PD transport completion 覆盖 peer GPU state,以及 CUDA Graph 读取更新后的 private page。

建议至少恢复 test_compressor_checkpoint_continuation_matches_full_prefill、test_swa_ring_attention_matches_full_cache_after_speculative_retries、test_hybrid_radix_hit_fork_pause_abort_and_eviction、test_c4_indexer_metadata_scoring_and_graph_replay、test_pd_transport_completion_covers_peer_gpu_state。

2. 生产 kernel 变成零直接单测(高)

删掉后,以下仍有生产调用点的 kernel 在 unit_tests/ 中已没有任何直接引用或断言:

  • gen_decode_params.py、gen_prefill_params.py、gen_sampling_params.py;
  • sp_pad_copy.py(base_layer_infer / Gemma4);
  • routing_capture.py(MoE routed-expert 回传);
  • copy_kv_index_to_req.py。

这些不是 autotune 克隆。尤其 gen_* 决定 attention 的 cumsum、position 和 sampling batch 参数,sp_pad_copy 决定 TP padding 布局;现有模型测试没有断言这些布局/边界契约。建议恢复对应的小测试,而不是依赖间接 import。

3. 多模态分块和 tokenizer 位置覆盖被整片删除(中)

lightllm/utils/multimodal_chunk_utils.py 有 infer_batch、radix cache、multi-level cache 四个生产消费者,但 test_multimodal_chunk_utils.py 被整文件删除;test_multimodal_tokenizer_positions.py 也删除了全部多模态 tokenizer 的最终位置断言。该类错误会直接切裂 image/audio block,且不是普通文本 cache 测试能覆盖的。

4. 同一 PR 重写 parser,却删除了全部既有 streaming tool 测试(中)

test_function_call_common_prefix.py、test_deepseek_tool_parser_stream.py、test_qwen3_coder_stream_fc.py、test_glm47_tool_parser.py 全删。新 logprob 测试主要覆盖单个短 tool call,缺少长参数、多 delta、多个 invoke 和多 tool 的契约。把这些测试放回当前 head 仍有 54 个通过,说明它们不是失效/重复测试。

5. README 的全量运行方式不完整(低)

unit_tests/README.md 只写 python -m pytest <paths>。直接运行 python -m pytest unit_tests 会因重复 basename 产生 3 个 collection error;需要 --import-mode=importlib。建议在 README 或 CI 命令中写明。

独立验证

  • test_chat_output_logprobs.py + test_sampling.py:190 passed。
  • test_stop_sequence_output.py + test_deepseek4_paged_cache.py:140 passed。
  • 代表性已删测试放回 head 运行:parser/kernel/multimodal 54 passed,tokenizer 22 passed,grammar 59 passed。
  • 额外探测了 tool markup 后接正文、长 tool 参数后接正文、两个 tool call、tool 截断 flush、reasoning 前缀等组合,logprob 与可见文本一致。
  • git diff --check 通过。
  • 全量单进程(现有 lightllm_dev 镜像):5705 passed、155 skipped、352 failed、5 errors(其中 4 个是我临时 probe 的 trio 缺失)。失败集中在现有镜像较旧的 flashinfer/flash_attn 签名(如缺 ckv_scale_arr、only_qv)和跑序相关;test_glm5_next/test_pd_cache.py 单独运行 410 passed。未在作者的隔离镜像上复现 0 failed。

除此之外,logprob 的 span 归属、raw score/rank 分离、PD 首 token 传递和 SHM 边界实现未发现功能性问题。

@sufubao sufubao closed this Nov 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant