CANN opbase 公共接口全景指南:aclTensor 与 aclnn 元数据 API 的创建、销毁与复用实战

发布时间:2026/9/18 3:06:11
CANN opbase 公共接口全景指南:aclTensor 与 aclnn 元数据 API 的创建、销毁与复用实战 CANN opbase 公共接口全景指南aclTensor 与 aclnn 元数据 API 的创建、销毁与复用实战【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase本文以 docs/zh/api/nnopbase/aclnn/public_interface.md 及其全部关联子文档为骨架系统讲解 CANN 算子库基础框架库opbase中 aclnn API 所依赖的公共 Meta 接口——涵盖 aclTensor、aclScalar、aclIntArray 等数据结构的创建/销毁/查询、Device 地址刷新、Executor 复用以及初始化/去初始化全流程。读者学完后将能独立完成单算子 API 调用前的参数封装与调用后的资源清理理解 StorageShape/ViewShape/stride/offset 的内在机制并掌握可复用 Executor 模式下地址刷新的正确姿势。文中代码示例来自官方文档可直接作为编码参考仓库源码路径作为纵深依据供深入研读。一、公共接口是什么单算子 API 的元数据底座在 CANN 框架中aclnn API如aclnnXxx是上层框架与昇腾算子库之间的标准调用入口。调用这类接口时除了算子自身的输入输出张量往往还需要携带标量如 alpha 系数、整型数组如 pad 参数、布尔数组如 mask等辅助参数。这些参数无法直接用 C 原生类型表达因此 CANN 定义了一套统一的元数据包装结构aclTensor、aclScalar、aclIntArray、aclFloatArray、aclBoolArray、aclTensorList、aclScalarList。public_interface.md正是这套公共接口的导航中枢它串联了 公共接口列表含 35 个接口的速查表、34 个单接口详解文档、预留接口 以及 公共接口返回码。从仓库源码可以验证这些结构是纯不透明句柄opaque handleinclude/nnopbase/aclnn/acl_meta.h 中以typedef struct aclTensor aclTensor;的形式仅做前向声明开发者只能通过公共 API 操作它们无法也无需接触内部布局。而 src/nnopbase/common/api/acl_op_api.cpp 展示了aclCreateTensor与aclCreateScalar的真实实现前者在参数非法如viewDims与viewDimsNum不匹配时返回nullptr后者在value nullptr时直接失败——这印证了创建失败返回 nullptr的文档约定。头文件说明调用本章接口时按实际情况 include 依赖的头文件一般定义在${INSTALL_DIR}/include目录。其中${INSTALL_DIR}为 CANN 软件安装路径以 root 安装举例为/usr/local/Ascend/cann。元数据类接口统一声明于aclnn/acl_meta.h而初始化/去初始化接口位于aclnn/aclnn_base.h。二、公共接口总览一张表看清 35 个 Meta 接口public_interface_list.md 给出了完整速查表按功能可划分为五大类2.1 创建类接口7 个接口说明所属头文件aclCreateBoolArray创建 aclBoolArrayaclnn/acl_meta.haclCreateFloatArray创建 aclFloatArrayaclnn/acl_meta.haclCreateIntArray创建 aclIntArrayaclnn/acl_meta.haclCreateScalar创建 aclScalaraclnn/acl_meta.haclCreateScalarList创建 aclScalarListaclnn/acl_meta.haclCreateTensor创建 aclTensoraclnn/acl_meta.haclCreateTensorList创建 aclTensorListaclnn/acl_meta.h2.2 销毁类接口8 个接口说明所属头文件aclDestroyAclOpExecutor销毁可复用状态的 aclOpExecutoraclnn/acl_meta.haclDestroyBoolArray / FloatArray / IntArray销毁对应数组aclnn/acl_meta.haclDestroyScalar销毁 aclScalaraclnn/acl_meta.haclDestroyScalarList销毁 aclScalarList内部 Scalar 不需再重复释放aclnn/acl_meta.haclDestroyTensor销毁 aclTensoraclnn/acl_meta.haclDestroyTensorList销毁 aclTensorList内部 Tensor 不需再重复释放aclnn/acl_meta.h注意销毁的所有权转移语义aclDestroyTensorList销毁列表时列表内的 Tensor 由列表一并释放不要再对每个元素单独调用aclDestroyTensor否则构成重复释放。aclDestroyScalarList同理。2.3 查询类接口14 个接口说明aclGetBoolArraySize / FloatArraySize / IntArraySize获取对应数组的大小aclGetDataType获取 aclTensor 的 DataTypeaclGetFormat获取 aclTensor 的 formataclGetRawTensorAddr获取 aclTensor 中原始记录的 Device 内存地址aclGetScalarListSize / TensorListSize获取列表大小aclGetStorageShape获取 aclTensor 的 StorageShapeaclGetViewOffset获取 ViewShape 对应的 offsetaclGetViewShape获取 aclTensor 的 ViewShapeaclGetViewStrides获取 ViewShape 对应的 stride2.4 地址刷新类接口7 个接口说明aclSetDynamicInputTensorAddr / OutputTensorAddr / TensorAddrExecutor 复用后刷新输入/输出/双向 aclTensorList 记录的 Device 地址aclSetInputTensorAddr / OutputTensorAddr / TensorAddrExecutor 复用后刷新单个 aclTensor 记录的 Device 地址aclSetRawTensorAddr刷新 aclTensor 中原始记录的 Device 内存地址2.5 生命周期与复用类接口3 个接口说明aclSetAclOpExecutorRepeatable开启 aclOpExecutor 为可复用状态aclnnInitaclnn API 的初始化函数aclnn/aclnn_base.haclnnFinalizeaclnn API 的去初始化函数aclnn/aclnn_base.h从 include/nnopbase/aclnn/acl_meta.h 可以看到上述全部接口的原型均以ACL_FUNC_VISIBILITY导出且查询类接口统一采用输出参数模式如aclGetViewShape(const aclTensor* tensor, int64_t** viewDims, uint64_t* viewDimsNum)调用方传入指针地址接收结果。三、核心数据结构与创建接口实战3.1 aclTensorViewShape 与 StorageShape 的二元世界aclCreateTensor是公共接口中使用频率最高、也最需要理解内存模型的接口。函数原型aclTensor *aclCreateTensor(const int64_t *viewDims, uint64_t viewDimsNum, aclDataType dataType, const int64_t *stride, int64_t offset, aclFormat format, const int64_t *storageDims, uint64_t storageDimsNum, void *tensorData)核心概念StorageShape 与 ViewShapeViewShapeTensor 的逻辑 shape是 Tensor 在实际使用时需要用到的大小。StorageShapeTensor 的实际物理排布 shape是 Tensor 在内存上实际存在的大小。举例StorageShape 为[10, 20]该 Tensor 在内存上按[10, 20]排布。ViewShape 为[2, 5, 20]在算子使用时该 Tensor 可被视为一块[2, 5, 20]的数据使用。参数说明参数名输入/输出说明viewDims输入tensor 的 ViewShape 维度值为非负整数viewDimsNum输入tensor 的 ViewShape 维度数dataType输入tensor 的数据类型stride输入tensor 各维度元素的访问步长为非负整数offset输入tensor 首元素相对于 storage 的偏移为非负整数format输入tensor 的数据排布格式storageDims输入tensor 的 StorageShape 维度值为非负整数storageDimsNum输入tensor 的 StorageShape 维度数tensorData输入tensor 在 Device 侧的存储地址该地址必须 32 字节对齐否则可能出现未定义错误约束与配套本接口必须与 aclDestroyTensor 配套使用完成创建与销毁的闭环。需要批量张量时用 aclCreateTensorList 存储张量列表需要初始化已存在 tensor 的参数时使用 aclInitTensor。调用示例来自 aclCreateTensor.md仅供参考不支持直接拷贝运行aclTensor *CreateXTensor() { std::vectorint64_t viewDims {2, 4}; std::vectorint64_t stride {4, 1}; // 第1维步长4第2维步长1 std::vectorint64_t storageDims {2, 4}; return aclCreateTensor(viewDims.data(), 2, ACL_FLOAT16, stride.data(), 0, ACL_FORMAT_ND, storageDims.data(), 2, nullptr); } // x 对应的转置 x^T通过 stride 表达转置跨度 aclTensor *CreateXTransposedTensor() { std::vectorint64_t viewDims {4, 2}; std::vectorint64_t stride {1, 4}; // 转置跨度通过stride表示 std::vectorint64_t storageDims {2, 4}; return aclCreateTensor(viewDims.data(), 2, ACL_FLOAT16, stride.data(), 0, ACL_FORMAT_ND, storageDims.data(), 2, nullptr); }上图展示了 aclTensor 的视图本质同一块原始内存storage通过不同的shape/stride/offset组合可以派生多个逻辑视图。以x为例viewDims[2,4]、stride[4,1]、offset0它按行优先完整覆盖原始 8 个元素而以offset1、stride[3,2]、viewDims[2,2]描述的y则从内存中取出了[2,4;5,7]这样的非连续子视图——这正是转置、切片等算子场景下 aclTensor 可以零拷贝表达非连续内存的底层原理。源码佐证从 src/nnopbase/common/api/acl_op_api.cpp 的实现看aclCreateTensor会先做入参校验viewDims/storageDims与对应维数不匹配时返回nullptr随后new一个aclTensor对象并传入全部描述信息。此外src/nnopbase/common/api/acl_op_api.cpp 附近还包含对 PCIe 与 non-PCIe 地址互刷的校验逻辑提示刷新 Device 地址时需保持地址类型一致否则会以ACLNN_ERR_PARAM_INVALID报错。3.2 aclScalar单值参数的载体aclScalar *aclCreateScalar(void *value, aclDataType dataType)参数名输入/输出说明value输入Host 侧的 scalar 类型指针其指向的值会作为 scalardataType输入scalar 的数据类型需与 aclDestroyScalar 配套使用。多个标量可先各自aclCreateScalar再用aclCreateScalarList组装成列表。调用示例// 创建aclScalar float alphaValue 1.2f; aclScalar* alpha aclCreateScalar(alphaValue, aclDataType::ACL_FLOAT); ... // 作为单算子API执行接口的入参 auto ret aclxxXxxGetWorkspaceSize(srcTensor, alpha, ..., outTensor, ..., workspaceSize, executor); ret aclxxXxx(...); ... // 销毁aclScalar ret aclDestroyScalar(alpha);从 src/nnopbase/common/api/acl_op_api.cpp 可见aclCreateScalar内部会通过op::ToOpDataType(dataType)将 acl 侧数据类型转换为算子侧类型再封装这也解释了为何标量数据类型需要与算子期望一致。3.3 三种数组aclIntArray / aclFloatArray / aclBoolArray三种数组接口形态完全一致仅元素类型不同aclIntArray *aclCreateIntArray(const int64_t *value, uint64_t size); // size为正整数 aclFloatArray *aclCreateFloatArray(const float *value, uint64_t size); // size为正整数 aclBoolArray *aclCreateBoolArray(const bool *value, uint64_t size); // size为正整数调用示例分别来自 aclCreateIntArray.md、aclCreateFloatArray.md、aclCreateBoolArray.md// 整型数组常用于表示 pad、size 等整形参数 std::vectorint64_t sizeData {1, 1, 2, 3}; aclIntArray *size aclCreateIntArray(sizeData.data(), sizeData.size()); // 浮点数组常用于表示 scale 等浮点参数 std::vectorfloat scalesData {1.0, 1.0, 2.0, 2.0}; aclFloatArray *scales aclCreateFloatArray(scalesData.data(), scalesData.size()); // 布尔数组常用于表示 mask 等开关参数 bool maskData[] {true, false}; aclBoolArray *mask aclCreateBoolArray(maskData, sizeof(maskData) / sizeof(maskData[0])); // 使用后逐一销毁 ret aclDestroyIntArray(size); ret aclDestroyFloatArray(scales); ret aclDestroyBoolArray(mask);文档明确说明aclCreateIntArray会将指针指向的值拷贝给 aclIntArray因此传入的 Host 侧缓冲区在创建后即可安全复用或释放。数组大小可用aclGetIntArraySize/aclGetFloatArraySize/aclGetBoolArraySize查询。3.4 列表aclTensorList 与 aclScalarList当算子需要不定长的张量/标量序列如动态输入个数场景时使用列表结构aclTensorList *aclCreateTensorList(const aclTensor *const *value, uint64_t size); // size为正整数 aclScalarList *aclCreateScalarList(const aclScalar *const *value, uint64_t size); // size为正整数调用示例来自 aclCreateTensorList.md// 创建aclTensor: input1 input2 std::vectorint64_t shape {1, 2, 3}; aclTensor *input1 aclCreateTensor(shape.data(), shape.size(), aclDataType::ACL_FLOAT, nullptr, 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), nullptr); aclTensor *input2 aclCreateTensor(shape.data(), shape.size(), aclDataType::ACL_FLOAT, nullptr, 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), nullptr); // 创建aclTensorList std::vectoraclTensor * tmp{input1, input2}; aclTensorList* tensorList aclCreateTensorList(tmp.data(), tmp.size()); ... // 销毁aclTensorList内部Tensor随之释放勿再单独销毁input1/input2 ret aclDestroyTensorList(tensorList);约束要点调用列表创建接口前需先分别创建好元素对象aclCreateTensor/aclCreateScalar。列表与销毁接口配套列表销毁后无需再逐个销毁内部元素。aclCreateTensorList创建的列表其内部元素可通过 aclSetDynamicInputTensorAddr / aclSetDynamicOutputTensorAddr / aclSetDynamicTensorAddr 刷新 Device 内存地址配合 Executor 复用。四、查询类接口读取 aclTensor 的元数据创建之后可通过成对的 Get 接口反查 aclTensor 的全部描述信息接口原型返回值语义aclGetViewShape(tensor, viewDims, viewDimsNum)逻辑 shape 与维数aclGetStorageShape(tensor, storageDims, storageDimsNum)物理排布 shape 与维数aclGetViewStrides(tensor, strides, stridesNum)ViewShape 对应的 strideaclGetViewOffset(tensor, offset)ViewShape 对应的 offsetaclGetFormat(tensor, format)数据排布格式aclGetDataType(tensor, dataType)数据类型aclGetTensorListSize(tensorList, size)/aclGetScalarListSize(scalarList, size)列表长度aclGetIntArraySize/aclGetFloatArraySize/aclGetBoolArraySize数组长度aclGetRawTensorAddr(tensor, addr)原始记录的 Device 内存地址这些接口在调试、序列化、以及算子调用前后校验参数时非常有用。查询接口均在 include/nnopbase/aclnn/acl_meta.h 声明实现在 src/nnopbase/common/api/acl_op_api.cpp 起的方法中均返回aclnnStatus成功为 0。五、Executor 复用模式与地址刷新接口这是公共接口中性能敏感的一组接口适用于同一算子、同一组张量形状、反复执行的高频推理场景如循环中对同一模型反复调用。默认情况下每次调用aclnnXxx都会经历完整的 Executor 创建-执行-销毁流程开启复用后可显著减少重复的图/任务构建开销。5.1 开启复用aclnnStatus aclSetAclOpExecutorRepeatable(aclOpExecutor *executor);在GetWorkspaceSize拿到executor之后、正式执行之前调用将 executor 标记为可复用状态。只有开启复用的 executor 才需要且必须用 aclDestroyAclOpExecutor 显式销毁非复用 executor 由框架在任务执行后自动回收。5.2 地址刷新接口矩阵开启复用后tensor 的 Device 内存地址若在多次执行间发生变更例如显存池复用、双缓冲交替必须刷新 executor 内部缓存的地址否则会读到旧地址导致错误。刷新接口按刷新对象分为两组单 tensor 维度参数为executor, index, tensor, addr接口适用场景aclSetInputTensorAddr输入单个 aclTensor 地址变更aclSetOutputTensorAddr输出单个 aclTensor 地址变更aclSetTensorAddr输入或输出单个 aclTensor 地址变更列表维度参数为executor, irIndex, relativeIndex, tensors, addr接口适用场景aclSetDynamicInputTensorAddr输入 aclTensorList 地址变更aclSetDynamicOutputTensorAddr输出 aclTensorList 地址变更aclSetDynamicTensorAddr输入或输出 aclTensorList 地址变更典型复用流程// 第一次调用创建参数、获取workspace并开启复用 auto ret aclxxXxxGetWorkspaceSize(xTensor, ..., outTensor, ..., workspaceSize, executor); ret aclSetAclOpExecutorRepeatable(executor); // 开启复用 ret aclxxXxx(workspace, workspaceSize, executor, stream); // 首次执行 // 后续循环仅刷新变更的地址后重新执行 ret aclSetInputTensorAddr(executor, 0, xTensor, newAddr); // 输入地址变了 ret aclxxXxx(workspace, workspaceSize, executor, stream); // 再次执行 ... // 结束显式销毁可复用executor ret aclDestroyAclOpExecutor(executor);5.3 aclSetRawTensorAddr / aclGetRawTensorAddr这对接口直接操作 aclTensor 中记录的原始Device 内存地址不涉及 Executor 状态aclnnStatus aclSetRawTensorAddr(aclTensor *tensor, void *addr); aclnnStatus aclGetRawTensorAddr(const aclTensor *tensor, void **addr);aclSetRawTensorAddr用于刷新 aclTensor 自身记录的 Device 地址aclGetRawTensorAddr用于读取。从 src/nnopbase/common/api/acl_op_api.cpp 的实现看刷新地址时会校验新旧地址的 PCIe/non-PCIe 类型是否一致不一致时报ACLNN_ERR_PARAM_INVALID并输出详细日志——这提醒我们在多卡/异构内存场景下刷新地址时保持类型一致。5.4 预留接口说明reserved_interface.md 罗列了 6 个预留接口AclSetInputTensorAddr、AclSetOutputTensorAddr、AclSetDynamicInputTensorAddr、AclSetDynamicOutputTensorAddr、AclSetTensorAddr、AclSetDynamicTensorAddr首字母大写的驼峰命名版本它们功能与对应小写版本一致但后续版本存在变更或废弃风险不建议开发者使用开发者无需关注。这些预留接口同样声明在aclnn/acl_meta.h中include/nnopbase/aclnn/acl_meta.h。六、初始化与去初始化aclnnInit / aclnnFinalizeaclnnStatus aclnnInit(const char *configPath); // 声明于 aclnn/aclnn_base.h aclnnStatus aclnnFinalize();aclnnInitaclnn API 的初始化函数在使用任何 aclnn 接口前调用用于加载算子库资源、初始化运行时环境。aclnnFinalizeaclnn API 的去初始化函数在全部 aclnn 调用结束后调用释放初始化时申请的资源。两者是 aclnn 编程模型的大门与收尾建议在进程生命周期内成对调用初始化一次、结束时 finalize 一次避免重复初始化开销或资源泄漏。七、返回码速查公共接口的错误语义所有公共接口返回aclnnStatusint32_t常见返回码见 public_interface_return_code.md。异常信息可通过 Runtime 运行时 API 的aclGetRecentErrMsg接口获取根据报错提示排查问题或联系技术支持。表 返回状态码状态码名称状态码值状态码说明ACLNN_SUCCESS0成功ACLNN_ERR_PARAM_NULLPTR161001参数校验错误参数中存在非法的 nullptrACLNN_ERR_PARAM_INVALID161002参数校验错误如输入的两个数据类型不满足输入类型推导关系ACLNN_ERR_RUNTIME_ERROR361001API 内存调用 npu runtime 的接口异常ACLNN_ERR_INNER_XXX561xxxAPI 发生内部异常。常见内部异常场景561101ACLNN_ERR_INNER_CREATE_EXECUTOR内部创建 aclOpExecutor 失败可能因为操作系统异常561102ACLNN_ERR_INNER_NOT_TRANS_EXECUTOR内部未调用 uniqueExecutor ReleaseTo561103ACLNN_ERR_INNER_NULLPTRaclnn API 内部出现 nullptr 异常从源码验证返回码语义在 src/nnopbase/common/api/acl_op_api.cpp 中地址类型不一致的刷新操作会通过OP_LOGE_FOR_INVALID_ARGUMENT_WITHOUT_SOLUTION记录ACLNN_ERR_PARAM_INVALID错误aclCreateTensor内部异常则通过OP_LOGE(ACLNN_ERR_INNER, ...)标记为内部错误——与 161002/561xxx 的分类完全对应。此外 include/nnopbase/aclnn/aclnn_base.h 定义了aclnnStatus类型与OK 0常量所有接口成功时返回 0。八、最佳实践清单综合以上接口语义与源码实现给出公共接口使用的黄金守则成对创建与销毁每个aclCreateXxx都对应一个aclDestroyXxx列表销毁后不要再单独销毁内部元素避免重复释放。调用顺序aclnnInit→ 创建各种 Meta 对象 →GetWorkspaceSize→ 执行 → 销毁 Meta 对象 →aclnnFinalize。复用需显式收尾只有调用aclSetAclOpExecutorRepeatable的 executor 才需要aclDestroyAclOpExecutor普通 executor 由框架管理。地址刷新与内存类型复用模式下地址变更必须调用对应刷新接口刷新时保持 PCIe/non-PCIe 地址类型一致否则返回 161002。32 字节对齐aclCreateTensor的tensorData必须 32 字节对齐否则可能出现未定义错误。空指针防御aclCreateTensor/aclCreateScalar在入参非法时返回nullptr参见 acl_op_api.cpp调用前应检查返回值。返回码排查接口失败时用aclGetRecentErrMsg获取详细错误信息按 161xxx参数/361001runtime/561xxx内部分类定位。预留接口回避首字母大写的AclSetXxx系列为预留接口后续可能变更或废弃统一使用小写正式接口。延伸阅读完整接口速查见 public_interface_list.md每个接口的独立详解见 docs/zh/api/nnopbase/aclnn 目录返回码与预留接口分别见 public_interface_return_code.md 与 reserved_interface.md。接口头文件位于仓库 include/nnopbase/aclnn/acl_meta.h核心实现位于 src/nnopbase/common/api/acl_op_api.cpp。【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询