Prhub

#30074 [refactor] Migrate the page_size resolution chain (stack 12/15)

原始 PR 作者 ch-wan 合并时间 2026-07-04 17:22 文件变更 5 提交数 1 评论 2 代码增减 +410 / -135

执行摘要

将 page_size 解析迁移至声明式 override 系统

在15步重构栈中,逐步将集中式条件逻辑迁移到声明式覆盖系统。PR #30074 聚焦 page_size 字段,它受多种因素影响:平台默认值、DLLM 块大小对齐、后端约束(FlashMLA/TRTLLM/FA4等)以及特定模型的 attention 后端选择。PR body 描述了“back-to-front”的顺序:先处理平台默认和 DLLM 对齐(这两个最后写入者),然后处理兼容性 handler 的八个后端 page snap,最后处理两个一体式写入者(Qwen3.5 hybrid 和 Qwen3VL aiter)。

值得精读。此 PR 展示了如何将大段条件逻辑安全地重构为声明式 pass 链,是理解 SGLang 配置系统演进的关键 PR。特别关注 _qwen3_5_hybrid_overrides 中 attention_backend 与 page_size 的耦合声明,以及 _mla_backend_page_constraints 如何整合六个 MLA 族后端约束为单一 pass。

讨论亮点

审核机器人 chatgpt-codex-connector 在代码审查中指出,_qwen3_5_hybrid_overrides 中调用 ServerArgs._get_default_attn_backend 时传递了 hf_config 参数,但实际方法需要 model_config 参数。然而阅读最终合并的代码,发现实际传递的是 model_config=server_args.get_model_config(),因此该评论可能基于中间版本。未发现人类审核者对此进一步讨论。

实现拆解

  1. 标记 page_size 为 model_overridable:在 python/sglang/srt/server_args.py 中,将 page_size 字段的 Arg 添加 model_overridable=True,使其纳入覆盖白名单。对应的测试 test_server_args_whitelist_is_exactly_the_migrated_fields 更新期望列表,包含 "page_size"
  2. 在 overrides.py 中新增声明式 pass:在 python/sglang/srt/arg_groups/overrides.py 中添加多个后处理 pass 和架构特定 override:
    • _page_size_default:在 page_size 为 None 时填充平台默认值(非 HIP/MUSA 平台为 1,MUSA 为 64)。
    • _dllm_page_size:当启用了 DLLM 且未禁用 radix cache 时,根据 DLLM block_size 对齐 page_size。
    • _mla_backend_page_constraints:将 MLA/TRTLLM 后端对 page_size 的限制(flashmla → 64, cutlass_mla → 128 等)迁移为后处理 pass。
    • _fa4_page_constraint:当使用 FA4 后端时强制 page_size 为 128。
    • _intel_xpu_page_constraint:Intel XPU 特定约束。
    • _qwen3_5_hybrid_overrides:为 Qwen3.5 系列模型在 SM100 上根据 attention 后端决定 page_size(trtllm_mha → 64,其他 → 1),并耦合 attention_backend 声明。
    • _qwen3vl_overrides:为 Qwen3VL 在 HIP + aiter unified attention 时设置 page_size 为 16。
  3. 从 server_args.py 移除旧逻辑:在 _handle_model_specific_adjustments_handle_attention_backend_compatibility 中删除对应 page_size 的直接赋值,改为调用 override 系统(通过 apply_model_overridesrun_post_process_pass 集成)。同时调整了导入,将 is_sm100_supported 等依赖从 server_args 层移除。
  4. 在 runtime_context.py 添加 page_size 叶子:在 Flags 数据类中添加 page_size: int | None = None 字段,作为解析后的状态容器。
  5. 新增单元测试:在 test/registered/unit/test_model_overrides.py 中添加针对每个 pass 的独立测试,包括 test_page_size_default_passtest_dllm_page_size_passtest_page_size_leaf_materializes_end_statetest_qwen3_5_hybrid_coupled_declarationtest_qwen3vl_page_sizetest_page_constraint_passes_at_callable_level。在 test/registered/unit/server_args/test_server_args.py 中调整 mock patch 的路径以适应新的函数位置。
文件 模块 状态 重要度
python/sglang/srt/arg_groups/overrides.py 覆盖系统 modified 8.76
test/registered/unit/test_model_overrides.py 覆盖测试 modified 7.92
python/sglang/srt/server_args.py 参数解析 modified 7.31
python/sglang/srt/runtime_context.py 运行时状态 modified 4.35
test/registered/unit/server_args/test_server_args.py 参数测试 modified 3.43

关键符号

_qwen3_5_hybrid_overrides _qwen3vl_overrides _page_size_default _dllm_page_size _mla_backend_page_constraints _fa4_page_constraint _intel_xpu_page_constraint test_page_size_default_pass test_dllm_page_size_pass test_page_size_leaf_materializes_end_state test_qwen3_5_hybrid_coupled_declaration test_qwen3vl_page_size test_page_constraint_passes_at_callable_level

关键源码片段

python/sglang/srt/arg_groups/overrides.py core-logic

核心变更文件,新增所有声明式 pass 和架构特定 override,共 193 行新增逻辑。

@_register_for(
    "Qwen3NextForCausalLM",
    "Qwen3_5MoeForConditionalGeneration",
    "InternS2PreviewForConditionalGeneration",
    "Qwen3_5ForConditionalGeneration",
)
def _qwen3_5_hybrid_overrides(server_args: Any, hf_config: Any) -> dict:
    """Qwen3.5 系列模型在 SM100 上的 attention_backend 与 page_size 声明。    此 override 同时声明两个字段:attention_backend 和 page_size,因为它们的
    取值相互依赖(trtllm_mha 需要 page_size > 1,而 radix cache + 无 spec 场景
    迫使 page_size=1 从而回退到 triton)。
    """
    if not is_sm100_supported() or server_args.attention_backend is not None:
        # 非 SM100 或用户已显式设置 attention_backend,无需干预
        return {}
    sm100_default_attn_backend = "triton"
    # trtllm_mha 要求 speculative_eagle_topk == 1 且 page_size > 1
    default_attn_backend = server_args._get_default_attn_backend(
        use_mla_backend=server_args.use_mla_backend(),
        model_config=server_args.get_model_config(),
    )
    if default_attn_backend == "trtllm_mha" and not (
        not server_args.enable_mamba_extra_buffer()
        and not server_args.disable_radix_cache
        and server_args.speculative_algorithm is None
    ):
        # 当 radix cache 未禁用、或有 spec decoding、或 extra buffer 启用时,
        # 才可以使用 trtllm_mha(满足 page_size > 1 的条件)
        sm100_default_attn_backend = "trtllm_mha"
    return {
        "attention_backend": sm100_default_attn_backend,
        "page_size": 64 if sm100_default_attn_backend == "trtllm_mha" else 1,
    }
test/registered/unit/test_model_overrides.py test-coverage

主要测试文件,新增 184 行测试,覆盖每个 pass 的独立行为和端到端发布。

def test_page_size_default_pass(self):
    from sglang.srt.arg_groups.overrides import ResolvedView, _page_size_default
​
    # 用户显式设置了 page_size,pass 应返回空(不覆盖)
    self.assertEqual(
        _page_size_default(ResolvedView(SimpleNamespace(page_size=64))), {}
    )
    # 非 HIP 且非 MUSA 平台,默认填充为 1
    with patch.object(overrides_module, "is_hip", return_value=False):
        with patch.object(overrides_module, "is_musa", return_value=False):
            self.assertEqual(
                _page_size_default(ResolvedView(SimpleNamespace(page_size=None))),
                {"page_size": 1},
            )
        # MUSA 平台默认填充为 64
        with patch.object(overrides_module, "is_musa", return_value=True):
            self.assertEqual(
                _page_size_default(ResolvedView(SimpleNamespace(page_size=None))),
                {"page_size": 64},
            )

评论区精华

潜在关键字参数错误在 _qwen3_5_hybrid_overrides 正确性

chatgpt-codex-connector 指出调用 _get_default_attn_backend 时使用了 hf_config 参数,但方法接受 model_config。然而合并后的代码实际使用了 model_config,因此评论可能基于旧版本。

结论:代码已合并,实际实现无此问题;未在 PR 内进一步讨论。 · 已解决

风险与影响

主要风险在于声明式 pass 的执行顺序和条件逻辑的精确性。例如,_mla_backend_page_constraints 假设 view.page_size 已经包含之前 pass 的结果,如果顺序有误可能导致不一致。另外,_qwen3_5_hybrid_overrides 中的条件与 radix cache、spec decoding 交互复杂,测试覆盖了常见路径但可能有遗漏。server_args.py 中的删除操作可能遗漏了对其他平台的保护(如 Intel XPU 约束在新 pass 中是否正确?)。此外,page_size 叶子的添加在 runtime_context.py 是仅一行,但如果消费者未使用 flags 层而直接读取 ServerArgs.page_size,则可能得到原始未解析值。但通常消费者应在服务器初始化后使用 flags 层。

对用户无直接影响,因为 page_size 的配置语义保持不变。对系统,配置解析变得更模块化,便于后续扩展新约束。对开发团队,需要熟悉声明式 pass 的注册及调用顺序。测试覆盖显著提升,每个 pass 有独立单元测试,降低了回归风险。

核心配置逻辑迁移 声明式 pass 顺序依赖 复杂条件逻辑

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论