资讯动态

CANN opbase:aclDestroyScalarList 接口详解——aclScalarList 标量列表的释放机制与源码剖析

发布时间:2026/9/18 10:03:28 来源:尧图企业网站定制
CANN opbaseaclDestroyScalarList 接口详解——aclScalarList 标量列表的释放机制与源码剖析【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase在 CANN 算子库基础框架库 opbase 中单算子AclNN接口以aclScalar表示标量参数、以aclScalarList批量承载多个标量参数。本篇围绕 AclNN 元信息 APIaclDestroyScalarList展开先给出该接口的原型、参数与返回值约定再结合 acl_op_api.cpp 的真实实现剖析其空指针保护、双重释放检测、元素级销毁与列表对象销毁的完整调用链最后给出与 aclCreateScalarList 配对的完整生命周期示例帮助读者在自定义算子或单算子调用场景中正确管理标量列表的内存避免泄漏与双重释放。接口功能与原型aclDestroyScalarList的功能是销毁通过调用 aclCreateScalarList API 创建的aclScalarList对象。aclScalarList是框架定义的一种用于管理和存储多个标量的列表结构用户无需了解其内部实现即可使用。aclnnStatus aclDestroyScalarList(const aclScalarList *array)该声明位于对外头文件 acl_meta.h带有ACL_FUNC_VISIBILITY导出标记与aclCreateScalarList、aclGetScalarListSize等接口共同构成 AclNN 元信息接口族。参数说明参数输入/输出说明array输入待销毁的aclScalarList指针返回值成功返回0否则返回失败错误码。完整的 AclNN 通用返回码定义见 common_api_return_codes.md其中与本接口直接相关的关键码值如下错误码值说明ACLNN_SUCCESS0成功ACLNN_ERR_PARAM_NULLPTR161001参数校验错误参数中存在无效的nullptrACLNN_ERR_INNER_XXX561xxx内部 API 异常如 561103 表示 aclnn API 内部空指针错误aclScalarList 的内存模型先看懂结构再看销毁理解aclDestroyScalarList的行为需要先理解aclScalarList内部持有什么。从 common_types.h 中的结构定义可以看出struct aclScalarList : public op::Object { friend class aclOpExecutor; friend aclScalarList* aclCreateScalarList(const aclScalar* const* value, uint64_t size); friend aclnnStatus aclDestroyScalarList(const aclScalarList* array); // ... private: aclScalar** scalars_{nullptr}; // 指向 aclScalar 指针数组 uint64_t size_{0}; // 列表长度 // ... };由此可以得出三个关键结论aclScalarList内部维护一个独立的aclScalar*指针数组scalars_记录列表长度size_。列表对元素只做指针拷贝浅拷贝。在 common_types.cpp 的构造函数中可以看到创建时通过memcpy_s将外部传入的aclScalar指针数组原样复制到内部aclScalarList::aclScalarList(const aclScalar* const* scalars, uint64_t size) { if (scalars ! nullptr size ! 0) { this-size_ size; this-scalars_ new (std::nothrow) aclScalar*[size]; OP_CHECK(memcpy_s(this-scalars_, size * sizeof(aclScalar*), scalars, size * sizeof(aclScalar*)) EOK, OP_LOGW(Failed to memcpy in aclScalarList create.), throw std::runtime_error(aclScalarList::aclScalarList memcpy runtime error.)); } }因此aclCreateScalarList不会复制标量数据本身列表与外部数组共享同一批aclScalar对象——谁负责销毁这些标量就成了 API 契约的核心。 3.构造函数与析构函数均为私有只对被声明为 friend 的aclCreateScalarList/aclDestroyScalarList开放。这从类型系统层面保证了对象只能经由官方成对的 Create/Destroy 接口完成生命周期管理用户无法new/delete该结构。源码实现解析aclDestroyScalarList 做了什么common_types.cpp 中的析构函数只负责释放内部指针数组本身不销毁各aclScalar元素aclScalarList::~aclScalarList() { for (uint64_t i 0; i size_; i) { scalars_[i] nullptr; } if (scalars_ ! nullptr) { delete[] scalars_; } }真正把元素销毁职责补齐的是对外 APIaclDestroyScalarList本身。其完整实现见 acl_op_api.cppaclnnStatus aclDestroyScalarList(const aclScalarList* array) { if (array nullptr) { return OK; } // 仅对外层 list 指针本身做一次预检元素由循环内 aclDestroyScalar 各自覆盖 if (unlikely(op::internal::IsAclnnDebugEnabled()) op::internal::CheckDoubleFree(const_castaclScalarList*(array))) { OP_LOGW(Possible double-free at addr %p., static_castconst void*(array)); } for (uint64_t i 0; i array-Size(); i) { aclDestroyScalar((*array)[i]); } delete array; return OK; }对照源码可以确认该接口执行了四个步骤空指针直通array为nullptr时直接返回OK接口对空指针是幂等安全的可放心用于条件分支的清理路径。调试态双重释放检测当开启 AclNN 调试开关IsAclnnDebugEnabled()时调用 bridge_pool.cpp 中的CheckDoubleFree对外层列表指针做一次预检。该函数读取内存块头部的 magic 与缓存链状态判断该地址对应的内存块是否已被归还到块缓存链表从而在日志中提示Possible double-free。源码中的注释明确说明外层只做一次预检各元素的双重释放检测由循环内的aclDestroyScalar各自覆盖。逐元素销毁标量按Size()遍历列表对每个元素调用aclDestroyScalar。aclDestroyScalaracl_op_api.cpp同样具备空指针直通与调试态双重释放检测最终delete标量对象。这正是文档Restrictions一节的实现依据列表销毁时已经代为销毁了其中的每个aclScalar因此用户无需再对列表中的aclScalar单独调用aclDestroyScalar重复调用会触发双重释放。销毁列表对象最后delete array触发上文析构函数释放内部aclScalar*指针数组并将各槽位置空。值得一提的是框架内部对销毁的调用也统一收口到该接口。例如单算子individual op回退路径 individual_op_fallback.cpp 中的封装实现即为void NnopbaseDestroyScalarList(const aclScalarList* scalar) { aclDestroyScalarList(scalar); }从源码结构看无论 AclNN 路径还是单算子回退路径标量列表的释放都收敛到同一入口保证了生命周期管理的一致性。使用限制与最佳实践与aclCreateScalarList必须配对使用二者分别负责创建与销毁同一个aclScalarList。列表在使用完毕单算子GetWorkspaceSize与执行调用完成后应及时销毁避免内存泄漏。元素不可二次销毁如上文所析aclDestroyScalarList已负责销毁列表内的全部aclScalar。销毁列表后原先指向各aclScalar的局部指针如示例中的alpha1、alpha2已失效不可再使用或再次释放。销毁前可查询长度如需校验可先调用 aclGetScalarListSize 获取列表元素个数其实现同样位于 acl_op_api.cpp对nullptr输入返回ACLNN_ERR_PARAM_NULLPTR。返回值需按错误码处理正常路径恒返回0ACLNN_SUCCESS若出现非零返回码可参考 common_api_return_codes.md 结合错误日志定位问题。完整使用示例官方文档指出aclDestroyScalarList的示例与 aclCreateScalarList 的调用示例一致。下面给出继承自官方文档的完整生命周期代码仅作参考不用于直接复制执行// 1. 创建 alpha1 aclScalar。 float alpha1Value 1.2f; aclScalar *alpha1 aclCreateScalar(alpha1Value, aclDataType::ACL_FLOAT); // 2. 创建 alpha2 aclScalar。 float alpha2Value 2.2f; aclScalar *alpha2 aclCreateScalar(alpha2Value, aclDataType::ACL_FLOAT); // 3. 创建 aclScalarList。 std::vectoraclScalar * tempscalar{alpha1, alpha2}; aclScalarList *scalarlist aclCreateScalarList(tempscalar.data(), tempscalar.size()); ... // 4. 将 aclScalarList 作为单算子 API 执行的输入参数。 auto ret aclxxXxxGetWorkspaceSize(srcTensor, scalarlist, ..., outTensor, ..., workspaceSize, executor); ret aclxxXxx(...); ... // 5. 销毁 aclScalarList同时销毁其中所有 aclScalar。 ret aclDestroyScalarList(scalarlist);示例中各步骤与本文分析的对应关系第 3 步构造时列表复制标量指针数组第 4 步期间aclOpExecutor通过 friend 权限读取标量值第 5 步一次调用完成逐标量销毁 列表指针数组释放 列表对象删除的全部清理。注意第 5 步之后不再出现对alpha1/alpha2的aclDestroyScalar调用——这正是元素无需再单独销毁这一限制在代码层面的体现。小结aclDestroyScalarList是 AclNN 元信息接口族中负责aclScalarList对象销毁的唯一入口原型为aclnnStatus aclDestroyScalarList(const aclScalarList *array)成功返回0。源码实现acl_op_api.cpp确认其行为空指针安全返回、调试态双重释放检测、循环内通过aclDestroyScalar逐元素销毁标量、最后delete列表对象。由于aclScalarList内部只是aclScalar指针数组的浅拷贝common_types.cpp销毁列表即完成全部标量的释放用户不应再次销毁列表元素。建议将aclCreateScalarList/aclDestroyScalarList视为严格成对的生命周期 API在单算子 workspace 计算与执行流程结束后立即配对销毁保证内存安全。如需继续了解标量与列表的创建侧接口可分别参阅 aclCreateScalar、aclCreateScalarList 及 aclGetScalarListSize 的接口文档。【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价