CANN opbase 单算子 API 整型数组入参创建:aclCreateIntArray 使用指南与源码解析
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
本指南围绕 CANN opbase 仓库中单算子 API(aclnn 接口)的入参构造接口aclCreateIntArray,讲解其功能定位、函数原型、参数与返回值语义、生命周期管理,并结合仓库源码与单元测试剖析其内部实现与配套接口(aclDestroyIntArray、aclGetIntArraySize)的协作方式。读者读完可以掌握如何正确创建、使用与销毁aclIntArray,避免空指针、内存泄漏等常见问题,并理解它在单算子执行链路中的真实作用。
功能定位:单算子 API 的整型数组入参载体
在 CANN 算子库(CANN/opbase)的 aclnn 单算子执行框架中,aclIntArray是框架定义的一种用来管理和存储整型(int64_t)数据的数组结构。它作为单算子 API 执行接口的入参出现,典型场景包括:
- 算子属性为整型数组类型时,例如
shape、dims、axis、padding、size等以多个整数值表达的算子参数; - 将一组 Host 侧整型数据传递到算子执行接口(如
GetWorkspaceSize与执行接口)中参与算子调度。
aclCreateIntArray负责创建这一对象,开发者无需关注其内部实现细节,只需保证传入的 Host 数据有效并妥善管理返回对象的生命周期即可。
接口声明位于 include/nnopbase/aclnn/acl_meta.h,其中将aclIntArray以不透明结构体(typedef struct aclIntArray aclIntArray;)的形式暴露给开发者,这正是"无需关注内部实现"的设计基础——外部只能通过本系列接口操作它。
函数原型与参数说明
aclCreateIntArray的函数原型为:
aclIntArray *aclCreateIntArray(const int64_t *value, uint64_t size)| 参数名 | 输入/输出 | 说明 |
|---|---|---|
| value | 输入 | Host 侧的int64_t类型指针,其指向的值会被拷贝给aclIntArray(创建后不再依赖原指针)。 |
| size | 输入 | 整型数组的长度,取值为正整数,即value指向的有效元素个数。 |
需要注意:
value指向的数据位于 Host 侧内存,接口内部会完成一次拷贝,因此创建后可以安全释放或复用原value缓冲区;size表示的是数组元素个数而非字节数,{1, 1, 2, 3}的 size 为 4;- 该函数是纯 Host 侧内存管理接口,不涉及 Device 内存分配,也不依赖具体的算子实现。
返回值说明
- 成功:返回创建好的
aclIntArray对象指针; - 失败:返回
nullptr(例如内部构造异常或参数非法导致分配失败时)。
调用方应在拿到返回值后立即判断是否为nullptr,再进行后续传参操作。
生命周期管理:与 aclDestroyIntArray 配套使用
aclIntArray由aclCreateIntArray创建,必须由 aclDestroyIntArray 接口销毁,二者配套使用,分别完成aclIntArray的创建与销毁:
aclnnStatus aclDestroyIntArray(const aclIntArray *array)销毁接口的返回码语义为:返回0表示成功,返回其他值表示失败,返回码列表参见 公共接口返回码。
从源码实现看,销毁接口对空指针做了安全兜底:src/nnopbase/common/api/acl_op_api.cpp 中,array == nullptr时直接返回OK,不会触发崩溃;同时,当开启 aclnn 调试能力(op::internal::IsAclnnDebugEnabled())时,会通过CheckDoubleFree检查重复释放,并在检测到可能的 double-free 时输出告警日志"Possible double-free at addr %p."。这意味着:
- 多次销毁同一对象在调试模式下会被记录告警,开发者应保证每个
aclIntArray只被销毁一次; - 对
nullptr调用销毁接口是安全的,可作为错误路径的收尾操作。
对应的单元测试也覆盖了这两个分支,见 tests/nnopbase/ut/composite_op/test_acl_op_api.cpp:
TEST_F(AclOpApiTest, aclIntArray) { int64_t values[] = {3, 4, 5}; auto* value = aclCreateIntArray(values, sizeof(values) / sizeof(values[0])); EXPECT_EQ(aclDestroyIntArray(value), OK); EXPECT_EQ(aclDestroyIntArray(nullptr), OK); }配套查询接口:aclGetIntArraySize
创建之后,可以调用 aclGetIntArraySize 获取aclIntArray的大小(元素个数):
aclnnStatus aclGetIntArraySize(const aclIntArray *array, uint64_t *size)| 参数名 | 输入/输出 | 说明 |
|---|---|---|
| array | 输入 | 输入的aclIntArray。 |
| size | 输出 | 返回aclIntArray的大小(元素个数)。 |
其实现位于 src/nnopbase/common/api/acl_op_api.cpp,核心逻辑非常简洁:
aclnnStatus aclGetIntArraySize(const aclIntArray* array, uint64_t* size) { if (array == nullptr || size == nullptr) { return ACLNN_ERR_PARAM_NULLPTR; } *size = array->Size(); return OK; }由此可知该接口的失败场景:当array或size为空指针时返回161001(ACLNN_ERR_PARAM_NULLPTR,空指针参数错误);测试用例对"空指针失败"与"正常取值"均有断言,见 tests/nnopbase/ut/composite_op/test_acl_op_api.cpp:
TEST_F(AclOpApiTest, aclGetIntArraySize) { EXPECT_NE(aclGetIntArraySize(nullptr, nullptr), OK); int64_t values[] = {3, 4, 5}; auto* value = aclCreateIntArray(values, sizeof(values) / sizeof(values[0])); uint64_t size = 0; EXPECT_EQ(aclGetIntArraySize(value, &size), OK); EXPECT_EQ(size, 3); // 元素个数为 3 EXPECT_EQ(aclDestroyIntArray(value), OK); }调用示例:创建、传参与销毁的完整流程
以下代码来自 aclCreateIntArray 文档,展示了从创建到作为单算子 API 入参再到销毁的完整闭环,关键代码示例如下,仅供参考,不支持直接拷贝运行:
// 创建aclIntArray std::vector<int64_t> sizeData = {1, 1, 2, 3}; aclIntArray *size = aclCreateIntArray(sizeData.data(), sizeData.size()); ... // aclIntArray作为单算子API执行接口的入参 auto ret = aclxxXxxGetWorkspaceSize(srcTensor, size, ..., outTensor, ..., &workspaceSize, &executor); ret = aclxxXxx(...); ... // 销毁aclIntArray ret = aclDestroyIntArray(size);配合查询接口的完整示例(来自 aclGetIntArraySize 文档):
// 创建aclIntArray std::vector<int64_t> valueData = {1, 1, 2, 3}; aclIntArray *valueArray = aclCreateIntArray(valueData.data(), valueData.size()); ... // 使用aclGetIntArraySize接口获取valueArray的大小 uint64_t size = 0; auto ret = aclGetIntArraySize(valueArray, &size); // 获取到的valueArray的size为4 ... // 销毁aclIntArray ret = aclDestroyIntArray(valueArray);结合上述源码实现,可以总结出几条可落地的使用要点:
- 创建后及时判空:
aclCreateIntArray可能返回nullptr,传参前务必检查; - 原缓冲区可复用:创建接口内部完成数据拷贝(
new aclIntArray(value, size)),创建后原value数据源即可安全释放; - 用
vector.data()+vector.size()是最自然的构造方式,元素类型为int64_t,与size语义(元素个数)天然匹配; - 成对创建与销毁:每个
aclIntArray只销毁一次,销毁后不要再次使用,调试模式下重复释放会触发 double-free 告警; - 空指针销毁安全:
aclDestroyIntArray(nullptr)直接返回成功,可作为统一清理逻辑的兜底。
源码纵深:aclIntArray 在单算子执行链路中的真实用途
aclIntArray虽然对开发者是不透明结构,但在框架内部会被广泛解析使用,可以从仓库源码中看到它的三类典型去向:
1. 作为算子属性参与 AICPU 任务构建
在 include/nnopbase/opdev/aicpu/aicpu_task.h 中,aclIntArray有两个用途:
AppendAttrForKey:逐个取出value->GetData()[i]参与执行缓存 key 的构建,即整型数组的每个元素都会被序列化进算子缓存键,用于区分不同参数取值下的缓存条目;AddAicpuAttr:将整个aclIntArray作为 AICPU 算子的属性(attrName)添加到AicpuAttrs中下发。
这说明aclIntArray不仅是 Host 侧的普通容器,其内容会真实参与算子执行缓存命中与属性下发,参数的数值直接影响算子的调度与执行结果。
2. 作为 OpArg 统一参数载体
在 include/nnopbase/opdev/op_arg_def.h 中,aclIntArray*与const aclIntArray*均可直接构造OpArgValue,从而进入统一的算子参数(OpArg)体系,与其他标量、张量、列表类型的入参走同一条参数收集与传递路径。
3. 支持从整型数组构造张量
在 src/nnopbase/common/utils/common_types.cpp 中,aclTensor提供了从aclIntArray出发的构造能力:
aclTensor::aclTensor(const aclIntArray* value, op::DataType dataType) : aclTensor(value->GetData(), value->Size(), dataType) {}即整型数组数据可以直接转为一个指定数据类型的aclTensor(视图),进一步印证了aclIntArray在 Host 数据组织中的基础地位——它是整型标量数组在 aclnn 框架中的通用入口容器。
4. 执行缓存键构建
在 src/nnopbase/common/utils/op_cache.cpp 中,AddParamToBuf(const aclIntArray* value)会将整型数组内容写入缓存参数缓冲区,参与算子执行缓存的键值生成,与 AICPU 任务侧的AppendAttrForKey形成呼应,确保整型数组参数的取值变化能正确区分缓存条目。
小结
aclCreateIntArray是 CANN opbase 单算子 API 生态中最基础的 Host 侧入参构造接口之一:它通过不透明结构体隐藏内部实现,用一次数据拷贝保证调用方数据安全,并通过aclDestroyIntArray、aclGetIntArraySize两个配套接口完成生命周期闭环。框架内部则将其内容用于 AICPU 属性下发、执行缓存键构建、统一 OpArg 传参乃至张量视图构造。理解并规范使用这三个接口(创建、查询、销毁),是正确编写 aclnn 单算子调用代码的前提。
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考