Closed
[Bug-Report|缺陷反馈]: aclnnRepeat 超4维 repeat 限制报 561103 内部异常而非 161002 参数非法,且延迟到第二段(实测 ret1=0 / ret2=561103) #3998
liuhanwen8Add on  15 days agoClosed at  10 days ago
liuhanwen8
liuhanwen8
15 days ago Create

现象

aclnnRepeat 的 repeats 违反资料「限制1/限制2」(同时 repeat 的非 1 维度个数超限)时,
第一段 GetWorkspaceSize 返回 0 放行、第二段执行才返回 561103(ACLNN_ERR_INNER_NULLPTR,内部异常);
而同一张错误码表里其它 repeats 入参约束全部由第一段返回 161002(ACLNN_ERR_PARAM_INVALID)。同机逐项实测(FLOAT32):

self / repeats ret(gws) ret(exec)
[2,2,2,2,2] / [2,2,2,2,2](首维非1,5 个非1) 0 561103 缺陷组
[2,2,2,2,2] / [1,2,2,2,2](首维=1,4 个非1) 0 561103 缺陷组
同表三条:[2,2]/[2,-1]、[2,2,2]/[2,2]、rank=9 161002 — 同表对照
合法边界两条:[2,2,2,2,2]/[2,2,2,2,1]、/ [1,2,2,2,1] 0 0 合法对照

期望

资料 math/tile/docs/aclnnRepeat.md「约束说明」原文:

限制1.当需要对第一根轴进行repeat时,最大支持同时对4个维度进行repeat操作(即repeats的参数非1数据个数不超过4)。
限制2.当不需要对第一根轴进行repeat时,最大支持同时对3个维度进行repeat操作。
x.repeat(2, 3, 4, 5, 6) # 不支持,校验报错,第一根轴为repeat为2,同时5个非1repeat参数

资料自己写明这是 「校验报错」 的入参约束,且文中示例正是本次缺陷组 → 应在第一段拦截并返回 161002。

环境

  • 硬件:Ascend 910B2(Atlas A2),npu-smi 26.1.1;CANN 9.2.0,Linux aarch64,g++ 11.4
  • 仓库与提交:cann/ops-math cf5f38c7(git fetch 后的 origin/master,2026-10-26 复现)

复现步骤

  1. 保存下方脚本为 repro.cpp,编译:
    g++ -std=c++17 -O2 repro.cpp -o repro -I$ASCEND_HOME_PATH/aarch64-linux/include -L$ASCEND_HOME_PATH/aarch64-linux/lib64 -lascendcl -lnnopbase -lopapi_math -lopapi
  2. ./repro:缺陷组 GetWorkspaceSize = 0 且 Execute = 561103;同表对照 GetWorkspaceSize = 161002

复现脚本

// aclnnRepeat: 超 4 维限制报 561103(内部异常)而非 161002(参数非法),且延迟到第二段
#include <cstdio>
#include <cstdint>
#include <vector>
#include <cmath>
#include "acl/acl.h"
#include "aclnnop/aclnn_repeat.h"

static aclTensor* Mk(const std::vector<int64_t>& sh, void** dev, bool fill)
{
    int64_t n = 1;
    for (auto d : sh) { n *= d; }
    size_t b = static_cast<size_t>(n) * sizeof(float);
    if (b == 0) { b = 1; }
    if (aclrtMalloc(dev, b, ACL_MEM_MALLOC_HUGE_FIRST) != ACL_SUCCESS) { return nullptr; }
    std::vector<float> h(n > 0 ? n : 1, 0.0f);
    for (int64_t i = 0; i < n; ++i) { h[i] = fill ? static_cast<float>(i + 1) : std::nanf(""); }
    aclrtMemcpy(*dev, b, h.data(), b, ACL_MEMCPY_HOST_TO_DEVICE);
    std::vector<int64_t> st(sh.size(), 1);
    for (int64_t i = static_cast<int64_t>(sh.size()) - 2; i >= 0; --i) { st[i] = sh[i + 1] * st[i + 1]; }
    return aclCreateTensor(sh.data(), sh.size(), ACL_FLOAT, st.data(), 0,
                           ACL_FORMAT_ND, sh.data(), sh.size(), *dev);
}

static void Run(const char* tag, const std::vector<int64_t>& ss,
                const std::vector<int64_t>& rep, const std::vector<int64_t>& os,
                aclrtStream stream)
{
    void* sA = nullptr; void* oA = nullptr;
    aclTensor* self = Mk(ss, &sA, true);
    aclTensor* out = Mk(os, &oA, false);
    aclIntArray* r = aclCreateIntArray(rep.data(), rep.size());
    uint64_t ws = 0; aclOpExecutor* ex = nullptr;
    int ret1 = static_cast<int>(aclnnRepeatGetWorkspaceSize(self, r, out, &ws, &ex));
    printf("%s GetWorkspaceSize = %d\n", tag, ret1);
    if (ret1 == 0) {
        void* wA = nullptr;
        if (ws > 0) { aclrtMalloc(&wA, ws, ACL_MEM_MALLOC_HUGE_FIRST); }
        int ret2 = static_cast<int>(aclnnRepeat(wA, ws, ex, stream));
        printf("%s Execute = %d\n", tag, ret2);
        if (wA != nullptr) { aclrtFree(wA); }
    }
    aclDestroyTensor(self); aclDestroyTensor(out); aclDestroyIntArray(r);
    aclrtFree(sA); aclrtFree(oA);
}

int main()
{
    aclInit(nullptr); aclrtSetDevice(0);
    aclrtStream s = nullptr; aclrtCreateStream(&s);
    Run("[缺陷组-超4维 首维非1]", {2,2,2,2,2}, {2,2,2,2,2}, {4,4,4,4,4}, s);
    Run("[缺陷组-超3维 首维=1]", {2,2,2,2,2}, {1,2,2,2,2}, {2,4,4,4,4}, s);
    Run("[对照组-含负值]", {2,2}, {2,-1}, {4,2}, s);
    Run("[对照组-个数不足]", {2,2,2}, {2,2}, {4,4,2}, s);
    Run("[对照组-rank9]", {1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1}, s);
    Run("[对照组-合法边界4个非1]", {2,2,2,2,2}, {2,2,2,2,1}, {4,4,4,4,2}, s);
    Run("[对照组-合法边界3个非1]", {2,2,2,2,2}, {1,2,2,2,1}, {2,4,4,4,2}, s);
    aclrtDestroyStream(s); aclrtResetDevice(0); aclFinalize();
    return 0;
}

实测输出(完整 7 组见上表):

[缺陷组-超4维 首维非1] GetWorkspaceSize = 0    Execute = 561103
[缺陷组-超3维 首维=1]   GetWorkspaceSize = 0    Execute = 561103
[对照组-含负值/个数不足/rank9] GetWorkspaceSize = 161002
[对照组-合法边界]       GetWorkspaceSize = 0    Execute = 0

影响

  1. 排查方向被带偏:561103 语义是「内部发生了 nullptr 异常」,调用方会去查框架/环境/驱动,
    而实际只需把 repeats 的非 1 维度减到 4(或 3)个以内。
  2. 失败时机被推迟:只在第一段判错的调用方会把责任交给第二段;第二段在 stream 上异步执行,错误要等同步/出队才可见。

建议

  1. 在 math/tile/op_api/aclnn_repeat.cpp 的 CheckParams 补「非 1 维度个数」校验
    (按 repeats 首元素是否为 1 分别判 4 / 3 上限),失败返回 ACLNN_ERR_PARAM_INVALID,
    与 CheckRepeatsSize / CheckRepeatsValue 同级;并同步把资料错误码表该条从
    ACLNN_ERR_INNER_NULLPTR(561103) 移入 ACLNN_ERR_PARAM_INVALID(161002)。
  2. 若只能在 tiling 阶段发现,至少换成面向参数的错误码,并在资料写明「第二段返回」。
likedislike
liuhanwen8liuhanwen8
15 days ago Added label: bug-report
xujiachen8Collaborators
14 days ago Comments:

您好,感谢反馈!

问题分析

核对 cann/ops-math 提交 5f717513abcb6a6b94a4ae61a8151e4ba65e9eb3,第一段入口会检查 repeats 长度、负值、输入维度等,但没有检查“首轴参与 repeat 时最多 4 个非 1 参数,首轴不参与时最多 3 个”的组合限制;随后调用 Tile 构建计算流程。第二段直接返回执行器的运行状态,因此您报告的 0 / 561103 应区分为第一段通过、第二段调用返回内部异常,不能由此推定异常一定到 stream 同步才可见。入口检查与执行路径

还有一处文档口径需要澄清:当前错误码表已将“同时对超过 4 个维度做 repeat”列为 561103,并非明确承诺该项返回 161002;但该表又放在“第一段接口完成入参校验”的说明之后,与您在 Ascend 910B2、CANN 9.2.0 上报告的实际失败阶段不符,约束说明中的“校验报错”也未说明阶段。现有错误码表、两种首轴约束

本轮未重新上板,当前公开入口不足以确定对应交付库中第二段 561103 的内部传播细节。

调整方向

可考虑对适用该限制的产品在第一段检查组合条件,返回便于调用方定位的 161002,并同步更新错误码和阶段说明;这属于校验前移及错误分类的调整,需要评估现有返回码兼容性。检查逻辑还需与首轴、输入扩维、空输出等实际分支一致,避免把某一产品内核的限制直接套用于所有产品。我们会继续评估这一报错时机与分类。

likedislike
Xxujiachen8Collaborators
14 days ago Assign chen_0715 as responsible person
Xxujiachen8Collaborators
14 days ago Added label: pending-confirmation
陈思陈思Collaborators
14 days ago Removed label: pending-confirmation
CchenyifengCollaborators
12 days ago Assign doufloat as responsible person
CchenyifengCollaborators
12 days ago Removed responsible person chen_0715
Bbaijinxiang_hwCollaborators
12 days ago Associated pull request
baijinxiang_hwCollaborators
11 days ago Comments:

您好,感谢反馈。最终处理结论如下。

代码处理

已在 math/tile/op_api/aclnn_repeat.cpp 的第一段接口增加 A2/A3 路径门控:

  • 仅对 ASCEND910B、ASCEND910_93 生效;
  • 首轴参与 repeat(repeats[0] != 1)时,非 1 维度最多 4 个;
  • 首轴不参与 repeat(repeats[0] == 1)时,非 1 维度最多 3 个;
  • 超过限制时 aclnnRepeatGetWorkspaceSize 返回 ACLNN_ERR_PARAM_INVALID(161002);
  • 空 Tensor、repeats 含 0 等不进入 Tile kernel 的既有 no-op 分支保持原行为。

A5 兼容性结论

A5 使用 DAV_3510 路径,实测与 A2/A3 不同:

  • 两个超限场景在 A5 上第一段、第二段均成功,输出校验通过;
  • 因此该限制是 A2/A3 的内部 broadcast kernel 限制,不能在公共第一段无条件拦截;
  • 本次未修改 A5 行为。

实测覆盖

  • A2、A3:fp32/fp16/bf16/int32 × 两个超限场景,8/8 均在第一段返回 161002;
  • A2、A3:合法边界场景 8/8 成功,负值控制项 4/4 返回 161002;
  • A5:两个超限场景 8/8 成功且输出正确,合法边界 8/8 成功;
  • A2、A3、A5 的 tile op_api UT 各 12/12 通过。

资料已同步为:A2/A3 第一段返回 161002,A5 支持超过 4 个非 1 维度。

likedislike
CANN-robotCANN-robotCollaborators
10 days ago Close issue
CANN-robotCANN-robotCollaborators
10 days ago Added label: resolved