Closed
[Bug-Report|缺陷反馈][工具检测]:matmul_s4 示例racecheck 报 1 条 WAW + 513 条 RAW hazard竞争异常 #1723
h-glueAdd on Sep 17Closed at Sep 29
Sep 21 Assign chen_xu0513 as responsible person
chen_xu0513
Sep 21 Comments:
Sep 21 Comments:
您好,感谢指出问题,经分析,当前样例确实存在两个AIV核冗余写同一GM区间和跨核同步未覆盖全部AIV的问题,会尽快修复


Sep 21 Associated pull request
chen_xu0513
Sep 29 Comments:
Sep 29 Comments:
问题已修复,已解决matmul_s4样例的两个问题:
1.两个 AIV 核(aiv-0 / aiv-1)执行完全相同的冗余解压。增加if分支判断,多核分别处理解压
2.跨核同步应覆盖全部 AIV:使用 CrossCoreSetFlag/CrossCoreWaitFlag 时应保证 AIC 能感知到所有 AIV 的完成信号。增加CrossCoreWaitFlag<4, PIPE_MTE2>(24)等待AIV1


Sep 29 Added label: resolved
问题描述 (Mandatory / 必填)
在 asc-devkit 示例
examples/01_simd_cpp_api/06_compatibility_guide/matmul_s4上启用 mssanitizer racecheck 检测,共报告 514 条 GM hazard(1 条 WAW + 513 条 RAW):Potential WAW hazard detected at GMPotential RAW hazard detected at GM__mix__(1, 2):1 AIC + 2 AIV关键特征:
Process()让每个 AIV 都调用Unzip(aGlobal, a4Global, ...)和Unzip(bGlobal, b4Global, ...),且两个 AIV 不区分 block_idx,都从 a4GM/b4GM 解压出完整 65536 字节分别写入整块 aGM 与 bGM;0x120000017000(aGM 基址)发生 WAW,两者 pc 相同(0x36a8),即 matmul_s4.asc:158 的DataCopy(dstGlobalTensor, dstLocalTensor, count * 2);0x120000017000的PIPE_MTE3写,与 block 0 (aic) 的PIPE_MTE2读(pc 0x2360,即 matmul_s4.asc:135 的SetTensorA)冲突,读地址自0x120000017100起按 0x100 步进覆盖整个 aGM(513 条);CrossCoreSetFlag<4, PIPE_MTE3>(8),matmul_s4.asc:107 AIC 执行CrossCoreWaitFlag<4, PIPE_MTE2>(8)。按 Ascend 950PR/DT 的 mode 4 映射规则:AIV0 的 flagId 8 → AIC 的 flagId 8(被等待);AIV1 的 flagId 8 → AIC 的 flagId 24(未被等待)。即 AIC 实际只等到 AIV0 的完成信号,AIV1 的信号被丢弃;block_idx分工、对同一 GM 地址发起重复写(多核同址写,属竞态设计模式);RAW 根因是 mode 4 同步仅覆盖 AIV0,AIC 读 aGM 的时机只与 AIV0 的写完成绑定,未保证 AIV1 已写完。当前因两个 AIV 解压结果逐字节一致(同一 a4GM/b4GM 输入),verify_result.py校验通过(CompareResult ... test pass!),功能正确仅依赖"写入内容相同"这一巧合;DataCopy(Unzip内)→ matmul_s4.asc:102(Process内)→ matmul_s4.asc:191(op.Process);读侧指向 matmul_s4.asc:135SetTensorA→ matmul_s4.asc:108 → matmul_s4.asc:191。环境信息 (Mandatory / 必填)
examples/01_simd_cpp_api/06_compatibility_guide/matmul_s4CMAKE_ASC_RUN_MODE=npu),CMAKE_ASC_ARCHITECTURES=dav-3510matmul_s4<256, 256, 256>(int4 矩阵乘),__mix__(1, 2):1 AIC + 2 AIV0x120000017000(65536) / b4GM0x120000027000(32768) / bGM0x12000002f000(65536) / a4GM0x12000003f000(32768) / cGM0x120000047000(262144)重现步骤 (Mandatory / 必填)
cd examples/01_simd_cpp_api/06_compatibility_guide/matmul_s4mkdir -p build && cd build export ASCFLAGS="-g --cce-enable-sanitizer" cmake .. -DSCENARIO_NUM=1 -DCMAKE_ASC_ARCHITECTURES=dav-3510 -DCMAKE_ASC_LINK_FLAGS=--cce-enable-sanitizer make -jPotential WAW hazard detected at GM和 513 条Potential RAW hazard detected at GM;0x120000017000;DataCopy),读侧指向 matmul_s4.asc:135(SetTensorA)。预期结果 (Mandatory / 必填)
mssanitizer racecheck 检测不应报告任何 WAW/RAW hazard。具体地:
Process()应按GetBlockIdx()分工,例如 AIV-0 只解压 A(写 aGM)、AIV-1 只解压 B(写 bGM),各自只操作独立的 GM 地址区间,从根上消除同址写;CrossCoreSetFlag/CrossCoreWaitFlag时应保证 AIC 能感知到所有 AIV 的完成信号。当前 mode 4 + flagId 8 只同步了 AIV0;应改用 mode 2(所有 AIV 全部SetFlag后 AIC 的WaitFlag才放行),或按 mode 4 的 flagId 映射规则对每个 AIV 使用独立 flagId 并分别等待。相关日志/截图 (Mandatory / 必填)
完整日志文件:
result_fix/155_matmul_s4/mssanitizer_origin_racecheck_20260916_090534.txt(514 条)result_fix/matmul_s4/mssanitizer_20260917151211_777171.log、result_fix/155_matmul_s4/mssanitizer_20260916090543_500899.logresult_fix/matmul_s4/san_racecheck.log典型 WAW ERROR(block 0 vs block 1):
典型 RAW ERROR(aiv 写 vs aic 读):
同步指令流(证明 mode 4 仅覆盖 AIV0):
地址映射分析(根因链):
0x120000017000,大小 65536 bytes(M*K = 256*256,int8)Unzip(aGlobal, a4Global)+Unzip(bGlobal, b4Global),写整块 aGM/bGM0x120000017000,1 对SetTensorA,0x100 步进 513 次),513 对verify_result.py校验通过调用栈说明:
修复建议 (Optional / 选填)
WaitFlag必须等所有 AIV 的SetFlag才放行,保证同步覆盖两个 AIV 核:// 修复前:mode 4,flagId 8 只覆盖 AIV0(AIV1 的 flagId 8 映射到 AIC 侧 flagId 24,未被等待) AscendC::CrossCoreSetFlag<4, PIPE_MTE3>(8); // AIV 侧 AscendC::CrossCoreWaitFlag<4, PIPE_MTE2>(8); // AIC 侧 // 修复后:mode 2,所有 AIV 都执行 SetFlag 后 AIC 的 WaitFlag 才放行 AscendC::CrossCoreSetFlag<2, PIPE_MTE3>(8); // AIV 侧(两个 AIV 都执行) AscendC::CrossCoreWaitFlag<2, PIPE_MTE2>(8); // AIC 侧if ASCEND_IS_AIV { if (AscendC::GetBlockIdx() == 0) { Unzip(aGlobal, a4Global, tiling.M * tiling.Ka / 2); AscendC::CrossCoreSetFlag<4, PIPE_MTE3>(8); } else { Unzip(bGlobal, b4Global, tiling.Kb * tiling.N / 2); AscendC::CrossCoreSetFlag<4, PIPE_MTE3>(8); // AIV1 → AIC flagId 24 } } if ASCEND_IS_AIC { AscendC::CrossCoreWaitFlag<4, PIPE_MTE2>(8); // 等 AIV0 AscendC::CrossCoreWaitFlag<4, PIPE_MTE2>(24); // 等 AIV1 RunMatmul(); }修复后验证:应重新编译 + mssanitizer racecheck 运行,确认 1 条 WAW + 513 条 RAW 全部清零;且
CompareResult ... test pass!功能验证通过。同类风险排查:检查其他
__mix__混合核示例(1 AIC + N AIV 协同)中是否存在"多个 AIV 冗余写同址 GM"或"mode 4 flagId 映射未按 AIV0/AIV1 区分"的同类模式。影响评估:当前因两个 AIV 解压结果逐字节相同,功能正确性不受影响。但该模式存在两处隐患:(1) 若未来修改解压逻辑使两核输出不同,AIC 可能读到 AIV1 未写完的数据;(2) mode 4 的 flagId 映射要求对每个 AIV 使用独立 flagId,直接用相同 flagId 会在多 AIV 场景下丢失同步语义。建议在示例层面修复,体现最佳实践。