Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rtp_llm/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ py_library(
":config_ops",
":warmup",
":jit_cache_manager_lib",
"//rtp_llm/models_py/kernel_tuning",
],
data = jit_deps(),
imports = ["."],
Expand Down
1 change: 1 addition & 0 deletions rtp_llm/models_py/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ py_library(
":utils",
":tile_kernels_mhc",
"//rtp_llm:warmup",
"//rtp_llm/models_py/kernel_tuning",
"//rtp_llm/models_py/triton_kernels:triton_kernels",
"//rtp_llm/models_py/distributed:deepep_wrapper",
"//rtp_llm/models_py/distributed:moriep_wrapper",
Expand Down
30 changes: 30 additions & 0 deletions rtp_llm/models_py/kernel_tuning/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
py_library(
name = "kernel_tuning",
srcs = glob([

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3] kernel_tuning BUILD 的 srcs/data glob 只覆盖一层目录,新增 provider 会静默漏出 runfiles

srcs = glob(["*.py", "aiter/*.py"])(BUILD:3-6)与 data = glob(["aiter/configs/*.csv"])(:7-9)都只匹配单层。而 registry.py:11 的 _PROVIDERS_BY_ARCH 正是本模块声明的扩展点:后续新增 provider 子目录或把 CSV 放进子目录时,文件不会进入 srcs/data,构建仍然成功,只在目标 arch 的运行时以 ImportError 或「RTP AITER FMoE overlay is missing」形式暴露——而后者对受影响签名等价于硬失败。同仓 //rtp_llm/models_py:modules 等 py_library 已使用 modules/**/*.py 这类递归 glob。

建议: 改为递归 glob("**/*.py""**/*.csv",必要时排除 test/),使新增 provider 目录默认被打包,避免扩展时出现只能在特定 arch 上复现的运行期缺文件问题。

Checklist: [6.1] OCP:本地扩展点优先于修改中心逻辑

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3] kernel_tuning BUILD 的 srcs/data glob 只覆盖一层目录,新增 provider 会静默漏出 runfiles

srcs = glob(["*.py", "aiter/*.py"])data = glob(["aiter/configs/*.csv"]) 都只匹配单层。按当前目录结构功能正确,但后续新增 provider(如放在 xxx/yyy/*.py)或把配置分子目录存放时,Bazel 不会报错,只会在运行期表现为 RTP AITER FMoE overlay is missingfmoe.py:220-224 返回 applied=False)→ 受影响 workload 在 executor 构造期抛 RuntimeError,失败点距根因很远。同仓 models_py/BUILD:40-44tile_kernels_mhc 已使用 **/*.py 递归 glob。

建议: 改为 glob(["**/*.py"], exclude = ["test/**"])glob(["**/configs/*.csv"]),让目录结构演进自动被打包覆盖(同时确认 test/ 不会被 srcs 意外吸入而与 py_test 的 srcs 重复);并在 overlay 缺失的 reason 中显式提示「检查 BUILD 的 data glob 与 wheel 打包」,缩短从现象到根因的距离。

Checklist: [6.1] 错误语义:fail-fast/retry/fallback/silent 行为显式;[6.1] 新逻辑有聚焦单测 + 相关集成/smoke 测试

"*.py",
"aiter/*.py",
]),
data = glob([
"aiter/configs/*.csv",
]),
deps = [
"//rtp_llm:torch",
],
visibility = ["//visibility:public"],
)

py_test(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] aiter_fmoe_test 未按 ROCm 硬件调度,sha256 与已安装 wheel 校验恒为 skip,且缺少多条 fail-closed 分支覆盖

仓内约定是需要真实 ROCm 依赖的 py_test 带 tags = ["rocm"]exec_properties = {'gpu':'MI308X-ROCM7'}(见 fused_moe/impl/rocm/test/BUILD 的 5 个目标,多数还带 timeout)。新增的 aiter_fmoe_test(BUILD:16-24)与 registry_test 两者都没有,deps 只有 :kernel_tuning(其 deps 仅 //rtp_llm:torch),运行环境不安装 aiter。因此 test_installed_aiter_matches_supported_artifacts_when_available(test:173-186)恒走 skipTest——它是全仓唯一把 _SUPPORTED_DEFAULT_CONFIG_SHA256 与真实 aiter/configs/tuned_fmoe.csv 做比对的地方。现有用例也未覆盖 sha256 漂移、`PackageNotFoundEr...

建议: 拆分目标:纯 Python 逻辑用例(fake distribution、临时 CSV、requirements 版本比对)保持无 tag 在通用 runner 上跑;把依赖真实 aiter 的断言拆到一个带 tags = ["rocm"]exec_properties = {'gpu':'MI308X-ROCM7'} 的 target(可复用同一 srcs + 显式 main),并加注释说明它是该 sha256 常量的唯一直接校验点。同时给 CPU 目标补 timeout,并用 fixture 构造 sha256 漂移、PackageNotFoundError、overlay 缺失三种情形补齐 fail-closed 分支断言。

name = "aiter_fmoe_test",
srcs = ["test/aiter_fmoe_test.py"],
data = [
"@rtp_deps//:requirements_lock_rocm.txt",
"@rtp_deps//:requirements_rocm.txt",
],
deps = [":kernel_tuning"],
)

py_test(
name = "registry_test",
srcs = ["test/registry_test.py"],
deps = [":kernel_tuning"],
)
4 changes: 4 additions & 0 deletions rtp_llm/models_py/kernel_tuning/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from rtp_llm.models_py.kernel_tuning.registry import configure_kernel_tuning
from rtp_llm.models_py.kernel_tuning.types import KernelTuningStatus

__all__ = ["KernelTuningStatus", "configure_kernel_tuning"]
15 changes: 15 additions & 0 deletions rtp_llm/models_py/kernel_tuning/aiter/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from rtp_llm.models_py.kernel_tuning.aiter.fmoe import (
AITER_FMOE_GFX942_OVERLAY,
AiterFmoeWorkloadSignature,
configure_aiter_fmoe_overlays,
is_affected_aiter_fmoe_signature,
require_aiter_fmoe_tuning,
)

__all__ = [
"AITER_FMOE_GFX942_OVERLAY",
"AiterFmoeWorkloadSignature",
"configure_aiter_fmoe_overlays",
"is_affected_aiter_fmoe_signature",
"require_aiter_fmoe_tuning",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cu_num,token,model_dim,inter_dim,expert,topk,act_type,dtype,q_dtype_a,q_dtype_w,q_type,use_g1u1,doweight_stage1,block_m,ksplit,us1,kernelName1,err1,us2,kernelName2,err2,us,run_1stage,tflops,bw,_tag
80,1,2048,128,256,8,ActivationType.Silu,torch.bfloat16,torch.float8_e4m3fnuz,torch.float8_e4m3fnuz,QuantType.per_Token,1,0,32,0,0.0,_ZN5aiter48fmoe_bf16_pertokenFp8_g1u1_vs_silu_1tg_ps_32x128E,0.0%,0.0,Null,0.0%,0.0,1,0.0,0.0,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 调优表全部性能与误差列为 0 占位值,调优结论不可追溯且 err1=0.0% 是未经测量的正确性声明

5 行数据的测量列全为占位值:us1=0.0err1=0.0%us2=0.0err2=0.0%us=0.0tflops=0.0bw=0.0。后果有两点:一是无法复核「one-stage 32x128 优于 stock 选核」这一结论,fmoe.py:17 的版本 pin 上抬时维护者没有任何基线可对比,只能重新盲调;二是 err1=0.0% 在无实测依据下声明了零数值误差。文件形式上是 AITER tuning 输出、实质是手工撰写的 dispatch 覆盖,仓内未留下实测延迟、tuning 命令行或采集环境记录。同仓同类离线调优数据 linear/impl/rocm/data/fp8_ptpc_hipb_solutions.json 带有 format_versiontarget(arch/hip/aiter 版本 prefix)与 selection_policy(GPU 集合、提速门槛、回退规则),本文件没有任何等价 provenance。

建议: 二选一:(1)回填 AITER 调优脚本产出的真实 us1/us/tflops/bw/err1;(2)保留 0 占位,但把无法在 CSV 格式内表达的 provenance 落到 configs/ 下的 README 或 AITER_FMOE_GFX942_OVERLAY 常量旁的注释,至少记录调优机型与 CU 数、复现命令与版本、baseline 与 overlay 的 us/tflops 对比、误差判定口径与重新生成步骤。无论哪种方式,都建议把 err10.0% 改为真实值或留空,避免在数据文件里留下伪造的精度结论。

Checklist: [6.1] PR description 说明动机与设计

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] token 覆盖仅到 16 且只有 2 的幂桶,桶间与桶外 token 的选核语义未记录也未覆盖

本表只提供 token 1/2/4/8/16 五行。但 require_aiter_fmoe_tuning(fmoe.py:271-284)的判定输入 AiterFmoeWorkloadSignature(fmoe.py:44-64)不含 token,是按 shape 整体 fail-closed 的:overlay 一旦生效,所有 token 数都被报告为已满足调优要求。真实 decode 批次 token 数连续变化(如 3、12、24),这些取值是被 AITER 向上/向下取整命中某行、还是精确匹配失败后回落到 stock 选核,取决于 AITER 内部桶解析规则;该规则既未在本仓以注释或断言固定,也无对应测试,无法从 worktree 内验证。若为精确匹配,非桶 token 仍走未调优路径而代码层面仍报告已生效;若为向下取整,token 17..31 会使用只在 ≤16 验证过的 one-stage kernel。

建议: 明确并在 _AFFECTED_TOKEN_BUCKETS 处注释 AITER 对 token 列的解析语义(精确匹配/向上取整/向下取整)及适用上界与截断理由:若为精确匹配,补齐连续 token 行或写明非桶 token 会回落到 stock 选核;若为向下取整,建议补一行 token=32(沿用 AITER 原表在该点的选择)作为显式上边界,避免 overlay 影响范围超出实际调优区间。同时在 rocm_fp8_fused_moe_test.py:329 的 token 参数中补一个非桶取值(如 3 或 12)作为边界用例。

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 调优产物的性能与精度列全为 0.0 占位,且无生成来源记录,收益与精度不可复核

5 行数据的 us1us2ustflopsbw 全为 0.0err1err2 全为 0.0%。目录名 kernel_tuning 与 fmoe.py:286 的 "reviewed one-stage tuning overlay" 均声称这是调优产物,但零值与「基准未跑」无法区分:既不能证明所选 kernel 快于 stock 行,也不能证明精度误差曾被校验,err1=0.0% 更是一条未经测量的正确性声明。仓内也检索不到生成命令、机型或 AITER commit 记录,fmoe.py:287 却要求维护者「Revalidate the small-token FMoE kernels」。AITER 升级迫使版本常量上调时没有基线可比,只能盲测重做。

建议: 回填真实 tuning 输出的 us/tflops/bw/err;若上游 tuning 脚本不产出这些列,请在 configs/ 下补一份说明文件,记录生成命令、AITER 版本、设备 SKU(gfx942 80 CU)、日期,以及 stock 行与 overlay 的实测耗时与精度对比,并写明 overlay 的退役步骤。同时在 PR 描述中明确 stock dispatch 行究竟是数值错误还是仅性能退化——若仅是性能问题,fail-closed 的可用性代价不成立。

Checklist: [6.1] 可观测性:日志/指标/超时可操作、非噪声;[6.1] 回滚路径:风险行为存在运维回滚手段;[6.1] PR description 说明动机与设计

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] overlay 只覆盖 token 精确值 1/2/4/8/16,中间 token 的命中语义无文档也无测试固化

CSV 仅有 token=1、2、4、8、16 五行,fmoe.py:41 的 _AFFECTED_TOKEN_BUCKETS 要求行集合与之精确相等,require_aiter_fmoe_tuning 一旦配置成功即视为该 workload 小 token 路径已覆盖。但文件名 m1_16 与 fmoe.py:285 的 "for token buckets" 都暗示意图覆盖 1..16 区间,而仓内没有任何地方固化 AITER 把任意 token 映射到这些行的规则(精确匹配还是向上取桶);rocm_fp8_fused_moe_test.py:359 的 token 循环同样只取 (1,2,4,8,16)。若为精确匹配,token=3、57、915 仍走本 PR 认定不佳的 stock 行,覆盖率不足一半,而状态与错误文案都显示 overlay 已生效,形成覆盖假象。

建议: 二选一并落到可验证形态:若为向上取桶,请在 _AFFECTED_TOKEN_BUCKETS 处或同目录说明中写明该语义及其在 pin 定版本中的出处;若为精确匹配,请补齐 token 1~16 全部行,或把命名与文案从 m1_16 改为明确的离散桶表述。同时在 ROCm 用例的 token 循环里加入 3、7、15 等非桶边界值,使「小 token 已覆盖」有测试支撑。

Checklist: [6.1] 新逻辑有聚焦单测 + 相关集成/smoke 测试;[6.1] 边界 case 覆盖(空、单元素、最大值)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 调优产物的性能与精度列全为 0.0 占位,且无生成来源记录,收益与精度不可复核

5 行数据的 us1/us2/us/tflops/bw 全为 0.0err1/err2 全为 0.0%——这些正是 AITER tune 脚本写回实测结果的列,说明文件不是 tuner 的原始产物。这与 fmoe.py:283-288 的 fail-closed 强约束矛盾:错误文案明确要求维护者「Revalidate the small-token FMoE kernels and update or remove the overlay」,但仓库内既无 overlay 行的实测 us,也无 stock fallback 对照值,该指令无法执行。仓内也未记录生成命令、tuning 机型、日期与对应 AITER commit,全部上下文只编码在文件名中。若 AITER 在同 key 多候选间按 us 择优,0.0 还会让该行无条件胜出,这层隐式依赖亦未文档化。

建议: 按 stock tuned_fmoe.csv 的格式回填目标机型上 token 1/2/4/8/16 的真实 tune 输出(至少 userr1run_1stage=1us2/kernelName2 保持 AITER 自身的空值约定)。若工具链确实不产出这些列,则在 aiter/configs/ 下新增一份 README 记录生成命令、tuning 机型与 gfx/CU 数、日期、AITER 版本,以及 overlay 行与 stock fallback 的 us/精度对照,并在 _OVERLAY_CONFIG 定义处注释指向它,使版本 bump 后的复核有明确基线;PR 描述中也应给出 token=1..16 的 before/after 数据。注意不要在 CSV 内插注释行——csv.DictReader 会把它解析成数据行并触发严格行数校验失败。

Checklist: [6.1] PR description 说明动机与设计

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] overlay 命中面比 fail-closed 声明更窄,中间 token 与 EP>1 的回落语义无文档也无测试

两个维度都比 fail-closed 声明更窄。其一,fmoe.py:271-288 只依据 signature、不依据 token:命中 signature 即声称「该 workload 需要本 overlay」,但 CSV 只提供 token ∈ {1,2,4,8,16};token=3/5-7/9-15 或 >16 是否被覆盖完全取决于 AITER 对 token 列的查表语义(精确匹配则未覆盖),仓内既无注释也无测试说明依赖哪一种,而 suites_rocm_oss.bzldecode_capture_config '1,2,3,4' 表明 token=3 是真实 decode batch。其二,expert=256/inter_dim=128 取自 w1.shape[0]/w2.shape[2],都是分片后本地值,故该行只匹配 ep_size=1;EP>1 时签名不命中而仅打 debug 日志,运维侧无感。

建议:_AFFECTED_TOKEN_BUCKETS 旁用一行注释写明 AITER 对 token 列的查表/取整语义与 bucket 选取依据,并明确 token > 16 时的预期行为;若为精确匹配则补齐 token 1..16 的全部行。同时注明 expert/inter_dim 为 EP/TP 分片后的本地值、本 overlay 仅覆盖 ep_size=1。覆盖上建议补一个在 aiter 可用时才运行的 gated 用例(或匹配该 signature 的 MI308X smoke case),断言若干非 2 的幂 token(如 5)确实命中 overlay 行而非 stock 回落,把当前只存在于作者头脑中的查表假设变成可回归的断言。

Checklist: [6.1] 可观测性:日志/指标/超时可操作、非噪声

80,2,2048,128,256,8,ActivationType.Silu,torch.bfloat16,torch.float8_e4m3fnuz,torch.float8_e4m3fnuz,QuantType.per_Token,1,0,32,0,0.0,_ZN5aiter48fmoe_bf16_pertokenFp8_g1u1_vs_silu_1tg_ps_32x128E,0.0%,0.0,Null,0.0%,0.0,1,0.0,0.0,
80,4,2048,128,256,8,ActivationType.Silu,torch.bfloat16,torch.float8_e4m3fnuz,torch.float8_e4m3fnuz,QuantType.per_Token,1,0,32,0,0.0,_ZN5aiter48fmoe_bf16_pertokenFp8_g1u1_vs_silu_1tg_ps_32x128E,0.0%,0.0,Null,0.0%,0.0,1,0.0,0.0,
80,8,2048,128,256,8,ActivationType.Silu,torch.bfloat16,torch.float8_e4m3fnuz,torch.float8_e4m3fnuz,QuantType.per_Token,1,0,32,0,0.0,_ZN5aiter48fmoe_bf16_pertokenFp8_g1u1_vs_silu_1tg_ps_32x128E,0.0%,0.0,Null,0.0%,0.0,1,0.0,0.0,
80,16,2048,128,256,8,ActivationType.Silu,torch.bfloat16,torch.float8_e4m3fnuz,torch.float8_e4m3fnuz,QuantType.per_Token,1,0,32,0,0.0,_ZN5aiter48fmoe_bf16_pertokenFp8_g1u1_vs_silu_1tg_ps_32x128E,0.0%,0.0,Null,0.0%,0.0,1,0.0,0.0,
288 changes: 288 additions & 0 deletions rtp_llm/models_py/kernel_tuning/aiter/fmoe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
import csv
import hashlib
import importlib.metadata
import logging
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Optional

from rtp_llm.models_py.kernel_tuning.types import KernelTuningStatus

_LOGGER = logging.getLogger(__name__)

AITER_FMOE_GFX942_OVERLAY = (
"aiter_fmoe_gfx942_cu80_m1_16_h2048_i128_e256_topk8_bf16_fp8pt"
)
_SUPPORTED_AITER_VERSION = "0.1.21.dev80+g987203ba5.d20260825"
_SUPPORTED_DEFAULT_CONFIG_SHA256 = (
"00a7d76ae7c49760b2bb389d9cd38887713878f139dc49ff3b0af5dc65a6039f"
)
_OVERLAY_CONFIG = (
Path(__file__).resolve().parent
/ "configs"
/ "gfx942_cu80_fmoe_m1_16_h2048_i128_e256_topk8_bf16_fp8pt.csv"
)
_DISPATCH_KEY_FIELDS = (
"cu_num",
"token",
"model_dim",
"inter_dim",
"expert",
"topk",
"act_type",
"dtype",
"q_dtype_a",
"q_dtype_w",
"q_type",
"use_g1u1",
"doweight_stage1",
)
_AFFECTED_TOKEN_BUCKETS = (1, 2, 4, 8, 16)


@dataclass(frozen=True)
class AiterFmoeWorkloadSignature:
"""Static portion of the AITER FMoE dispatch key.

Tensor-parallel, expert-parallel, and model identity are intentionally
absent. They matter only through the local workload passed to AITER.
"""

gfx: str
cu_num: int
model_dim: int
inter_dim: int
expert: int
topk: int
act_type: str
dtype: str
q_dtype_a: str
q_dtype_w: str
q_type: str
use_g1u1: int
doweight_stage1: int


_AFFECTED_WORKLOAD_SIGNATURES = frozenset(
{
AiterFmoeWorkloadSignature(
gfx="gfx942",
cu_num=80,
model_dim=2048,
inter_dim=128,
expert=256,
topk=8,
act_type="ActivationType.Silu",
dtype="torch.bfloat16",
q_dtype_a="torch.float8_e4m3fnuz",
q_dtype_w="torch.float8_e4m3fnuz",
q_type="QuantType.per_Token",
use_g1u1=1,
doweight_stage1=0,
)
}
)

_CONFIG_STATUS: Optional[KernelTuningStatus] = None


def is_affected_aiter_fmoe_signature(
signature: AiterFmoeWorkloadSignature,
) -> bool:
return signature in _AFFECTED_WORKLOAD_SIGNATURES


def _sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as source:
for chunk in iter(lambda: source.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()


def _stock_fmoe_configs(default_config: Path) -> list[Path]:
model_config_dir = default_config.parent / "model_configs"
model_configs = sorted(
path
for path in model_config_dir.glob("*tuned_fmoe*.csv")
if path.is_file() and "untuned" not in path.name
)
return [default_config, *model_configs]


def _dispatch_keys(config: Path) -> set[tuple[str, ...]]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] stock 与 overlay 两条 CSV 解析路径重复实现,且 _tag 过滤语义不对称可致误判 dispatch 冲突

_dispatch_keys(fmoe.py:114-126)与 _validated_overlay_dispatch_keys(fmoe.py:129-164)逐字重复「打开 CSV → 校验 _DISPATCH_KEY_FIELDS 齐全 → 拼 key tuple」。更关键的是语义不一致:overlay 侧显式认定「AITER 会把 _tag 非空的行排除在正常 FMoE dispatch 之外」并据此拒绝(fmoe.py:140-145),但用于 stock 配置的 _dispatch_keys 完全不看 _tag。因此若 stock tuned_fmoe.csv 或任一 model_configs/*tuned_fmoe*.csv 存在 _tag 非空、key 与 overlay 相同的行,按 overlay 侧自己的规则它并不参与常规 dispatch、不构成真冲突,却会在 fmoe.py:230-238 被判为 overlap → overlay 静默失效;修复上文 act_type 问题后这将直接升级为权重加载期的 Runti...

建议: 抽出单一的 _read_dispatch_keys(config, *, exclude_tagged: bool) 供两处复用,并让 stock 侧与 overlay 侧对 _tag 采用同一语义(按代码注释所述,两侧都应排除 tagged 行);补一个「stock 含 tagged 同 key 行不应判为冲突」的用例固化该语义。若刻意保留 stock 侧的保守策略,请在代码注释中写明「宁可误判也不放过」的取舍及其对启动失败的影响。

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 两条 CSV 解析路径整段重复,且 _tag 过滤语义不对称可致误判 dispatch 冲突

_dispatch_keys(fmoe.py:114-126)与 _validated_overlay_dispatch_keys(fmoe.py:129-150)逐字重复了「打开 CSV、DictReader、检查 _DISPATCH_KEY_FIELDS 缺列、抛同一条 ValueError、按字段 strip 构造 key 元组」这段非平凡逻辑,后续调整 dispatch 列必须双改。更关键的是语义不对称:overlay 侧因「AITER 排除带 tag 行」而要求 _tag 为空(fmoe.py:140-145),但 stock 侧 _dispatch_keys 不做任何 tag 过滤,于是上游一条带 tag、本就不参与常规 dispatch 的 stock 行只要 key 相同,就会在 fmoe.py:230 被判为冲突,令 overlay 无谓停用并使受影响形状硬失败。

建议: 抽出 _read_dispatch_rows(config) -> list[dict] 统一负责打开与缺列校验,两个调用方各自在其上做 key 构造与额外校验;并在 stock 侧同样按 _tag 非空过滤掉不参与常规 dispatch 的行,使两条路径的 tag 语义与 AITER 的实际 dispatch 集合一致。补一条「stock 存在同 key 但带 tag 的行时 overlay 仍应生效」的用例。

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 两条 CSV 解析路径整段重复,且 _tag 过滤语义不对称可致误判 dispatch 冲突

_validated_overlay_dispatch_keysfmoe.py:140-145)明确以「AITER 会把 _tag 非空的行排除在普通 FMoE dispatch 之外」为依据拒绝带 tag 的 overlay 行;但同一文件里用于 stock 配置的 _dispatch_keysfmoe.py:114-126)完全不看 _tag,把带 tag 的行也算作 dispatch key。_stock_fmoe_configs 扫描的正是 model_configs/*tuned_fmoe*.csv——按 AITER 目录约定,这些按模型区分的文件恰恰最可能带 _tag。一旦其中出现与 overlay 同 key 但带 tag 的行,overlap 检查误判(fmoe.py:229-238)→ overlay 不启用 → 受影响 workload 在 executor 构造期抛 RuntimeError,服务无法启动。此外两函数的缺列校验与 key 元组提取逐字重复。

建议: 抽出一个共用的 CSV reader 统一两处对 _tag 的语义:读取 stock 配置时同样跳过 _tag 非空的行(它们不参与普通 dispatch),overlay 侧继续保留「不允许带 tag」的强校验。这样 overlap 判定与 AITER 实际的 dispatch 集合一致,同时消除当前两段 CSV 解析代码的重复,后续新增 dispatch key 列时也只需改一处。建议补一条用例:stock model_configs 中存在与 overlay 同 key 但带 tag 的行时,overlay 仍应正常生效。

with config.open(newline="") as source:
reader = csv.DictReader(source)
fieldnames = set(reader.fieldnames or ())
missing = set(_DISPATCH_KEY_FIELDS) - fieldnames
if missing:
raise ValueError(
f"{config} is missing AITER FMoE dispatch columns: {sorted(missing)}"
)
return {
tuple((row.get(field) or "").strip() for field in _DISPATCH_KEY_FIELDS)
for row in reader
}


def _validated_overlay_dispatch_keys(config: Path) -> set[tuple[str, ...]]:
with config.open(newline="") as source:
reader = csv.DictReader(source)
fieldnames = set(reader.fieldnames or ())
missing = set(_DISPATCH_KEY_FIELDS) - fieldnames
if missing:
raise ValueError(
f"{config} is missing AITER FMoE dispatch columns: {sorted(missing)}"
)
rows = list(reader)

tagged_rows = [row for row in rows if (row.get("_tag") or "").strip()]
if tagged_rows:
raise ValueError(
f"{config} has non-empty _tag values; AITER excludes tagged rows from "
"normal FMoE dispatch"
)

actual_keys = {
tuple((row.get(field) or "").strip() for field in _DISPATCH_KEY_FIELDS)
for row in rows
}
expected_keys = {
tuple(
str(token if field == "token" else getattr(signature, field))
for field in _DISPATCH_KEY_FIELDS
)
for signature in _AFFECTED_WORKLOAD_SIGNATURES
for token in _AFFECTED_TOKEN_BUCKETS
}
if actual_keys != expected_keys or len(rows) != len(expected_keys):
raise ValueError(
f"{config} dispatch rows do not match the declared affected workload "
f"signatures and token buckets {_AFFECTED_TOKEN_BUCKETS}"
)
return actual_keys


def _status(
applied: bool, reason: str, version: Optional[str] = None
) -> KernelTuningStatus:
return KernelTuningStatus(
overlay=AITER_FMOE_GFX942_OVERLAY,
applied=applied,
reason=reason,
dependency_version=version,
)


def configure_aiter_fmoe_overlays() -> KernelTuningStatus:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3] configure_aiter_fmoe_overlays 自身无 arch 自检,作为公共 API 可在非 gfx942 上装入 gfx942 调优行

arch 维度只体现在两处函数体外的信息中:registry._PROVIDERS_BY_ARCH 的 key(registry.py:12)与 overlay 文件名前缀 gfx942_cu80_。函数本身不做任何 arch/CU 校验,而它已通过 aiter/__init__.py__all__ 导出为公共 API,任何直接调用者(含未来其他 provider)在 gfx950 上都会把 gfx942 的行写进 AITER_CONFIG_FMOE_validated_overlay_dispatch_keysexpected_keys 也不覆盖 gfx 字段(CSV 无该列),未来若受影响签名集合扩展到多 arch,key 会退化重合。

建议:configure_aiter_fmoe_overlays 入口增加一次 arch 自检(与 _AFFECTED_WORKLOAD_SIGNATURES 中的 gfx 取值比对,不匹配则返回 not-applied 而非写 env),使该函数脱离 registry 单独调用时同样安全;或收窄导出面,仅由 registry 内部调用。

Checklist: [6.1] 分层边界:新概念在正确层级,不泄漏内部;[6.1] 状态不变量:创建/更新/失败/重试/回滚路径有效

"""Append reviewed RTP dispatch rows before AITER's first FMoE lookup."""

global _CONFIG_STATUS
if _CONFIG_STATUS is not None:
return _CONFIG_STATUS

try:
distribution = importlib.metadata.distribution("aiter")
except importlib.metadata.PackageNotFoundError:
_CONFIG_STATUS = _status(False, "aiter is not installed")
return _CONFIG_STATUS

version = distribution.version
if version != _SUPPORTED_AITER_VERSION:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] aiter 版本精确全等匹配叠加加载期硬 raise,无降级与运维逃生通道,且与仓内既有约定相反

_SUPPORTED_AITER_VERSION(fmoe.py:17)含 .d20260623 构建日期段,fmoe.py:192 用 != 全等比较,同一 commit 换日期重新构建 aiter 即失配;随后 require_aiter_fmoe_tuning(fmoe.py:279)在 RocmExpertsFp8PerChannel.__init__(rocm_moe.py:237)抛 RuntimeError,即权重加载期失败,经 start_backend_server.py:116 的 except BaseException 上报后终止全部 rank。回滚通道不存在:版本判定位于 env 分支(fmoe.py:245)之前,预设不含 overlay 的 AITER_CONFIG_FMOE 会走 fmoe.py:251 的 applied=False 同样抛异常。仓内解决同类问题的 fp8_ptpc_linear.py:235-241 恰好相反:prefix 匹配(其 prefix 刻意不含日期段)、失配仅返回 False 静默降级...

建议: 改用与 fp8_ptpc_linear.py 一致的版本 prefix 匹配(去掉 .dYYYYMMDD 段),并抽出共用的 aiter 版本/arch 判定工具消除两份实现;内容兼容性已由 sha256 与 dispatch key 冲突检测覆盖,版本号可放宽为最小兼容区间。同时提供显式运维开关(如 require|warn|off 三态,默认 require),warn/off 退化为 ERROR/WARNING + 继续启动,把「强制复核」诉求放在 CI 断言而非线上启动路径。注意两点耦合:一是修复上一条后本路径才会被生产流量真正命中(当前受 signature 判定门控,生产恒不可达,故本条按 P2 处理);二是放宽版本匹配会同时移除下一条 glob 重建的唯一门控,必须同步加固。若确实保留硬失败,请在 PR description 与错误信息中写明这是有意的部署闸门及其回滚手段。

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] fail-closed 缺少运维逃生开关与 overlay 复核流程,版本门位于 env 分支之前使显式配置也无法兜底

版本不等(fmoe.py:192)、stock CSV sha256 变化(:210)、任一 stock CSV 缺 13 个 dispatch 列或 key 冲突(:229)中任意一条成立即 applied=False,随后 fmoe.py:283 在 executor __init__ 抛 RuntimeError,即模型加载期硬失败。版本门早于 fmoe.py:245 的 env 分支,因此运维手工设置 AITER_CONFIG_FMOE 也绕不过;aiter_fmoe_test.py:129 还把该行为固化为断言。全链路无降级开关,唯一恢复手段是改代码发版。错误信息要求「Revalidate the small-token FMoE kernels」,但仓内没有生成/复核该 CSV 的脚本或说明。此外 inactive 时 registry.py:38 会在每个 gfx942 rank 打 warning,与该形状无关的部署也会看到噪声。

建议: 增加显式逃生开关(如 RTP_AITER_FMOE_OVERLAYauto/off/force),使运维可在不改代码的前提下降级为 warning;或把精确相等改为「已知不安全版本区间」语义,并把版本门移到 env 检查之后,使显式设置 AITER_CONFIG_FMOE 能作为有效兜底。在 kernel_tuning 包内补一份 overlay 生成与退役说明(tuning 命令、采集机型、如何刷新 version 与 sha256、失效后处理路径)。把 inactive warning 收敛为仅在命中受影响形状时输出。

_CONFIG_STATUS = _status(
False,
"unsupported AITER version; review whether the overlay is still needed",
version,
)
return _CONFIG_STATUS

default_config = Path(
distribution.locate_file("aiter/configs/tuned_fmoe.csv")
).resolve()
if not default_config.is_file():
_CONFIG_STATUS = _status(
False, f"AITER default FMoE config is missing: {default_config}", version
)
return _CONFIG_STATUS

actual_sha256 = _sha256(default_config)
if actual_sha256 != _SUPPORTED_DEFAULT_CONFIG_SHA256:
_CONFIG_STATUS = _status(
False,
"AITER default FMoE config changed; review the RTP overlay before use "
f"(expected {_SUPPORTED_DEFAULT_CONFIG_SHA256}, got {actual_sha256})",
version,
)
return _CONFIG_STATUS

overlay_config = _OVERLAY_CONFIG.resolve()
if not overlay_config.is_file():
_CONFIG_STATUS = _status(
False, f"RTP AITER FMoE overlay is missing: {overlay_config}", version
)
return _CONFIG_STATUS

stock_configs = _stock_fmoe_configs(default_config)
try:
overlay_keys = _validated_overlay_dispatch_keys(overlay_config)
for stock_config in stock_configs:
duplicate_keys = overlay_keys & _dispatch_keys(stock_config)
if duplicate_keys:
_CONFIG_STATUS = _status(
False,
"AITER stock FMoE configs now overlap the RTP overlay; review "
f"and remove or refresh {overlay_config}",
version,
)
return _CONFIG_STATUS
except (OSError, ValueError) as error:
_CONFIG_STATUS = _status(
False, f"failed to validate AITER FMoE config keys: {error}", version
)
return _CONFIG_STATUS

existing = os.environ.get("AITER_CONFIG_FMOE")
if existing:
existing_paths = {
str(Path(path).resolve()) for path in existing.split(os.pathsep) if path
}
if str(overlay_config) not in existing_paths:
_CONFIG_STATUS = _status(
False,
"AITER_CONFIG_FMOE was explicitly set without the RTP overlay; "
f"include {overlay_config}",
version,
)
return _CONFIG_STATUS
else:
config_paths = [*stock_configs, overlay_config]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 启动期用 glob 重建的列表整体覆写 AITER_CONFIG_FMOE,波及进程内所有 gfx942 MoE 负载且最终清单无日志

_PROVIDERS_BY_ARCH(registry.py:11-13)在 configure_kernel_tuning()(registry.py:32-35)按 arch 无条件执行,此时进程还不知道要加载哪个模型。fmoe.py:259-260 执行 config_paths = [*stock_configs, overlay_config] 后整体覆写 env,而非在 aiter 已解析的默认集合上追加。stock_configs(fmoe.py:104-111)用 tuned_fmoe.csv + model_configs/*tuned_fmoe*.csv(排除 untuned)这一 glob 启发式复刻 aiter 内部规则,仓内无任何断言证明其等于 aiter 默认集合——aiter_fmoe_test.py:93-96 断言的是 RTP 自己写出的 env 字符串;Path.glob 在目录不存在时静默返回空。若 aiter 实际解析范围更广,未复刻的已调优行被静默丢弃(性能回退、无报错),而 _LOGGER.info(...

建议: 优先读取 aiter 自身暴露的默认配置集合再追加 overlay,而不是重建;若确实只能重建,补一条在 pinned 版本下断言「重建集合 ⊇ aiter 默认解析结果」的 ROCm 门控测试,让上游改名/移动由测试而非线上行为暴露。同时把 _LOGGER.info 升级为打印最终生效的完整 AITER_CONFIG_FMOE 清单(含 stock 文件数量),便于线上核对实际生效的 dispatch 表;并考虑把 env 写入从「启动期按 arch 无条件执行」收敛为命中受影响 signature 后再配置(该时机仍早于首次前向)。若采纳上一条放宽版本匹配的建议,本条必须同批落地,否则将失去唯一保护。

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 启动期用 glob 重建的列表整体覆写 AITER_CONFIG_FMOE,波及进程内所有 gfx942 MoE 负载

registry.py:11 仅以 gfx942 为键注册 provider,start_backend_server.py:92 对任意 gfx942 rank 无条件调用,因此与 overlay 形状完全无关的 dense/embedding 服务也会在 fmoe.py:260 把该变量从「未设置(由 AITER 自决)」覆写为 RTP 拼出的列表。该列表由 _stock_fmoe_configs(fmoe.py:104-111)用 glob("*tuned_fmoe*.csv") 排除 untuned 自行重建 AITER 的默认发现集合;sha256 只锁单文件内容,不覆盖文件集合的新增/改名。全仓除新代码与其单测外无一处引用 AITER_CONFIG_FMOE,其 pathsep 多路径与「替换默认集合」语义在仓内无文档无断言。一旦重建结果与上游默认集合或优先级不一致,同进程内所有 FMoE 形状(含不做任何校验的 RocmExpertsBf16)的 dispatch 都会随之变化。

建议: 优先只做追加而不接管:若 AITER 提供配置查询或追加入口,改用该接口而非路径 glob。若必须覆写,请在 configure 阶段把 _stock_fmoe_configs() 结果与 AITER 内部默认解析出的列表显式比对,不一致时返回 applied=False 并在 reason 中列出差集,并为该比对补一条基于真实 AITER 安装目录的用例(现有 test_configures_additive_overlay_and_keeps_model_configs 使用自写 fixture,属自证)。同时把写 env 的生效范围收窄到「确实命中受影响签名」时,并把最终生效清单写入日志便于线上排障。

Checklist: [6.1] 分层边界:新概念在正确层级,不泄漏内部

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 启动期用 glob 重建的列表整体覆写 AITER_CONFIG_FMOE,波及进程内所有 gfx942 MoE 负载

fmoe.py:259-260 在 env 未设置时写入 os.pathsep.join([default_config, *model_configs, overlay])。主动重列 stock 文件说明作者认定该变量是替换语义,因此需同时成立三个假设:AITER 按 os.pathsep 拆分多路径、在首次 FMoE lookup 时才读取、_stock_fmoe_configsfmoe.py:104-111,glob model_configs/*tuned_fmoe*.csv 并排除 untuned)重建的清单与 AITER 自身发现结果等价。全仓检索 AITER_CONFIG_FMOE 仅命中本 PR 两个文件,三点均无断言或注释支撑。一旦不成立,gfx942 上全部 MoE 形状都会丢失 stock tuned 行。且 registry.py:11-13 只按 arch 注册,非 80 CU 的 gfx942 与纯 dense 模型也被改写。

建议: 把 env 改写收敛到确实需要的场景:让 provider 注册 key 带上 cu_num,或改为在 require_aiter_fmoe_tuning 命中受影响签名时惰性配置,把影响面从「全部 gfx942 进程」压回目标形状。若必须在启动期注入,则写入前调用 AITER 自身的配置解析入口取回默认清单并断言与重建结果一致,不一致时返回 applied=False 而非继续覆写。同时在 _stock_fmoe_configs 与写入点补注释,写明「该变量为替换语义」以及 glob 复刻的是哪个 AITER 版本的目录约定,使后续升级有明确复核依据。

Checklist: [6.1] 分层边界:新概念在正确层级,不泄漏内部

os.environ["AITER_CONFIG_FMOE"] = os.pathsep.join(map(str, config_paths))

_CONFIG_STATUS = _status(True, "RTP AITER FMoE overlay configured", version)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] applied=True 只代表环境变量已写入,无法证明 AITER 真正消费了 overlay,兜底调用还发生在 import aiter 之后

fmoe.py:260-262 写完 env 即返回 applied=Truerequire_aiter_fmoe_tuning 以此放行。整套机制依赖三个仓内无文档、无断言的上游假设:AITER 按 os.pathsep 解析多路径、该变量完全替换默认列表、且在首次 FMoE 查表时才读取。configure_kernel_tuning 只挂在 start_backend_server.py:92;不经该入口时只能依赖 rocm_moe.py:253 的兜底,而 rocm_moe.py:4,6 在模块导入期已执行 import aiter。唯一跑真实 aiter 的 rocm_fp8_fused_moe_test 亦在顶层导入 aiter 且从不调用 configure_kernel_tuning(),判据只有 cosine——若 AITER 在导入期快照 env,overlay 静默失效而用例照样通过,恰是 fail-closed 想拦住的场景。

建议: 在成功分支加后置校验:回读 AITER 解析出的 FMoE 配置来源列表并断言包含 overlay 路径,或对受影响探针 shape 断言最终命中的 kernel 名等于 CSV 中声明的 1tg_ps_32x128 变体,校验失败则 applied=False。补一条「在 import aiter 之后调用 configure_aiter_fmoe_overlays 仍然生效」的回归用例。若确实无法断言,请把状态字段语义改为「env 已配置(未验证生效)」并在日志中显式声明,不要以它作为 fail-closed 的唯一依据。

Checklist: [6.1] 状态不变量:创建/更新/失败/重试/回滚路径有效

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] applied=True 只代表环境变量已写入,无法证明 AITER 真正消费了 overlay,兜底调用还发生在 import aiter 之后

fmoe.py:260-262 写入 env 后直接置 applied=True,全程未回读 AITER 侧解析结果。而 require_aiter_fmoe_tuning 的兜底调用发生在 RocmExpertsFp8PerChannel.__init__rocm_moe.py:253),此时 rocm_moe.py:4,6import aiter / from aiter.fused_moe import fused_moe 早已执行。只要启动期未跑到 provider(registry.py:22 宽泛 except Exception 吞掉 arch 探测异常,或进程不经 local_rank_start),兜底会在 import 之后写 env 却仍报 applied=True 且不抛错。新增 GPU 用例只断言 shape/finite/mean cosine>0.99,overlay 完全未生效时同样通过,PR 唯一的安全网可能在 overlay 实际失效时放行。

建议: 补一道后置校验使「overlay 未真正生效」无法通过守卫,二选一或并用:(1)配置完成后回读 AITER 已加载的 FMoE dispatch 表,确认 overlay 的 5 条 key 在其中才置 applied=True;(2)在 configure_aiter_fmoe_overlays 开头检测 "aiter" in sys.modules,已导入则返回 applied=False 并在 reason 中说明「配置时机过晚」。同时把最终生效的 AITER_CONFIG_FMOE 取值写入 reason 便于线上定位,并在 ROCm 用例中断言目标形状实际命中的 kernel 名为 overlay 声明的 ..._1tg_ps_32x128 变体,使 fail-open 可被测试发现。

_LOGGER.info(
"Configured kernel tuning overlay %s from %s",
AITER_FMOE_GFX942_OVERLAY,
overlay_config,
)
return _CONFIG_STATUS


def require_aiter_fmoe_tuning(signature: AiterFmoeWorkloadSignature) -> None:
"""Fail closed only for a workload with known-bad stock dispatch rows."""

if not is_affected_aiter_fmoe_signature(signature):
_LOGGER.debug(
"AITER FMoE tuning overlay is not required for workload signature: %s",
signature,
)
return
status = configure_aiter_fmoe_overlays()
if status.applied:
return
raise RuntimeError(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] fail-closed 缺少运维逃生开关,版本与哈希门位于 env 分支之前使显式配置也无法兜底

require_aiter_fmoe_tuningfmoe.py:283 无条件抛 RuntimeError,调用点在 RocmExpertsFp8PerChannel.__init__rocm_moe.py:253),异常会让权重加载失败、backend rank 起不来。触发条件包括 aiter 版本字符串与 pin 不符、stock CSV 哈希变化、overlay 在 runfiles/wheel 中缺失、_tag 不对称导致的误判冲突、运维显式设置了不含 overlay 的 env。这些全部属于性能调优前提而非数值正确性前提;且版本校验(fmoe.py:192)与 sha256 校验(fmoe.py:210)都排在 env 分支(fmoe.py:245)之前,运维即使手动把 overlay 路径写进环境变量也无法绕过版本 pin。代码中不存在任何显式开关,线上只有「带 overlay 跑」或「加载失败」两态。

建议: 增加一个显式逃生开关(例如 RTP_ALLOW_UNTUNED_AITER_FMOE=1,默认保持现有 fail-closed 语义):置位时把 RuntimeError 降级为高等级错误日志(打印完整 reason 与命中签名,并提示「小 token 延迟可能显著上升」)并放行 stock 分发,同时把开关状态写入 KernelTuningStatus.reason 以便可观测;RuntimeError 文案中直接给出该开关名与「需重新 tuning 并更新 overlay」的操作指引。这样 aiter wheel 临时升级或打包漏文件时,线上表现为小 token 延迟回退而非整体不可用,运维具备不发版即可回滚的手段。

"The AITER FMoE workload signature "
f"{signature} for token buckets {_AFFECTED_TOKEN_BUCKETS} requires the "
f"reviewed one-stage tuning overlay, but it is inactive: {status.reason}. "
"Revalidate the small-token FMoE kernels and update or remove the overlay."
)
Loading
Loading