Prhub

#34266 config: the alias form of the runner-side instance read

原始 PR 作者 ch-wan 合并时间 2026-08-15 15:39 文件变更 18 提交数 1 评论 13 代码增减 +319 / -147

执行摘要

别名形式 server_args 读取全部迁移到配置 bag,新增派生访问器

PR body 明确指出:上一个批次只统计了 self.server_args.X,便声称 runner 表面已迁移完毕,但同样的读取通过局部别名拼写(server_args = model_runner.server_args 后接 server_args.leaf)时,grep 看不到;AST 普查在 11 个文件中共找出 57 处此形式读取。目标是让所有进程级配置读取统一走已发布的 bag,使 post-publish override 语义一致,并为后续 step-12 的迁移与盯测(ratchet)提供准确基线。

值得精读。这是理解 SGLang runtime context 配置迁移(step-12 系列)如何系统性收口 runner 侧读取面的关键 PR,尤其推荐关注三处:bag 访问器与 ServerArgs 成员的等价性如何由测试盯测;GDN 发布后读回导致幂等性破坏的根因与修复方式;以及 configured_pp_size() 这类“配置值 vs 活拓扑”的取舍与 ratchet 登记。

讨论亮点

Codex 评审捕获了本 PR 中两个最关键的语义回归:一是 GDN 自动默认值在 TBO 多副本下失去幂等性——将 guard 改成读取 bag 叶子后,函数自身发布的自动默认值被读回为“已配置”,导致后续副本跳过默认值并回退 Triton;二是 dispatch_event_loop 改用 get_parallel().pp_size 后,MLX stub 因从不初始化 torch.distributed 而直接触发断言。两个问题均在合入前修复并补充测试。作者自审还发现 SWAChunkCap 的 spec decode 分配尺寸仍从 handed record 读取,与 bag 守卫存在 override 可见性不一致,于是将 spec_decode_alloc_len_per_request 改为纯关键字入参。测试侧则统一了 per-case publish + addCleanup 的恢复模式,避免 last-publish-wins 污染同进程后续用例。

实现拆解

  1. AST 普查与分类:对 11 个文件中的别名读取逐函数计数,52 处为叶子读取(spec 11、schedule 9、memory 7、exec.graph 5、exec.moe 5、parallel 4、disagg 4、model 3、exec.mamba 2、exec.overlap 2),5 处为非叶子(3 个派生成员、get_attention_backends()、以及一个只重名的 server_args_dict)。
  2. 叶子读取迁移:将别名转换为对应 bag 访问器。典型如 pool_configurator.py 的 SWAChunkCapPoolConfigurator 构造函数,sa.speculative_algorithm 等改为 get_spec() / get_schedule() / get_disagg() / get_memory();flashinfer_autotune.py 的开关与 MoE backend 字符串改为 get_exec().kernel / get_exec().deterministic / get_exec().moe / get_spec();flashattention_backend.py 的 seed 读取与 fa_skip_kv_cache 判断改为 get_spec() / get_exec() / get_model() / get_schedule() / get_memory()。
  3. 派生成员与访问器收口:runtime_context.py 新增 max_prefill_buffer_tokens() 访问器,由 schedule 叶子与 configured PP 大小推导;eager_runner.py 改用 max_speculative_num_draft_tokens()、mamba_extra_buffer_enabled()、max_prefill_buffer_tokens()、get_parallel().dp_size;attention_backend_setup.py 的 build_attention_backends 与 resolve_attention_backend_strs 改为读 attention_backends() 与 get_disagg() / get_exec()。
  4. 两项语义修正:GDN 自动默认值改为让 initialize_linear_attn_config 也读 bags,使默认值经已发布 override 传播并在 TBO 三次副本初始化中幂等;dispatch_event_loop 三个 PP 分支改用 configured_pp_size(),避免 MLX stub 未初始化 torch.distributed 时触发实际拓扑属性断言。
  5. 测试与盯测配套:test_pool_configurator.py、test_registry.py、test_gdn_prefill_backend_policy.py 由灌注 SimpleNamespace / MagicMock record 改为 per-case override_server_args + addCleanup 恢复;test_runtime_context.py 新增对 max_prefill_buffer_tokens() 的 48 case 派生断言;test_global_config_read_ratchet.py 登记 configured_pp_size() 等新调用点,exposure ratchet 同步移除已消失的读取对。
文件 模块 状态 重要度
python/sglang/srt/runtime_context.py 配置访问 modified 7.23
python/sglang/srt/model_executor/pool_configurator.py 池配置器 modified 7.07
python/sglang/srt/layers/attention/flashattention_backend.py 注意力后端 modified 6.95
python/sglang/srt/model_executor/runner/flashinfer_autotune.py 自动调优 modified 6.97
python/sglang/srt/managers/scheduler.py 调度器 modified 6.41
python/sglang/srt/utils/common.py 公共工具 modified 6.56
python/sglang/srt/model_executor/runner/eager_runner.py 执行器 modified 6.59
test/registered/unit/model_executor/test_pool_configurator.py 池配置测试 modified 5.97
test/registered/unit/test_runtime_context.py 配置访问测试 modified 4.98

关键符号

max_prefill_buffer_tokens spec_decode_alloc_len_per_request _should_disable_scheduler_metadata_precompute should_run_flashinfer_autotune build_attention_backends dispatch_event_loop

关键源码片段

python/sglang/srt/runtime_context.py dependency-wiring

配置 bag 访问器的核心载体,新增 max_prefill_buffer_tokens() 派生访问器,把 schedule 叶子与 configured PP 大小统一为可被 override 的单一数据源。

def max_prefill_buffer_tokens() -> int:
    """The prefill-buffer ceiling: chunked_prefill_size, except PP dynamic
    chunking can grow chunks toward max_prefill_tokens and probe at 1.25x.
    该访问器完全从已发布的 bag 推导,因此会跟随 post-publish override。
    """
    import math
​
    schedule = get_schedule()
    chunked = (
        schedule.chunked_prefill_size
        if schedule.chunked_prefill_size and schedule.chunked_prefill_size > 0
        else 0
    )
    tokens = chunked
    if (
        schedule.enable_dynamic_chunking
        and _configured_parallel("pp_size") > 1 # 配置值而非活拓扑,MLX 场景安全
        and chunked
    ):
        # PP 动态分块时,chunk 可向 max_prefill_tokens 增长并上探 1.25x
        tokens = max(
            tokens, schedule.max_prefill_tokens or 0, math.ceil(chunked * 1.25)
        )
    return tokens
python/sglang/srt/model_executor/runner/flashinfer_autotune.py data-contract

flashinfer 自动调优的开关、确定性门控与 MoE backend 字符串从 server_args 改为 exec / spec bag,注释同步更新以标明数据来源。

def should_run_flashinfer_autotune(
    model_runner: ModelRunner, *, for_speculative_draft: bool = False
) -> bool:
    """Check if flashinfer autotune should be run."""
    mr = model_runner
    if mr.device != "cuda":
        return False
    # 开关型叶子改从 exec bag 读取,行为与 server_args 等价
    if get_exec().kernel.disable_flashinfer_autotune:
        return False
    if get_exec().deterministic.enable_deterministic_inference:
        # 确定性模式下不调优:tuned configs 按问题 shape 变化,会破坏归约顺序
        return False
​
    if for_speculative_draft:
        # draft 侧叶子走 get_spec(),target 侧叶子走 get_exec().moe
        backend_str = (
            get_spec().speculative_moe_runner_backend
            or get_exec().moe.moe_runner_backend
        )
        a2a_backend_str = (
            get_spec().speculative_moe_a2a_backend
            or get_exec().moe.moe_a2a_backend
        )
    else:
        backend_str = get_exec().moe.moe_runner_backend
        a2a_backend_str = get_exec().moe.moe_a2a_backend
​
    # CuteDSL v1 绕过 MoeRunner,其 dummy dispatch 可能超过 DeepEP 低延迟上限
    if backend_str == "flashinfer_cutedsl" and a2a_backend_str == "deepep":
        return False
​
    moe_needs_autotune = backend_str in [
        "flashinfer_trtllm",
        "flashinfer_trtllm_routed",
        "flashinfer_mxfp4",
        "flashinfer_cutedsl",
        "flashinfer_cutlass",
    ]
    ...

评论区精华

GDN 自动默认值在 TBO 多副本下失去幂等性 正确性

Codex P2 指出:guard 改为读 bag 叶子后,函数自身发布的自动默认值 gdn_backend.sm100_flashinfer_default 被读回为“已配置”;TboAttnBackend 三次调用 backend creator,后续副本跳过默认值,initialize_linear_attn_config(仍读 record)对执行拆分 prefill 批次的子对象回退到 Triton 基础后端。

结论:将 initialize_linear_attn_config 的投影也改为读 bags 并移除参数,默认值经已发布 override 传播,所有副本落到同一值;test_linear_attn_config.py 改为 publish 并固定三次连续初始化仍保持 flashinfer。 · 已解决

MLX 事件循环调度读取实际 PP 大小导致断言崩溃 正确性

Codex P1 指出:MlxModelRunnerStub 从不初始化 torch.distributed,get_parallel().pp_size 会触发 get_pp_group() 断言,pp_size=1 的 MLX 服务也会在事件循环调度阶段失败。

结论:dispatch_event_loop 三个 PP 分支全部改用 configured_pp_size() 读取配置叶子,并在 _CONFIGURED_SIZE_CALL_SITES 登记理由;ratchet 机制捕获了未登记的首版实现。 · 已解决

SWAChunkCap 的 spec decode 分配尺寸仍来自 handed record 设计

作者自审:decode_alloc 仍经 spec_decode_alloc_len_per_request(sa) 与 get_alloc_len_per_decode(sa) 读取原始 record,post-publish override 会让 bag 守卫与分配长度不一致,属 override 可见性债务。

结论:spec_decode_alloc_len_per_request 改为纯关键字入参并全部取 get_spec() 叶子;spec-v2 路径读取 max_speculative_num_draft_tokens();sa = kvc.server_args 绑定从文件移除。 · 已解决

测试夹具发布后的恢复模式 测试

review 指出模块级 _PUBLISHED + install() 依赖 last-publish-wins 与 LIFO tearDownModule,失败用例可能给同进程后续文件留下部分 publish 污染,偏离 runtime-context skill 推荐的 with override_server_args 形态。

结论:三个套件(GDN prefill policy、cache registry、pool configurator)统一改为 per-case _publish(testcase, **fields) + addCleanup(override.restore),sps-table 套件同步采用相同形态。 · 已解决

过时注释清理 documentation

flashinfer_autotune.py 注释仍写“read the target or draft backend from server_args”,metrics_reporter.py 注释仍写“Fallback to server_args”,与实际改用 get_spec() / get_exec().moe 的代码不符。

结论:两处注释均已更新,分别标明从 spec bag / exec.moe 叶子读取与回退到已发布 spec bag。 · 已解决

风险与影响

风险集中在配置语义与启动路径:

1) dispatch_event_loop 改用 configured_pp_size() 后,若实际拓扑与配置值在动态场景下不一致,事件循环选择可能与真实并行组不符(当前预期二者一致,但需关注未来动态并行);
2) GDN 自动默认值的正确性依赖发布 override 的传播时序,initialize_linear_attn_config 与 backend 副本之间的读取顺序若被后续改动打破,可能再次出现 Triton/FlashInfer 回退不一致;
3) 测试夹具改为全局限定 override 后,同进程内其他测试在窗口期会观察到被覆盖的配置值,虽有 addCleanup 兜底,但仍属共享可变状态;
4) flashattention_backend.py 与 eager_runner.py 位于模型初始化与 CUDA graph 捕获核心路径,任何 bag 叶子与 ServerArgs 成员的不等价都会直接改变缓冲尺寸或确定性开关。

影响面覆盖模型启动、内存池/SWA 池尺寸、flashinfer 自动调优、CUDA graph 捕获批次选择、事件循环调度与 GDN 后端选择,属于核心运行路径的配置读取面重构。对用户默认行为保持等价(作者验证 Qwen3-Next GDN 启动与 base 字节一致),但为后续 post-publish override 与配置迁移提供了统一基线。对团队而言,该 PR 确立了几项可复用模式:别名读取普查方法、派生访问器 + TestDerivedPredicatesAgreeAcrossTiers 盯测、configured_pp_size() 调用点 ratchet 登记,以及测试夹具 per-case publish 恢复范式。

核心路径变更 配置语义迁移 测试全局状态隔离 启动路径依赖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论