Closed
[Bug-Report|缺陷反馈][工具检测]:matmul_s4 示例racecheck 报 1 条 WAW + 513 条 RAW hazard竞争异常 #1723
h-glueAdd on  Sep 17Closed at  Sep 29
h-glue
Sep 17 Create

问题描述 (Mandatory / 必填)

在 asc-devkit 示例 examples/01_simd_cpp_api/06_compatibility_guide/matmul_s4 上启用 mssanitizer racecheck 检测,共报告 514 条 GM hazard(1 条 WAW + 513 条 RAW):

错误类别 错误类型 数量 涉及核
GM WAW hazard Potential WAW hazard detected at GM 1 aiv(0) vs aiv(1),两 AIV 核写同一 GM 地址
GM RAW hazard Potential RAW hazard detected at GM 513 aiv(1) 写 vs aic(0) 读同一 GM 区间
合计 514 混合核 __mix__(1, 2):1 AIC + 2 AIV

关键特征:

  1. 两个 AIV 核(aiv-0 / aiv-1)执行完全相同的冗余解压:matmul_s4.asc:102-103 中 Process() 让每个 AIV 都调用 Unzip(aGlobal, a4Global, ...) 和 Unzip(bGlobal, b4Global, ...),且两个 AIV 不区分 block_idx,都从 a4GM/b4GM 解压出完整 65536 字节分别写入整块 aGM 与 bGM;
  2. WAW 冲突点:racecheck 报告 block 0 (aiv) 与 block 1 (aiv) 在同一地址 0x120000017000(aGM 基址)发生 WAW,两者 pc 相同(0x36a8),即 matmul_s4.asc:158 的 DataCopy(dstGlobalTensor, dstLocalTensor, count * 2);
  3. RAW 冲突点:racecheck 报告 block 1 (aiv) 在 0x120000017000 的 PIPE_MTE3 写,与 block 0 (aic) 的 PIPE_MTE2 读(pc 0x2360,即 matmul_s4.asc:135 的 SetTensorA)冲突,读地址自 0x120000017100 起按 0x100 步进覆盖整个 aGM(513 条);
  4. 跨核同步存在但不完整(mode 4 flagId 映射缺陷):matmul_s4.asc:104 两个 AIV 均执行 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 的信号被丢弃;
  5. WAW/RAW 均为算子设计问题,确认属实:WAW 根因是两个 AIV 未按 block_idx 分工、对同一 GM 地址发起重复写(多核同址写,属竞态设计模式);RAW 根因是 mode 4 同步仅覆盖 AIV0,AIC 读 aGM 的时机只与 AIV0 的写完成绑定,未保证 AIV1 已写完。当前因两个 AIV 解压结果逐字节一致(同一 a4GM/b4GM 输入),verify_result.py 校验通过(CompareResult ... test pass!),功能正确仅依赖"写入内容相同"这一巧合;
  6. 所有 ERROR 调用栈一致:写侧均指向 matmul_s4.asc:158 DataCopy(Unzip 内)→ matmul_s4.asc:102(Process 内)→ matmul_s4.asc:191(op.Process);读侧指向 matmul_s4.asc:135 SetTensorA → matmul_s4.asc:108 → matmul_s4.asc:191。

环境信息 (Mandatory / 必填)

项 值
硬件型号 Ascend950PR_9579(dav-3510)
代码分支 asc-devkit 9.1.0 分支
软件版本 CANN 9.1.0
工具链 Ascend C(ascendc-bin 编译),mssanitizer(MindStudio Sanitizer)racecheck
算子示例 examples/01_simd_cpp_api/06_compatibility_guide/matmul_s4
运行模式 NPU(CMAKE_ASC_RUN_MODE=npu),CMAKE_ASC_ARCHITECTURES=dav-3510
算子配置 matmul_s4<256, 256, 256>(int4 矩阵乘),__mix__(1, 2):1 AIC + 2 AIV
GM 内存布局 aGM 0x120000017000(65536) / b4GM 0x120000027000(32768) / bGM 0x12000002f000(65536) / a4GM 0x12000003f000(32768) / cGM 0x120000047000(262144)

重现步骤 (Mandatory / 必填)

  1. 拉取 asc-devkit 并切到 9.1.0 分支,进入示例目录:
cd examples/01_simd_cpp_api/06_compatibility_guide/matmul_s4
  1. 编译(950 平台,开启 sanitizer 插桩):
mkdir -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 -j
  1. 启用 mssanitizer racecheck 运行 demo:
./demo
mssanitizer -t racecheck -- ./demo
  1. 观察日志输出:
    • 出现 1 条 Potential WAW hazard detected at GM 和 513 条 Potential RAW hazard detected at GM;
    • WAW 为 block 0 (aiv) vs block 1 (aiv) 同址写 0x120000017000;
    • RAW 为 block 1 (aiv) 写 vs block 0 (aic) 读,读地址覆盖 aGM 全部 513 个 0x100 步进区间;
    • 所有 ERROR 写侧指向 matmul_s4.asc:158(DataCopy),读侧指向 matmul_s4.asc:135(SetTensorA)。

预期结果 (Mandatory / 必填)

mssanitizer racecheck 检测不应报告任何 WAW/RAW hazard。具体地:

  1. 两个 AIV 核不应冗余写同一 GM 区间:Process() 应按 GetBlockIdx() 分工,例如 AIV-0 只解压 A(写 aGM)、AIV-1 只解压 B(写 bGM),各自只操作独立的 GM 地址区间,从根上消除同址写;
  2. 跨核同步应覆盖全部 AIV:使用 CrossCoreSetFlag/CrossCoreWaitFlag 时应保证 AIC 能感知到所有 AIV 的完成信号。当前 mode 4 + flagId 8 只同步了 AIV0;应改用 mode 2(所有 AIV 全部 SetFlag 后 AIC 的 WaitFlag 才放行),或按 mode 4 的 flagId 映射规则对每个 AIV 使用独立 flagId 并分别等待。

相关日志/截图 (Mandatory / 必填)

完整日志文件:

  • racecheck 报告: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.log
  • 带完整调用栈报告:result_fix/matmul_s4/san_racecheck.log

典型 WAW ERROR(block 0 vs block 1):

====== ERROR: Potential WAW hazard detected at GM in "void matmul_s4<256, 256, 256>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, unsigned char*, unsigned char*)":
======    PIPE_MTE3 Write at WAW()+0x120000017000 in block 0 (aiv) on device 0 at pc current 0x36a8 (serialNo:52)
======    #0 .../matmul_s4.asc:158:9
======    #1 .../matmul_s4.asc:102:13
======    #2 .../matmul_s4.asc:191:8
======    PIPE_MTE3 Write at WAW()+0x120000017000 in block 1 (aiv) on device 0 at pc current 0x36a8 (serialNo:116)
======    #0 .../matmul_s4.asc:158:9
======    #1 .../matmul_s4.asc:102:13
======    #2 .../matmul_s4.asc:191:8

典型 RAW ERROR(aiv 写 vs aic 读):

====== ERROR: Potential RAW hazard detected at GM in "void matmul_s4<256, 256, 256>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, unsigned char*, unsigned char*)":
======    PIPE_MTE3 Write at RAW()+0x120000017000 in block 1 (aiv) on device 0 at pc current 0x36a8 (serialNo:116)
======    #0 .../matmul_s4.asc:158:9
======    #1 .../matmul_s4.asc:102:13
======    #2 .../matmul_s4.asc:191:8
======    PIPE_MTE2 Read at RAW()+0x120000017100 in block 0 (aic) on device 0 at pc current 0x2360 (serialNo:170)
======    #0 .../matmul_s4.asc:135:12
======    #1 .../matmul_s4.asc:108:13
======    #2 .../matmul_s4.asc:191:8

同步指令流(证明 mode 4 仅覆盖 AIV0):

[checker.cpp:515] SET_INTRA_BLOCK, 81, aiv-0, 0x3a84, PipeType:PIPE_MTE3, syncid:8
[checker.cpp:515] PIPE_BARRIER, 82, aiv-0, 0x3aa4, pipe:PIPE_ALL
[checker.cpp:515] SET_INTRA_BLOCK, 145, aiv-1, 0x3a84, PipeType:PIPE_MTE3, syncid:8
[checker.cpp:515] WAIT_INTRA_BLOCK, 169, aic-0, 0x2c4, PipeType:PIPE_MTE2, syncid:8   ← 只等 AIV0 的 flagId 8

地址映射分析(根因链):

环节 说明
aGM 输出缓冲区 0x120000017000,大小 65536 bytes(M*K = 256*256,int8)
冗余解压 两个 AIV 核均完整执行 Unzip(aGlobal, a4Global) + Unzip(bGlobal, b4Global),写整块 aGM/bGM
mode 4 同步映射 AIV0 flagId 8 → AIC flagId 8(被等待);AIV1 flagId 8 → AIC flagId 24(未等待)
WAW 冲突集 aiv-0 与 aiv-1 同址写 0x120000017000,1 对
RAW 冲突集 aiv-1 写 aGM 与 aic-0 读 aGM(SetTensorA,0x100 步进 513 次),513 对
程序实际运行 正常退出,地址正常释放,verify_result.py 校验通过

调用栈说明:

matmul_s4.asc:191:8   ← op.Process()  [kernel entry]
  matmul_s4.asc:102:13  ← Process() 中 AIV 分支调用 Unzip()
    matmul_s4.asc:158:9  ← DataCopy(dstGlobalTensor, dstLocalTensor, count*2)  [两个 AIV 写同一 GM 地址]
  matmul_s4.asc:108:13  ← Process() 中 AIC 分支
    matmul_s4.asc:135:12 ← SetTensorA 读取 aGM  [与 AIV1 的写冲突]

修复建议 (Optional / 选填)

  • 修复方案(推荐,已实施):将跨核同步从 mode 4 改为 mode 2,使 AIC 的 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 侧
  • 优化方案(可选,消除冗余计算):两个 AIV 解压同一份数据属于算力浪费。可让 AIV-0 只解压 A、AIV-1 只解压 B,并按 mode 4 映射规则分别设置 flag(AIV0 → AIC flagId 8,AIV1 → AIC flagId 24),AIC 侧等待两个 flagId 后再执行 Matmul:
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 场景下丢失同步语义。建议在示例层面修复,体现最佳实践。


likedislike
Hh-glue
Sep 17 Modify description of issue
Cchen_xu0513Collaborators
Sep 21 Assign chen_xu0513 as responsible person
chen_xu0513Collaborators
Sep 21 Comments:

您好,感谢指出问题,经分析,当前样例确实存在两个AIV核冗余写同一GM区间和跨核同步未覆盖全部AIV的问题,会尽快修复

likedislike
Cchen_xu0513Collaborators
Sep 21 Associated pull request
Hh-glue
Sep 29 changed custom state from 待办的 to 已解决
Hh-glue
Sep 29 Close issue
chen_xu0513Collaborators
Sep 29 Comments:

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

likedislike
CANN-robotCANN-robotCollaborators
Sep 29 Added label: resolved