Pull Request已成功合入, 合并人@CANN-robot
(感谢 zhong-zixin 的贡献)变更摘要
本 PR 针对关联 Issue #5029,将"是否有专家权重(hasExpertScalesFlag_)"的判断从 MoE 发送的逐 token 循环内提升到循环外,从而消除可选 topk weight 分支在循环内重复判断引入的性能劣化。改动集中在 mc2/moe_distribute_dispatch_v2/op_kernel/moe_distribute_dispatch_v2.h:原 SendToMoeExpert 的循环主体被提取为带布尔开关的新函数,开关在进入循环前一次性确定,并通过新增形参沿 ProcessToken → FillTriple 传递。
主要改动
- 新增
SendToMoeExpertLoop并拆分循环:将原SendToMoeExpert中的循环逻辑整体提取为SendToMoeExpertLoop(startTokenId, endTokenId, writeExpertScale);SendToMoeExpert在循环外根据hasExpertScalesFlag_判断一次,再以固定的true/false调用循环函数,避免每个 token 在循环内重复做专家权重判断。 FillTriple增加bool writeExpertScale形参:原(k < axisK_) && (hasExpertScalesFlag_)的循环内条件判断改为由调用方传入的布尔开关控制,仅在writeExpertScale为真时写入expertScalesTensor_对应的专家权重(xOutTfloat(expertScaleAlign_))。ProcessToken增加bool writeExpertScale形参:签名扩展后将开关原样透传给FillTriple(两个分支中的调用均同步更新)。- 共享专家路径显式关闭专家权重写入:
SendToSharedExpert在调用ProcessToken时传入false,明确共享专家发送不走专家权重写入逻辑,与 MoE 专家路径的开关行为区分开。


Thanks for your pull-request.
The full list of commands accepted by me can be found at here.
You can get sig-info at here.
You can self-configure the PR merge rules for this repository. For more details, please refer to Here.
For more, you also can visit HICANN.
PR Approval Progress
✅ Congratulations! All modules have met the lgtm and approve requirements.
Module Approval Details
| module | lgtm status | approve status |
|---|---|---|
| mc2 | ✅ wang-minbo, tgwsakiko_ (2/2) | ✅ wang-minbo (1/1) |
💡 Tip:
- Committer can comment
/approveor/lgtm- Commenting
/approveimplies both code review (lgtm) and intent to merge (approve)
CLA Signature Pass
zhong-zixin, thanks for your pull request. All authors of the commits have signed the CLA. 👍


compile


| 🚀 CI 流水线已启动 |
|---|
| 📋 执行详情: 点击查看流水线 |


/lgtm


/lgtm
/approve


描述
将
FillTriple/ProcessToken/TokenToExpert中循环内的(k < axisK_) && hasExpertScalesFlag_运行时判断外提:SendToMoeExpert拆分为入口 + 循环体,按hasExpertScalesFlag_以字面量true/false分流传参,共享专家路径固定传false,消除未启用 expertScales 场景逐 token 热循环中的分支开销。同步修复 arch22 / arch35 FullMesh 变体中的同款问题,行为与基线严格等价。关联的Issue
关联Issue #5029
测试
本地验证,二级冒烟
文档更新
不涉及
类型标签
PR #11394 代码检视报告
fix_topkw_loop→master33d8246e0f,PR head1e37cfe17(单提交)moe_distribute_dispatch_v2.h、arch22 / arch35 两个 FullMesh 变体1. 整体概述
1.1 背景与动机
提交
2a0d633137(PR !7350,"Support optional topk weights for MTE low latency")为moe_distribute_dispatch_v2引入了可选的 topK 权重输入expertScales。该特性在逐 token 发送热循环内以运行时条件(k < axisK_) && hasExpertScalesFlag_控制权重写入,对未启用 expertScales 的存量场景(绝大多数调用方)造成性能劣化。1.2 修复方式
将"是否写专家权重"的判断提升到循环外,通过函数参数显式传递:
FillTriple、ProcessToken新增bool writeExpertScale参数;SendToMoeExpert拆分为入口 +SendToMoeExpertLoop循环体,入口按hasExpertScalesFlag_以字面量true/false分流;SendToSharedExpert(共享专家路径)固定传false。该修复同时覆盖标准 kernel 与两个 FullMesh 变体,回归在三种部署形态下全部消除。
2. 主头文件变更解析
FillTriple/ProcessToken新增writeExpertScale参数,内部判断if (writeExpertScale);SendToMoeExpert拆分为入口 +SendToMoeExpertLoop,入口按hasExpertScalesFlag_以字面量分流;SendToSharedExpert固定传false;k = expertIdx % axisK_恒小于axisK_;共享专家:k = axisK_ + idx恒不小于axisK_)行为与基线严格等价;expertScaleAlign_仅在hasExpertScalesFlag_ == true时初始化,expertScalesTensor_仅在同条件下加载且先于发送,无读未初始化风险;3. FullMesh 两文件变更解析
3.1 改动模式
两个 FullMesh 文件复刻主头文件的修复思路,但因函数族不同(
TokenToExpert/TokenToExpertInQuant直接持有FillTriple调用)适配方式略有差异:FillTriple新增bool writeExpertScale,内部判断由(k < axisK_) && hasExpertScalesFlag_改为(k < axisK_) && writeExpertScale(注意:与主头文件不同,k < axisK_被保留);TokenToExpert/TokenToExpertInQuant新增bool writeExpertScale形参并透传给FillTriple;SendToMoeExpert拆分为入口 +SendToMoeExpertLoop,入口按hasExpertScalesFlag_以字面量true/false分流;SendToSharedExpert的两处调用固定传false。3.2 arch22(
moe_distribute_dispatch_v2_full_mesh.h)等价性论证调用路径逐一验证:
SendToSharedExpert:607/609)axisK_ + toSharedExpertIndex,恒>= axisK_(k < axisK_)恒假 → 不写false→ 不写SendToMoeExpertLoop:707/710)topKIndex = calExpertIdsIdx % axisK_(:700),恒< axisK_hasExpertScalesFlag_writeExpertScale = hasExpertScalesFlag_(入口 :666-670 分流)拆分完整性:入口保留
SplitExpertNumToCore()+CalExpertSendNum()+ 分流;calExpertIdsIdx/maskN64Num/dstWinGMTensor/expertMaskTensorU64四个声明(均无副作用)与双重循环体逐语句移入SendToMoeExpertLoop,循环体与旧版逐行一致(仅两处调用增加实参)。BS 模式旁证:
SendToMoeExpertByBS(:836)不调用TokenToExpert/FillTriple,不受签名变更影响,无需改动。3.3 arch35(
moe_distribute_dispatch_v2_a5_full_mesh.h)等价性论证SendToSharedExpert:626/628)axisK_ + toSharedExpertIndex,恒>= axisK_false→ 不写SendToMoeExpertLoop:695/697)topKId = index % axisK_(:671),恒< axisK_hasExpertScalesFlag_writeExpertScale = hasExpertScalesFlag_(入口 :651-655 分流)拆分完整性:与旧版
SendToMoeExpert逐语句对比确认——前奏(Duplicate、validTokenNum计算、syncFlagId_ = 0、SetFlag 循环)保留在入口;dstWinGMTensor/dstTokenIdx声明(无副作用)与 token 循环移入SendToMoeExpertLoop;尾部 WaitFlag 循环保留在入口 if/else 之后。执行顺序与旧单函数完全一致(SetFlag 全部置位 → 逐 token Wait/Set → 收尾 Wait)。3.4 arch22 与 arch35 实现一致性
实现模式一致(FillTriple 判断式、字面量分流、共享专家传 false 均相同)。存在两处结构差异,均为两文件既有循环组织差异所致,非本次引入:
SendToMoeExpertLoop签名不同:arch35 额外传validTokenNum(其循环按 token 索引跨核步进,validTokenNum在前奏中计算);arch22 按专家分核,循环上界用成员sendNum_,无需传参。3.5 状态一致性
expertScaleAlign_仅在Init中hasExpertScalesFlag_ == true时初始化(两文件同款守卫,arch22:384 / arch35:384);新代码仅在writeExpertScale == true(即hasExpertScalesFlag_ == true)时读取,无读未初始化成员风险。expertScalesTensor_在ExpIdsCopyAndMaskCal尾部按hasExpertScalesFlag_守卫加载(arch22:1966-1970 / arch35:1816-1820),先于AllToAllDispatchA3/A5分流执行;共享专家核虽也执行该函数,但路径固定传false不读 scales,与旧代码(靠k < axisK_恒假跳过)行为一致。3.6 调用点完整性
全库检索确认:
FillTriple全部调用(定义体内各 2 处)、TokenToExpert/TokenToExpertInQuant全部调用(共享专家各 2 处 + MoE 循环各 2 处)实参数目与新签名一一匹配;moe_distribute_dispatch_v2/moe_distribute_dispatch_v3的 arch22*_a3.cpp与 arch35*_apt.cpp共 4 个 cpp 仅调用公共入口(Init/Process),私有方法签名变更随模板惰性实例化自动传播,无需改动;examples/fast_kernel_launch_example/下的 full_mesh 副本是独立的旧版拷贝(独立命名空间、未被本 PR 修改),不受影响。3.7 格式检查
以仓库
.clang-format(clang-format 22.1.8)对 3 个文件 PR 版本全文执行:4. 性能修复有效性
(k < axisK_) && false经内联 + 常量折叠完全消除,回归修复覆盖 FullMesh 部署形态;有权重场景保留一次k < axisK_运行期比较(见观察项 5.2),仍优于旧代码(成员加载 + 比较 + 分支)。hasExpertScales提升为模板参数的方案(需翻倍实例化、增加 tiling key 复杂度),当前运行时分流 + 编译期折叠的折中是合理的。5. 检视发现
阻塞问题
无。
观察项(非阻塞)
[观察-1] FullMesh 修复未覆盖 BS 模式路径(arch22)
arch22 的
SendToMoeExpertByBS(:836,canUseBSMode分支)不经过TokenToExpert/FillTriple,本就不含(k < axisK_) && hasExpertScalesFlag_判断,无回归残留。仅作完整性说明,无需改动。[观察-2] FullMesh
FillTriple保留了冗余的k < axisK_判断(可选清理)两文件
FillTriple的判断为(k < axisK_) && writeExpertScale,而两条调用路径上该条件已可静态判定:共享专家路径writeExpertScale == false使k < axisK_成为死条件;MoE 路径k = xxx % axisK_恒真。主头文件的对应修改已将判断简化为if (writeExpertScale)。FullMesh 保留k < axisK_的后果:无权重特化路径(回归场景)经常量折叠完全消除,不受影响;有权重特化路径每次 FillTriple 多一次运行期比较,属微小冗余。保留亦可视为防御性写法,不要求修改;如后续清理,建议与主头文件风格统一。6. 综合判定