STFT 算子在 atk 批跑精度测试中偶现失败:单跑成功、批跑失败,失败用例不固定(如 case 169 有时成功有时失败)。对比 NPU 与 CPU 输出发现,失败时 NPU 输出在部分行的尾部帧输出 0,其余位置数值完全正确。
复现命令(Ascend950PR 环境):
atk node --backend npu --devices 1 node --backend cpu --name acc task -c ./error_case_stft.json --task accuracy -p ./exec_stft.py -mt 5 --save_data input --save_data output
失败示例(case 281,nfft=7/hop=1/win=4/onesided=false,输出 shape [7,7]):
STFT AICore kernel 内存在 MTE3(UB→GM 异步拷贝,Vector 流水线)与 Cube matmul(读 GM,Cube 流水线)之间的流水线竞态:
StftPlanMul::Process()
STFTGeneralized::Process()
SplitWindows
StftMatmul
STFTGeneralizedComplex::Process()
首次调用时 workspace 为新分配内存(内容为 0),matmul 抢先读到未写入的数据 → 输出 0;后续调用 workspace 残留上次正确的数据,竞态被掩盖 → 呈现“偶现”特性。这也是单跑(新进程首次调用易触发)与批跑表现差异的原因。
在三处 MTE3 写 workspace 之后、Cube matmul 读取之前插入 HardEvent::MTE3_S 跨流水线事件同步:
HardEvent::MTE3_S
event_t eventIdMTE3ToS = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE3_S)); SetFlag<HardEvent::MTE3_S>(eventIdMTE3ToS); WaitFlag<HardEvent::MTE3_S>(eventIdMTE3ToS);
涉及文件:
math/stft/op_kernel/stft_plan_mul.h
math/stft/op_kernel/stft_generalized.h
math/stft/op_kernel/stft_generalized_complex.h
同时清理 stft_tiling_base 中冗余代码:删除从未使用的 l1Size/l0ASize/l0BSize/l0CSize(其中 l0A/B/C 获取时误用了 CoreMemType::UB)及重复的 l1SizePlatform 赋值。
stft_tiling_base
l1Size/l0ASize/l0BSize/l0CSize
CoreMemType::UB
l1SizePlatform
Ascend950PR 环境验证:
/assign @east_yang
问题描述
STFT 算子在 atk 批跑精度测试中偶现失败:单跑成功、批跑失败,失败用例不固定(如 case 169 有时成功有时失败)。对比 NPU 与 CPU 输出发现,失败时 NPU 输出在部分行的尾部帧输出 0,其余位置数值完全正确。
复现命令(Ascend950PR 环境):
失败示例(case 281,nfft=7/hop=1/win=4/onesided=false,输出 shape [7,7]):
根因分析
STFT AICore kernel 内存在 MTE3(UB→GM 异步拷贝,Vector 流水线)与 Cube matmul(读 GM,Cube 流水线)之间的流水线竞态:
StftPlanMul::Process():plan×window 结果通过 MTE3 写入 plan workspace 后没有等待写完成,主算子 Cube matmul 立即读取STFTGeneralized::Process():SplitWindows通过 MTE3 写 splitWindow workspace 后同样无同步,StftMatmul立即读取STFTGeneralizedComplex::Process():complex 输入路径存在相同问题首次调用时 workspace 为新分配内存(内容为 0),matmul 抢先读到未写入的数据 → 输出 0;后续调用 workspace 残留上次正确的数据,竞态被掩盖 → 呈现“偶现”特性。这也是单跑(新进程首次调用易触发)与批跑表现差异的原因。
修复方案
在三处 MTE3 写 workspace 之后、Cube matmul 读取之前插入
HardEvent::MTE3_S跨流水线事件同步:event_t eventIdMTE3ToS = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE3_S)); SetFlag<HardEvent::MTE3_S>(eventIdMTE3ToS); WaitFlag<HardEvent::MTE3_S>(eventIdMTE3ToS);涉及文件:
math/stft/op_kernel/stft_plan_mul.hmath/stft/op_kernel/stft_generalized.hmath/stft/op_kernel/stft_generalized_complex.h同时清理
stft_tiling_base中冗余代码:删除从未使用的l1Size/l0ASize/l0BSize/l0CSize(其中 l0A/B/C 获取时误用了CoreMemType::UB)及重复的l1SizePlatform赋值。验证结果
Ascend950PR 环境验证: