Closed
[Documentation|文档反馈]: aclnnInplaceFrac 资料把原地张量 inputRef 的「输入/输出」标成「输入」,与签名和实现不符 #4124
liuhanwen8Add on  11 days agoClosed at  8 days ago
liuhanwen8
liuhanwen8
11 days ago Create

现象

aclnnInplaceFrac 的唯一张量形参 inputRef 是原地写回(既读又写),但资料参数表把它的「输入/输出」列写成「输入」:

  • 资料:math/sub/docs/aclnnFrac&aclnnInplaceFrac.md,锚点 L253–L254(aclnnInplaceFracGetWorkspaceSize 参数表)
  • 原文:<td>inputRef(aclTensor*)</td> / <td>输入</td> / <td>待进行frac计算的输入tensor。</td>

同一份资料的三处口径互不一致:

  1. 同文件函数原型(L57–L58)是非 const:aclnnStatus aclnnInplaceFracGetWorkspaceSize( / aclTensor* inputRef,
  2. 头文件 math/sub/op_api/aclnn_frac.h:74 同样非 const:aclnnInplaceFracGetWorkspaceSize(aclTensor* inputRef, ...);对照同文件 L35 的只读入参是 const aclTensor* input
  3. 实现 math/sub/op_api/aclnn_frac.cpp 中 aclnnInplaceFracGetWorkspaceSize 直接调用 ExecFracGetWorkspaceSize(inputRef, inputRef),末尾 ViewCopy(fracOutRet, out) 把结果写回同一 buffer

同仓横向对照:**/docs/*.md 共 83 条 XxxRef(aclTensor*) 参数行,75 条(90%)在「输入/输出」列标「输入/输出」(59 条「输入/输出」、7 条「输入输出」、9 条「输入|输出」),本文件属7 条例外之一。资料正文里「原地」「写回」出现 0 次,仅示例变量名 inplaceWorkspaceSize 间接暗示。

期望

参数表 inputRef 的「输入/输出」列改为输入/输出(与签名、实现、同仓 90% 口径一致);「功能说明」补一句写回语义——该段目前与 aclnnFrac 共用,只写「计算输入Tensor中每个元素的小数部分后输出」,未说明结果写回原张量。

环境

  • 仓:cann/ops-math,分支 master,提交 21848df45078c387db46718f43db0ebc26e93661(2026-10-27 git fetch 后核对,该行仍为「输入」);资料 sha256 前 16 位 8035eb83b71a4aa1
  • 硬件:Atlas A2 训练系列(910B2);CANN 9.2.0;OS:openEuler aarch64。原地写回已实测:带 storageOffset 的切片视图,视图内 32/32 元素正确、视图外 0/32 被写

复现步骤

  1. git clone https://gitcode.com/cann/ops-math.git && cd ops-math && git checkout 21848df45078c387db46718f43db0ebc26e93661
  2. 将下方脚本保存为 frac_doc_role.py
  3. 在仓根执行 python3 frac_doc_role.py --repo-root .
  4. 查看退出码为 1,输出含 [DEFECT] 与 got=<td>输入</td>

复现脚本

#!/usr/bin/env python3
# 断言 aclnnInplaceFrac 资料把原地张量 inputRef 的角色标成「输入」。
# rc: 0=无缺陷 / 1=缺陷成立(打印 [DEFECT])/ 2=无法判定
# 用法: python3 frac_doc_role.py [--repo-root <ops-math 仓根>]
import os, re, sys

DOC = "math/sub/docs/aclnnFrac&aclnnInplaceFrac.md"
HDR = "math/sub/op_api/aclnn_frac.h"


def root_of(argv):
    cand = []
    if "--repo-root" in argv:
        i = argv.index("--repo-root")
        cand += argv[i + 1:i + 2]
    cand += [a for a in argv[1:] if not a.startswith("-")]
    cand += [".", "repos/ops-math", "~/ops-math"]
    for c in cand:
        if os.path.isfile(os.path.join(c, DOC)):
            return c
    return None


def row_role(text, name="inputRef"):
    for tr in re.findall(r"<tr>(.*?)</tr>", text, re.S):
        tds = [re.sub(r"<[^>]+>", "", x).strip()
               for x in re.findall(r"<td[^>]*>(.*?)</td>", tr, re.S)]
        if len(tds) > 1 and tds[0].startswith(name):
            return tds[0], tds[1]
    return None, None


def first_param(text, fn):
    m = re.search(re.escape(fn) + r"\s*\((.*?)\)\s*;", text, re.S)
    if not m:
        return None, False
    p = m.group(1).split(",")[0].strip()
    return p, ("const" not in p)


root = root_of(sys.argv)
if not root:
    print("[UNDECIDED] 找不到 ops-math 仓根(把脚本放仓根或传 --repo-root)")
    sys.exit(2)
doc = open(os.path.join(root, DOC), encoding="utf-8").read()
cell, role = row_role(doc)
if role is None:
    print("[UNDECIDED] 资料里没有 inputRef(aclTensor*)参数行")
    sys.exit(2)
line = doc[: doc.find("<td>%s</td>" % cell)].count("\n") + 1
proto, writable = first_param(doc, "aclnnInplaceFracGetWorkspaceSize")
hdr_first, hdr_writable = first_param(
    open(os.path.join(root, HDR), encoding="utf-8").read(), "aclnnInplaceFracGetWorkspaceSize")
print("[anchors]%s:%d 参数行=%r 角色列=%r" % (DOC, line, cell, role))
print("[anchors] 资料原型首个形参=%r 非const=%s" % (proto, writable))
print("[anchors] 头文件首形参=%r 非const=%s" % (hdr_first, hdr_writable))
if role.replace("|", "/").replace(" ", "") in ("输入/输出", "输入输出"):
    print("[OK] 角色列已是「输入/输出」")
    sys.exit(0)
if not (writable and hdr_writable):
    print("[OK] 签名是 const 只读,标「输入」成立")
    sys.exit(0)
print("[DEFECT] 角色列=%r,但资料原型与头文件均为非 const 可写、实现原地写回同一 buffer" % role)
print("         expected=<td>输入/输出</td> got=<td>%s</td>" % role)
sys.exit(1)

实测输出(文本断言,无需上板;退出码 1):

[anchors]math/sub/docs/aclnnFrac&aclnnInplaceFrac.md:253 参数行='inputRef(aclTensor*)' 角色列='输入'
[anchors] 资料原型首个形参='aclTensor*      inputRef' 非const=True
[anchors] 头文件首形参='aclTensor* inputRef' 非const=True
[DEFECT] 角色列='输入',但资料原型与头文件均为非 const 可写、实现原地写回同一 buffer
         expected=<td>输入/输出</td> got=<td>输入</td>

影响

  • 使用者按参数表把 inputRef 当只读入参时,会认为调用后原 tensor 不变;该接口恰恰把结果写回原 buffer,而资料正文对「原地写回」零字说明。
  • 5 个同类接口存在同一标注(不同接口,未合并):aclnnFmodTensor&aclnnInplaceFmodTensor.md、aclnnFmodScalar&aclnnInplaceFmodScalar.md、aclnnMuls&aclnnInplaceMuls.md、aclnnSubs&aclnnInplaceSubs.md、aclnnClampMinTensor&aclnnInplaceClampMinTensor.md;不影响功能与精度(2000 条精度 + 40 条确定性全部通过),按 P2 提交。

建议

本文件与上述 5 个文件同批修订「输入/输出」列,「功能说明」段补一句「结果原地写回 inputRef」;若仓库已有「原地接口 Ref 张量在参数表统一标 输入/输出」的口径,可将本单脚本接入资料检视门禁,避免新增文档回退。

likedislike
liuhanwen8liuhanwen8
11 days ago Added label: documentation
xujiachen8Collaborators
10 days ago Comments:

您好,感谢反馈!核对 master b08e885e7fac370203a51904fd0680523b9a9205,原地接口参数表确实将 inputRef 只标为“输入”。实现中 aclnnInplaceFracGetWorkspaceSize 将同一张量传给 ExecFracGetWorkspaceSize 的 input 和 out,结果经 ViewCopy 写回该张量;这比仅依据非 const 签名更直接地证明其读写角色。

可将该参数改为“输入/输出”,并在功能说明中明确结果写回 inputRef,使调用方了解原数据会被更新。头文件的参数方向注释也宜一起核对。此项属于说明修订,无需改变函数签名或数值计算流程。您列举的其他接口可以按各自实现逐一检视后修订,不宜仅凭命名统一替换;切片写回结果沿用您的报告,本轮尚未独立上板复测。

核对依据:aclnnFrac、aclnnInplaceFrac.md;aclnn_frac.cpp;aclnn_frac.h。

likedislike
Xxujiachen8Collaborators
10 days ago Assign chen_0715 as responsible person
Xxujiachen8Collaborators
10 days ago Added label: pending-confirmation
陈思陈思Collaborators
10 days ago Removed label: pending-confirmation
CANN-robotCANN-robotCollaborators
8 days ago Close issue
CANN-robotCANN-robotCollaborators
8 days ago Added label: resolved