已关闭
[Bug] reduce_sum_v2 AxesAll 对齐 pad 污染合法全归约求和 #2605
Agent-Bug-Hunter创建于 8月13日关闭于 9月20日
陈思
8月20日 评论:
8月20日 评论:
8月20日 关联了pull request:fix(reduce_sum_v2): ignore aligned tail elements
8月20日 将 chensi79 设为负责人
8月28日 删除了关联的pull request:fix(reduce_sum_v2): ignore aligned tail elements
8月28日 关联了pull request:fix(reduce_sum_v2): ignore aligned tail elements
8月28日 删除了关联的pull request:fix(reduce_sum_v2): ignore aligned tail elements
8月28日 删除了关联的pull request:fix(reduce_sum_v2): ignore aligned tail elements
9月20日 移除了负责人 chensi79
9月20日 将 chensi79 设为负责人
9月20日 移除了负责人 chensi79
9月20日 将 xujiachen8 设为负责人
Xxujiachen8
9月20日 关联了pull request:fix(experimental): 修复 reduce_sum_v2/reduce_max_v2 AxesAll 对齐 pad 污染 (issues #2605 #3134)
9月20日 关联了pull request:fix(experimental): 修复 reduce_sum_v2/reduce_max_v2 AxesAll 对齐 pad 污染 (issues #2605 #3134)
xujiachen8
9月20日 评论:
9月20日 评论:
已完成复现与修复。根因与之前同步的一致:AxesAll 全归约按 32B 对齐后的 tile/tail 长度累加,末 tile 把 GM 对齐 pad 计入求和。
修复方式:DataCopy 保持按对齐长度搬运(MTE2 对齐约束),求和循环改为只统计按 coreDataNum(逻辑长度)裁剪后的 validLen 个元素,pad 不再参与归约;CopyIn 改由调用方传入实际搬运长度,Axes0/Axes1 语义不变。
真机验证(Ascend910B 系列 + CANN 9.2.0,单算子包源码编译安装后走 aclnn):
- 基线按 issue 用例复现成功:sum=3005(期望 5,exit 42)
- 修复后:sum=5(exit 0)
- 扩展回归 14 组用例全部通过:fp32/fp16 AxesAll+canary pad、Axes0/Axes1+pad、{1,100003} 多核多 tile 非对齐尾对照 CPU golden、{1,8} 对齐输入无 pad;ascend910b 编译通过
修复 PR:!5858


9月20日 关闭了 issue
9月20日 添加了label:resolved
摘要
experimental
reduce_sum_v2与 mean_v2 同构 AxesAll pad 污染。复现 actual=3005(期望 5)。环境
2d1098d3e902cann-ops-math-cann_scan_repro_linux-*.run→$ASCEND_HOME_PATH/vendors/cann_scan_repro_math为什么认为这是问题:期望 vs 实际
输入(与复现用例一致)
期望行为
实际行为(aclnn / 源码编译安装路径)
对比结论
根因
$OPS_MATH/experimental/math/reduce_sum_v2/op_kernel/reduce_sum_v2.hAxesAll。为何确认跑的是源码编译内核(非 built-in)
source $ASCEND_HOME_PATH/vendors/cann_scan_repro_math/bin/set_env.bash,ASCEND_CUSTOM_OPP_PATH指向该 vendor。op_api/op_impl,而非仅依赖 CANN built-in 同名算子(见repro_manifest.json中built_from_source=true)。完整复现过程
占位符:
$ASCEND_HOME_PATH/$OPS_MATH/$REPRO_ROOT。步骤 1:环境使能
source <CANN安装目录>/ascend-toolkit/set_env.sh步骤 2:源码编译单算子包
cd "$OPS_MATH" bash build.sh --pkg --soc=ascend910b --ops=reduce_sum_v2 --experimental \ --vendor_name=cann_scan_repro -j8成功标志:生成
$OPS_MATH/build_out/cann-ops-math-cann_scan_repro_linux-*.run步骤 3:安装并切换到自定义包
bash $OPS_MATH/build_out/cann-ops-math-cann_scan_repro_linux-*.run \ --quiet --install-path="$ASCEND_HOME_PATH" source "$ASCEND_HOME_PATH/vendors/cann_scan_repro_math/bin/set_env.bash" echo "ASCEND_CUSTOM_OPP_PATH=$ASCEND_CUSTOM_OPP_PATH"步骤 4:放置复现源码与执行脚本
(本 draft 目录内已含上述文件,可直接作为
$REPRO_ROOT。)步骤 5:编译并运行
cd "$REPRO_ROOT" chmod +x build_and_run_repro.sh bash build_and_run_repro.sh --vendor cann_scan_repro --src test_aclnn_reduce_sum_v2_axesall_pad.cpp # 退出码 42 = BUG_REPRODUCED成功复现标志:进程退出码 42。
实际运行摘录
复现用例源码
文件名:
test_aclnn_reduce_sum_v2_axesall_pad.cpp/** * Track B — MATH-RSV2-001: same AxesAll pad contamination as mean_v2 for sum. * Exit 42 = BUG_REPRODUCED. */ #include <cmath> #include <cstdio> #include <cstdint> #include <vector> #include "acl/acl.h" #include "aclnn_reduce_sum_v2.h" #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) static int Init(int32_t deviceId, aclrtStream* stream) { auto ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); ret = aclrtSetDevice(deviceId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); ret = aclrtCreateStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); return 0; } int main() { const int64_t logicalN = 5; const int64_t allocN = 8; std::vector<float> xHost(allocN, 1000.f); for (int64_t i = 0; i < logicalN; ++i) { xHost[i] = 1.f; } const std::vector<int64_t> xShape = {1, logicalN}; const std::vector<int64_t> yShape = {1, 1}; const float expected = 5.f; int32_t deviceId = 0; aclrtStream stream; auto ret = Init(deviceId, &stream); CHECK_RET(ret == ACL_SUCCESS, return 1); void* xAddr = nullptr; ret = aclrtMalloc(&xAddr, allocN * sizeof(float), ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, return 1); ret = aclrtMemcpy(xAddr, allocN * sizeof(float), xHost.data(), allocN * sizeof(float), ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret == ACL_SUCCESS, return 1); std::vector<int64_t> strides = {logicalN, 1}; aclTensor* x = aclCreateTensor(xShape.data(), xShape.size(), aclDataType::ACL_FLOAT, strides.data(), 0, aclFormat::ACL_FORMAT_ND, xShape.data(), xShape.size(), xAddr); void* yAddr = nullptr; float yInit = -999.f; ret = aclrtMalloc(&yAddr, sizeof(float), ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, return 1); ret = aclrtMemcpy(yAddr, sizeof(float), &yInit, sizeof(float), ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret == ACL_SUCCESS, return 1); std::vector<int64_t> yStrides = {1, 1}; aclTensor* y = aclCreateTensor(yShape.data(), yShape.size(), aclDataType::ACL_FLOAT, yStrides.data(), 0, aclFormat::ACL_FORMAT_ND, yShape.data(), yShape.size(), yAddr); int64_t axes = -1; int64_t keepdims = 1; uint64_t workspaceSize = 0; aclOpExecutor* executor = nullptr; ret = aclnnReduceSumV2GetWorkspaceSize(x, axes, keepdims, y, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("GetWorkspaceSize failed. ERROR: %d\n", ret); return 1); void* workspaceAddr = nullptr; if (workspaceSize > 0) { ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, return 1); } ret = aclnnReduceSumV2(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReduceSumV2 failed. ERROR: %d\n", ret); return 1); ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("SynchronizeStream failed. ERROR: %d\n", ret); return 1); float actual = -999.f; ret = aclrtMemcpy(&actual, sizeof(float), yAddr, sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret == ACL_SUCCESS, return 1); LOG_PRINT("=== expect vs actual (axes=-1, ones{1,5} + canary1000 pad) ===\n"); LOG_PRINT(" [0] expected=%.8g actual=%.8g\n", expected, actual); bool mismatch = !std::isfinite(actual) || std::fabs(actual - expected) > 1e-3f; aclDestroyTensor(x); aclDestroyTensor(y); aclrtFree(xAddr); aclrtFree(yAddr); if (workspaceAddr) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); if (mismatch) { LOG_PRINT("\nVERDICT: BUG_REPRODUCED (exit 42) — AxesAll pad contaminates sum\n"); return 42; } LOG_PRINT("\nVERDICT: NO_REPRO\n"); return 0; }执行脚本
文件名:
build_and_run_repro.sh#!/usr/bin/env bash # Build/run math vendor aclnn (links libcust_opapi; vendor include first). set -euo pipefail VENDOR="" SRC_NAME="" while [[ $# -gt 0 ]]; do case "$1" in --vendor) VENDOR="$2"; shift 2 ;; --src) SRC_NAME="$2"; shift 2 ;; *) echo "unknown arg: $1" >&2; exit 2 ;; esac done : "${ASCEND_HOME_PATH:?请先 source CANN set_env.sh}" ROOT="$(cd "$(dirname "$0")" && pwd)" if [[ -z "$SRC_NAME" ]]; then mapfile -t _srcs < <(ls "$ROOT"/test_aclnn_*.cpp 2>/dev/null || true) if [[ ${#_srcs[@]} -ne 1 ]]; then echo "请用 --src 指定测试文件" >&2 exit 2 fi SRC="${_srcs[0]}" else SRC="$ROOT/$SRC_NAME" fi BIN="${SRC%.cpp}" VENDOR_DIR="" if [[ -n "$VENDOR" ]]; then for cand in \ "${ASCEND_HOME_PATH}/vendors/${VENDOR}_math" \ "${ASCEND_HOME_PATH}/vendors/${VENDOR}_nn" \ "${ASCEND_HOME_PATH}/vendors/${VENDOR}_cv" \ "${ASCEND_HOME_PATH}/vendors/${VENDOR}" do if [[ -f "$cand/bin/set_env.bash" ]]; then set +u # shellcheck disable=SC1090 source "$cand/bin/set_env.bash" set -u VENDOR_DIR="$cand" echo "[env] sourced $cand/bin/set_env.bash" echo "[env] ASCEND_CUSTOM_OPP_PATH=${ASCEND_CUSTOM_OPP_PATH:-}" break fi done fi INC="${ASCEND_HOME_PATH}/aarch64-linux/include" LIB="${ASCEND_HOME_PATH}/aarch64-linux/lib64" [[ -d "$INC" ]] || INC="${ASCEND_HOME_PATH}/include" [[ -d "$LIB" ]] || LIB="${ASCEND_HOME_PATH}/lib64" VENDOR_INC="" VENDOR_LIB="" if [[ -n "$VENDOR_DIR" ]]; then VENDOR_INC="$VENDOR_DIR/op_api/include" VENDOR_LIB="$VENDOR_DIR/op_api/lib" fi echo "[build] g++ $SRC" g++ -std=c++17 -O2 "$SRC" \ ${VENDOR_INC:+-I"$VENDOR_INC"} -I"$INC" -I"$INC/aclnnop" \ -L"$LIB" ${VENDOR_LIB:+-L"$VENDOR_LIB"} \ -Wl,-rpath,"$LIB"${VENDOR_LIB:+ -Wl,-rpath,"$VENDOR_LIB"} \ -lascendcl -lnnopbase ${VENDOR_LIB:+-lcust_opapi} -lopapi \ -o "$BIN" echo "[run] $BIN" set +e "$BIN" RC=$? set -e echo "[exit] $RC (42=BUG_REPRODUCED, 0=NO_REPRO, 1=harness error)" exit "$RC"修复建议
按文档/torch 参考语义修正计算或 tiling;补充合法输入单测与期望对照。
人工复核说明
Agent 复现结果供参考;语义边界(是否允许 wrap、文档是否声明调用方契约)以人工结论与产品规范为准。