Prhub

#50175 [1/N][warmup][DSv4] Migrate generic MLA metadata and indexing kernels

原始 PR 作者 LopezCastroRoberto 合并时间 2026-09-01 11:26 文件变更 17 提交数 10 评论 31 代码增减 +1269 / -625

执行摘要

DSv4 MLA 元数据内核迁移至共享 JIT warmup 契约

目标来自 Issue #49349「Zero JIT compilation during runtime」:把内核编译全部前移到启动期 warmup,使模型能在 --jit-monitor-mode error 下无任何运行时 JIT。本 PR 是 DSv4 模型 de-JIT 化的 1/N 拆分之一,负责迁移「generic MLA metadata and indexing kernels」。旧实现(vllm/model_executor/warmup/sparse_mla_triton_warmup.py)在 worker 上按 attention backend 名称探测后手工调用各内核 warmup,代表性形状写死在外部函数里,内核自身不掌握自己的编译键空间。PR body 明确列出新方案要点:迁移 sparse-MLA 元数据与索引转换内核、迁移 prefill chunk 元数据与 top-k/SWA 组合内核、用 kernel-owned traced dispatch spaces 取代外部代表性形状循环、只注册激活后端选中的 warmup provider。

值得精读。核心看三点:VllmTritonJitKernel + kernel_launcher 的「预热即假启动」设计(运行时 launch 规格是唯一事实来源,避免 launch 与 warmup 参数漂移);triton_scalar_specialization_rep 对 Triton 标量特化类(exact-one / divisible-by-16 / generic)的处理;zip_inputs + _trace_dispatch 对编译键空间的声明式枚举。评审对话本身也是很好的教材:三处「预热变体不可达」说明编译键必须覆盖运行时真实特化类。若团队要迁移其他 Triton 内核,建议先读 jit_warmup_triton_helper.py 与本 PR 的 review 记录。

讨论亮点

评审由维护者 LucasWilkinson 主导,多线程为 blocking 级,核心交锋如下:

  • LucasWilkinson 在 indexer.py 指出 grid 尺寸改变导致越界读:“The call site passes the full decode_seq_lens_buffer (allocated at max_num_batched_tokens), so this grid launches the buffer capacity, not the batch... Padding programs compute req_id = idx // max_decode_len past the real batch and read seq_lens/block_table rows out of bounds.” 作者以显式 num_decode_tokens 参数修正(“Runtime count is explicit now and drives the grid.”)。

  • 最大的一类问题被归纳为「预热变体不可达」:CompressedSlotMappingKernel 传字面量 1,命中的是 Triton 的 exact-one 特化类,而运行时值落在 divisible-by-16 类,等于白编译。同样的问题出现在 ConvertReqIndexToGlobalIndexKernel 的 constexpr max_num_blocks_per_req:“It's only a bounds check — suggest demoting it to a do_not_specialize runtime arg.” 两处均按建议修复。

  • _COMBINE_TOPK_SWA_INDICES_KERNEL 覆盖丢失:“The deleted sparse_mla_triton_warmup.py also warmed _COMBINE_TOPK_SWA_INDICES_KERNEL; nothing registers it after this PR, so it JITs at first use.” Lucas 建议统一 register_dsv4_sparse_warmups() 辅助函数防两处注册漂移;作者补回覆盖但明确不采纳统一 helper:“The migrated kernels are not exclusively DSv4-owned, and different backends require different subsets.”

  • update_draft_decode_metadata 的语义变化:用 self.window_size 取代 decode_swa_indices.shape[-1],Lucas 提醒 DSpark 非因果缓冲宽度是对齐后的 window+spec,行尾可能残留 stale indices;此线程在材料中未见作者明确回复,属遗留确认项。

  • malaiwah 在 Issue 评论中给出 fresh-cache 校验结论:BuildPrefillChunkMetadataKernel 仍会逐 worker 编译一次,需把 query_slice_start/stop 与 DCP 参数标记 do_not_specialize,并用一次真实一行执行填充进程内 JITFunction.run cache;修复在独立 review branch,未并入本 PR。

  • 设计取舍:Lucas 建议 get_warmup_keys(self, vllm_config) 统一契约以省去 signature sniffing;作者反驳“Some kernels need no configuration... adds unused-argument boilerplate”;Lucas 最终认同“lets ignore this”。另外 lucas 建议把无调用方的 jit_warmup_cutedsl_helper.py 移出本 PR,最终文件清单已无该文件。

实现拆解

整个迁移分 5 步推进:

  1. 扩展共享预热基建。vllm/model_executor/warmup/jit_warmup_triton_helper.py 新增 VllmTritonJitKernel 基类(约 +90 行):抽象方法 warmup_inputs(compile_key) 返回能复现该编译键的输入;compile() 置 _warming 标志后走真实 call,launch() 依据标志路由到 kernel.warmup(grid=(1,)) 做纯编译期代码生成。配套新增 kernel_launcher 装饰器与 LaunchSpec 类型,让 call 只声明 grid 与 launch kwargs;TritonWarmupTensor 增加 strides 字段以模拟非紧凑/转置张量布局。vllm/model_executor/warmup/jit_warmup.py 的 registry.warmup() 改为用 inspect.signature 探测 get_warmup_keys 是否需要参数、按需注入 vllm_config,从而支持 config-free 内核;kernel_warmup.py 移除对已删除文件的 import。

  2. 迁移四个 MLA 内核模块为自描述内核。sparse_utils.py(+370/-173):ConvertReqIndexToGlobalIndexKernel 的 max_num_blocks_per_req 由 tl.constexpr 降为 do_not_specialize 运行时参数,避免按 block-table 宽度无限重编译;get_warmup_keys 用 zip_inputs 枚举 5 个变体(prefill workspace、count_valid、DCP size/rank/interleave、compact_to_front);warmup_inputs 为 token_indices/out 显式提供 (16, 1) 步长以匹配分页缓存布局;valid_counts 分配恢复 single-tile 用 torch.empty、multi-tile 用 torch.zeros 的分支。compressor_utils.py(+125/-40):CompressedSlotMappingKernel 的 block_table_stride 进 do_not_specialize,block_size 用 triton_scalar_specialization_rep 代表值,压缩比列表合并 hf_config.index_kpool,无大于 1 的压缩比时返回空 key 列表跳过预热。indexer.py(+163/-101):PrepareUniformDecodeKernel 增加显式 num_decode_tokens 驱动 grid(修复按 buffer 容量 over-launch 的越界读),BuildPrefillChunkMetadataKernel 编译键只保留算法维度(block size、压缩比、指针对齐),query_slice 与 DCP 参数走特化类代表值。sparse_swa.py(+304/-155):ComputePrefillMetadataKernel 与 ComputeSWAIndicesAndLensKernel 迁移,window_size/block_size 编译键从 vllm_config 取值,调用点改用命名参数 num_tokens=/token_offset=,并新增 _COMPUTE_DSPARK_NONCAUSAL_SWA_INDICES_KERNEL 包装。

  3. 注册点迁移到模型构造处并删除外部编排。删除 vllm/model_executor/warmup/sparse_mla_triton_warmup.py(-111 行)。vllm/models/deepseek_v4/attention.py 的 DeepseekV4Attention.init 与 vllm/model_executor/layers/attention/mla_attention.py 的 MLAAttention.init/bind_kv_cache 在 enable_jit_warmup 下按激活后端注册对应 provider;block_stride_rows 依赖真实 KV-cache stride,故放到 bind_kv_cache 中注册。review 中补回了 _COMBINE_TOPK_SWA_INDICES_KERNEL 的注册。

  4. runner 集成。vllm/v1/worker/gpu/model_runner.py 与 vllm/v1/worker/gpu_model_runner.py 把 load_model 与 initialize_kv_cache 包进 jit_warmup_registry.activate() 上下文,让模型构造与 KV-cache 分配期间产生的注册被 registry 收集。

  5. 测试与文档配套。tests/v1/attention/test_indexer_deepseek_v4_slot_mapping.py 新增 test_compressed_slot_mapping_warmup_includes_index_kpool 与 test_index_conversion_warmup_uses_physical_block_stride;tests/model_executor/test_jit_warmup.py 新增 test_registry_default_request_supports_config_free_kernel;test_gpu_model_runner_v2_eplb.py、test_fused_shared_expert.py 做 enable_jit_warmup 相关适配;docs/contributing/jit_kernel_warmup.md 更新注册示例(内部单例统一下划线命名)。

文件 模块 状态 重要度
vllm/v1/attention/backends/mla/sparse_swa.py SWA 内核 modified 8.84
vllm/v1/attention/backends/mla/sparse_utils.py 索引内核 modified 8.65
vllm/model_executor/warmup/jit_warmup_triton_helper.py 预热基建 modified 8.55
vllm/v1/attention/backends/mla/compressor_utils.py 压缩映射 modified 8.52
vllm/v1/attention/backends/mla/indexer.py 索引器 modified 8.51
vllm/model_executor/warmup/sparse_mla_triton_warmup.py 预热编排 removed 8.7
vllm/models/deepseek_v4/attention.py DSv4 模型 modified 6.97
vllm/model_executor/layers/attention/mla_attention.py MLA 层 modified 6.95
vllm/model_executor/warmup/jit_warmup.py 预热注册表 modified 5.6
vllm/v1/worker/gpu/model_runner.py 运行器 modified 6.1
vllm/v1/worker/gpu_model_runner.py 运行器 modified 5.78
vllm/model_executor/warmup/kernel_warmup.py 预热基建 modified 4.88
tests/v1/attention/test_indexer_deepseek_v4_slot_mapping.py 索引测试 modified 6.19
tests/model_executor/test_jit_warmup.py 预热测试 modified 6.31
tests/v1/worker/test_gpu_model_runner_v2_eplb.py 运行器测试 modified 3.8
tests/model_executor/layers/test_fused_shared_expert.py 融合专家测试 modified 3.29
docs/contributing/jit_kernel_warmup.md 文档 modified 2.73

关键符号

VllmTritonJitKernel.compile VllmTritonJitKernel.launch kernel_launcher ConvertReqIndexToGlobalIndexKernel.dispatch ConvertReqIndexToGlobalIndexKernel.get_warmup_keys ConvertReqIndexToGlobalIndexKernel.warmup_inputs CompressedSlotMappingKernel.dispatch CompressedSlotMappingKernel.get_warmup_keys CompressedSlotMappingKernel.warmup_inputs PrepareUniformDecodeKernel.get_warmup_keys BuildPrefillChunkMetadataKernel.get_warmup_keys ComputePrefillMetadataKernel.warmup_inputs ComputeSWAIndicesAndLensKernel register_warmup JitWarmupRegistry.warmup

关键源码片段

vllm/v1/attention/backends/mla/sparse_utils.py core-logic

最大改动文件(+370/-173):ConvertReqIndexToGlobalIndexKernel 迁移,max_num_blocks_per_req 降为 do_not_specialize 运行时参数,get_warmup_keys 以 zip_inputs 枚举 5 个 DCP/prefill 变体,warmup_inputs 显式模拟分页步长。

    def get_warmup_keys(
        self,
        vllm_config: VllmConfig,
        *,
        block_stride_rows: int,
    ) -> list[CompileKey]:
        # 编译键空间由运行时配置推导,取代旧实现里写死的外部“代表性形状”循环:
        # block size、DCP 参数、index_topk、block-table 宽度全部来自 vllm_config。
        block_size = vllm_config.cache_config.block_size
        dcp_size = vllm_config.parallel_config.decode_context_parallel_size
        dcp_interleave = vllm_config.parallel_config.cp_kv_cache_interleave_size
        dcp_rank = get_dcp_group().rank_in_group if dcp_size > 1 else 0
        num_topk_tokens = vllm_config.model_config.hf_config.index_topk
        max_num_blocks = cdiv(
            vllm_config.model_config.max_model_len,
            block_size * dcp_size,
        )
        max_num_blocks_per_req = get_block_table_width(max_num_blocks, block_size)
        # zip_inputs 对 5 个“语义变体”做笛卡尔积式的组合枚举:
        # prefill workspace / count_valid / DCP 过滤与紧凑化是正交的算法分支。
        return self._trace_dispatch(self.dispatch)(
            zip_inputs(
                dict(HAS_PREFILL_WORKSPACE=False, COUNT_VALID=False,
                     COMPACT_TO_FRONT=False, DCP_SIZE=1, DCP_RANK=0, DCP_INTERLEAVE=1),
                dict(HAS_PREFILL_WORKSPACE=False, COUNT_VALID=True,
                     COMPACT_TO_FRONT=False, DCP_SIZE=1, DCP_RANK=0, DCP_INTERLEAVE=1),
                dict(HAS_PREFILL_WORKSPACE=True, COUNT_VALID=True,
                     COMPACT_TO_FRONT=False, DCP_SIZE=1, DCP_RANK=0, DCP_INTERLEAVE=1),
                dict(HAS_PREFILL_WORKSPACE=False, COUNT_VALID=True,
                     COMPACT_TO_FRONT=False, DCP_SIZE=dcp_size,
                     DCP_RANK=dcp_rank, DCP_INTERLEAVE=dcp_interleave),
                dict(HAS_PREFILL_WORKSPACE=False, COUNT_VALID=True,
                     COMPACT_TO_FRONT=dcp_size > 1, DCP_SIZE=dcp_size,
                     DCP_RANK=dcp_rank, DCP_INTERLEAVE=dcp_interleave),
            ),
            BLOCK_SIZE=block_size,
            BLOCK_STRIDE_ROWS=block_stride_rows,
            BLOCK_N=128,
            NUM_TOPK_TOKENS=num_topk_tokens,
            max_num_blocks_per_req=max_num_blocks_per_req,
        )
​
    def warmup_inputs(self, compile_key: CompileKey) -> dict[str, Any]:
        int32_ptr = TritonWarmupTensor(torch.int32)
        token_shape = (1, compile_key.num_topk_tokens)
        # token_indices / out 显式给出 (16, 1) 步长:运行时张量是分页布局,
        # 若按紧凑布局推断,Triton 指针特化键会与真实启动不一致,预热即失效。
        token_strides = (16, 1)
        return dict(
            req_id=int32_ptr,
            block_table=TritonWarmupTensor(
                torch.int32,
                shape=(1, compile_key.block_table_stride),
            ),
            token_indices=TritonWarmupTensor(
                torch.int32, shape=token_shape, strides=token_strides,
            ),
            out=TritonWarmupTensor(
                torch.int32, shape=token_shape, strides=token_strides,
            ),
            valid_counts=int32_ptr if compile_key.count_valid else None,
            prefill_workspace_request_ids=(
                int32_ptr if compile_key.has_prefill_workspace else None
            ),
            prefill_workspace_starts=(
                int32_ptr if compile_key.has_prefill_workspace else None
            ),
            # max_num_blocks_per_req 已是 do_not_specialize 运行时参数,
            # 值本身不参与编译键,这里给 1 即可。
            max_num_blocks_per_req=1,
            BLOCK_SIZE=compile_key.block_size,
            BLOCK_STRIDE_ROWS=compile_key.block_stride_rows,
        )
vllm/model_executor/warmup/jit_warmup_triton_helper.py data-contract

整个迁移的契约核心:新增 VllmTritonJitKernel 基类、kernel_launcher 装饰器、LaunchSpec 类型,TritonWarmupTensor 增加 strides 支持;后续所有 Triton 内核迁移都依赖此文件。

class VllmTritonJitKernel(VllmJitKernel[CompileKeyT], Generic[CompileKeyT]):
    """Triton 内核的共享 JIT 预热契约:用“假启动”代替手工 warmup 调用。"""
​
    kernel: ClassVar[Any]
    _warming = False
​
    @abstractmethod
    def warmup_inputs(self, compile_key: CompileKeyT) -> dict[str, Any]:
        # 子类负责为每个 CompileKey 给出能复现该编译键的输入:
        # 张量用 TritonWarmupTensor 描述符代替,标量用特化类代表值。
        raise NotImplementedError
​
    def compile(self, compile_key: CompileKeyT) -> None:
        # 预热 = 带着 fake 输入走一遍真实的 __call__。_warming 标志让
        # launch() 路由到 kernel.warmup(grid=(1,)):只做编译期类型推导
        # 与代码生成,不真正启动 grid,因此不需要真实显存与真实 batch。
        inputs = self.warmup_inputs(compile_key)
        self._warming = True
        try:
            cast(Callable[..., None], self)(**inputs)
        finally:
            self._warming = False
​
    @cached_property
    def _kernel_param_names(self) -> frozenset[str]:
        # 调用侧惯用不带 _ptr 后缀的名字(如 seq_lens),launch() 据此
        # 把实参自动映射到 Triton 形参(seq_lens_ptr)。
        return frozenset(self.kernel.arg_names)
​
    def launch(
        self,
        grid: tuple[int, ...],
        inputs: Mapping[str, Any],
        /,
        **kwargs: Any,
    ) -> Any:
        for name, value in inputs.items():
            target = name if name in self._kernel_param_names else f"{name}_ptr"
            if target in self._kernel_param_names and target not in kwargs:
                kwargs[target] = value
        if self._warming:
            warmup = getattr(self.kernel, "warmup", None)
            assert warmup is not None
            return warmup(grid=(1,), **kwargs)
        return self.kernel[grid](**kwargs)
​
​
def kernel_launcher(
    call_fn: Callable[..., LaunchSpec],
) -> Callable[..., None]:
    """把声明式的 __call__(返回 grid + launch kwargs)包装成统一启动入口。"""
    signature = inspect.signature(call_fn)
​
    @wraps(call_fn)
    def wrapper(
        self: VllmTritonJitKernel[Any],
        *args: Any,
        **kwargs: Any,
    ) -> None:
        grid, launch_kwargs = call_fn(self, *args, **kwargs)
        bound = signature.bind(self, *args, **kwargs)
        bound.apply_defaults()
        inputs = {
            name: value for name, value in bound.arguments.items() if name != "self"
        }
        self.launch(grid, inputs, **launch_kwargs)
​
    return wrapper

评论区精华

PrepareUniformDecodeKernel 按 buffer 容量 over-launch 导致越界读 正确性

LucasWilkinson blocking 评论:调用点传完整 decode_seq_lens_buffer(按 max_num_batched_tokens 分配),grid 启动的是 buffer 容量而非 batch;padding program 计算 req_id = idx // max_decode_len 越过真实 batch,读 seq_lens/block_table 越界,脏写落在后续被 slice/zeroed 的 buffer 尾部,掩盖了问题。

结论:作者改为显式 num_decode_tokens 关键字驱动 grid(“Runtime count is explicit now and drives the grid.”),head 版本已修正。 · 已解决

CompressedSlotMappingKernel 预热变体不可达(Triton 特化类不匹配) 正确性

LucasWilkinson blocking 评论:传字面量 1 预热的是 Triton exact-one 特化类,运行时值落在 divisible-by-16 类,编译出的二进制运行时永远用不到,内核仍在首次使用时 JIT。

结论:改为 do_not_specialize=["block_table_stride"],block_size 用 triton_scalar_specialization_rep 代表值;indexer.py 同样问题一并修复。 · 已解决

ConvertReqIndexToGlobalIndexKernel 的 max_num_blocks_per_req 作 constexpr 导致死预热 正确性

LucasWilkinson blocking 评论:constexpr 用 1 预热,运行时永远传真实 block-table 宽度,预热二进制不可能命中;且按宽度无限重编译。

结论:降为 do_not_specialize 运行时参数,作者确认“It is now a runtime, non-specialized argument.”。 · 已解决

BuildPrefillChunkMetadataKernel 在 fresh-cache 下仍逐 worker 编译一次 正确性

malaiwah Issue 评论:--jit-monitor-verbose 下发现 query_slice_start/stop、DCP_RANK/WORLD/INTERLEAVE 是运行时值而非算法编译键,留在 CompileKey 会产生 callsite 变体;且 compile-only 的 kernel.warmup() 不填充进程内 JITFunction.run cache,首次真实 prefill 仍编译。

结论:修复方案(do_not_specialize + 一次真实一行执行 + OOT 后端 config-name 回退 + GLM index_kpool)在独立 review branch,未并入本 PR,需后续跟进。 · 待处理

_COMBINE_TOPK_SWA_INDICES_KERNEL 预热覆盖丢失 正确性

LucasWilkinson blocking 评论:被删除的 sparse_mla_triton_warmup.py 原本也为指定 backend 预热该内核,本 PR 无人注册,首次使用仍 JIT;并建议统一 register_dsv4_sparse_warmups() 辅助函数防止两处注册漂移。

结论:作者补回注册,但未采纳统一 helper:“The migrated kernels are not exclusively DSv4-owned, and different backends require different subsets.”。 · 已解决

update_draft_decode_metadata 的 window_size 替代 shape[-1] 行为变化 正确性

LucasWilkinson:因果缓冲下两者等价,但 DSpark 非因果缓冲宽度是 64 对齐的 window+spec,若该路径可达 update_draft_decode_metadata,有效窗口收窄、行尾残留 stale indices。

结论:材料中未见作者明确回复,head 版本仍用 self.window_size,需回归确认 DSpark 非因果 draft 路径。 · 待处理

valid_counts 无条件 torch.zeros 丢掉 single-tile 优化 性能

LucasWilkinson:single-tile 模式是普通 store 而非 atomic add,不需要零初始化;无条件 zeros 在 decode 热路径上增加一次 memset launch。

结论:作者恢复分支:single-tile 用 torch.empty,multi-tile 用 torch.zeros。 · 已解决

硬编码 block size 64 与 NUM_TOPK_TOKENS=2048 的编译键一致性 正确性

LucasWilkinson:当前能工作只是因为 64 与真实缓存块尺寸同属 divisible-by-16 特化类,建议改用 vllm_config.cache_config.block_size,与 ConvertReqIndexToGlobalIndexKernel 保持一致。

结论:作者确认编译键取值改从 vllm_config 获取(“Values now come from vllm_config.”)。 · 已解决

get_warmup_keys 是否统一注入 vllm_config 的契约争论 设计

LucasWilkinson 建议统一签名 get_warmup_keys(self, vllm_config)(config-free 内核忽略参数),删除 signature sniffing 特例与对应测试;作者反对,认为无配置内核会引入 unused-argument 样板。

结论:Lucas 最终认同:“agreed @LopezCastroRoberto lets ignore this”。 · 已解决

jit_warmup_cutedsl_helper.py 无调用方,建议移出本 PR 设计

LucasWilkinson:该文件在本分支无调用者(torch_to_cute_dtype 同样),若为未来 CuteDSL 迁移准备,建议移出本 PR。

结论:最终合并文件清单已无该文件,按建议移出。 · 已解决

风险与影响

  1. 残留首轮运行时编译:malaiwah 的 fresh-cache 校验发现 BuildPrefillChunkMetadataKernel 在部分配置下仍会逐 worker 编译一次(indexer.py)。query_slice_start/stop、DCP_RANK/WORLD/INTERLEAVE 若留在 CompileKey 会生成 callsite 变体,且 compile-only 的 kernel.warmup() 不填充进程内 JITFunction.run cache;OOT 后端的 config-name 回退与 GLM index_kpool 也需纳入。修复在独立 review branch,未并入本 PR,在 --jit-monitor-mode error 下会直接暴露。
  2. DSpark 非因果 draft 路径行为变化:sparse_swa.py 的 update_draft_decode_metadata 用 window_size 取代 decode_swa_indices.shape[-1],非因果缓冲宽度为 64 对齐后的 window+spec;若 DSpark 可到达该路径,有效窗口收窄且清行循环只覆盖 window_size,行尾会残留 stale indices。
  3. 注册点分散易漂移:同一内核族在 deepseek_v4/attention.py 与 mla_attention.py 多处注册,作者未采纳统一 helper,_COMBINE_TOPK_SWA_INDICES_KERNEL 已被遗漏过一次,长期靠 review 兜底。
  4. 编译键与运行时特化类强耦合:triton_scalar_specialization_rep 的 1、16 整除、其他三类必须与运行时真实值一致,任何新调用点若改变 shape/stride/标量分布,预热即静默失效;本次 review 抓到的三类问题均属此。
  5. 性能回归风险:valid_counts 分配与 grid 尺寸若回归到统一 torch.zeros 或 buffer-capacity 启动,会重新引入 decode 热路径 memset 或越界读。

运行时影响:对启用 enable_jit_warmup 的 DSv4 与通用稀疏 MLA 后端(FLASHMLA_SPARSE、FLASHINFER_MLA_SPARSE、FLASHINFER_MLA_SPARSE_SM120、DEEPSEEK_V32_INDEXER 等),内核编译前移到启动期,覆盖完整时首次推理不再出现 JIT 停顿,直接服务于 Issue #49349 的「Zero JIT」目标。架构影响:确立「内核自描述 + 注册就近」的迁移范式,VllmTritonJitKernel 与 kernel_launcher 成为后续 Triton 内核迁移的模板,删除外部编排文件减少了 backend 名称字符串与内核符号的隐式耦合。团队影响:为系列后续 PR(#50176-#50178、#53564-#53567 等)提供可复制模式,review 暴露的特化类问题将成为后续迁移的检查清单。范围限制:仅覆盖 Triton 元数据/索引内核,DeepGEMM、CuTeDSL、TileLang 等其他后端的 de-JIT 仍在后续工作中。

残留首轮运行时编译 DSpark 非因果 draft 路径行为改变 注册点分散易遗漏内核 预热键与运行时特化类强耦合 依赖后续 PR 系列闭环

关联 Issue

#49349 Zero JIT compilation during runtime

完整报告

参与讨论