CANN Runtime 错误码 EE1018 深度解析:Invalid Argument API Call Sequence(API 调用序列非法)
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
EE1018 是 CANN Runtime 运行时(RTS)错误码系列中用于标识"API 调用序列非法"的通用错误。当某个 Runtime API 被重复调用、调用顺序不符合前置条件,或在未完成必要初始化步骤前就被调用时,Runtime 会以统一格式%s failed. Reason: %s.上报该错误。本文基于 EE1018 官方错误参考 与仓库源码,完整讲解错误格式、典型触发场景、源码级原理与定位方法,帮助开发者在遇到该错误时快速判断问题根因。
EE1018 错误码是什么
EE1018 属于 RTS(Runtime System)错误码大类,错误标题为Invalid_Argument_API_Call_Sequence,即"参数合法但调用序列非法"。在错误码注册中心 error_code.json 中,它的定义如下:
| 字段 | 值 |
|---|---|
| errClass | RTS Errors |
| errTitle | Invalid_Argument_API_Call_Sequence |
| ErrCode | EE1018 |
| ErrMessage | %s failed. Reason: %s. |
| Arglist | func, reason |
从中可以看出,该错误的核心特征是:传入参数本身通常是合法的,问题出在 API 的调用时机或调用顺序上——例如重复执行了本应只执行一次的设置操作,或者在某个前置资源创建完成之前就使用了该资源。因此错误信息中只携带两个占位符:func(报错阶段或 API 名)和reason(报错原因),这也是本文关联文档中错误格式%s failed. Reason: %s.的来源。
错误信息格式与占位符含义
按照文档定义,EE1018 的报错格式为:
%s failed. Reason: %s.两个占位符%s的含义依次为:
- 第一个
%s:报错阶段(error stage)或 API 名称(API name),如rtsLabelSet、aclrtSetLabel、aclrtProfilingInit等; - 第二个
%s:报错原因(error cause),描述具体的非法调用情形。
文档给出的标准报错示例如下:
rtsLabelSet failed. Reason: The label cannot be set repeatedly.该示例中,rtsLabelSet是报错的 API(label 设置),The label cannot be set repeatedly说明根因是 label 被重复设置。
典型触发场景与源码级原理
EE1018 在 Runtime 源码中被大量用于表达"状态不满足预期"的检查(常配合COND_RETURN_AND_MSG_OUTER等条件宏),以下按功能模块梳理最常见、也最具代表性的触发场景。
场景一:Label 被重复设置(文档示例的出处)
rtsLabelSet failed. Reason: The label cannot be set repeatedly.对应的实现位于 label.cc 的Label::Set方法。该方法在提交 label 设置任务前依次做了一系列前置检查,其中与 EE1018 直接相关的是:
COND_RETURN_AND_MSG_OUTER( setFlag_, RT_ERROR_LABEL_SET, ErrorCode::EE1018, "rtLabelSet", "The label cannot be set repeatedly");即当Label对象的setFlag_已经被置为true(说明该 label 此前已经成功设置到某个 stream 上)时,再次调用设置接口就会触发 EE1018。从源码流程看,setFlag_只有在任务成功提交后才被置位:
error = dev->SubmitTask(labelTask); ... setFlag_ = true; stream_ = stm;也就是说,同一个 Label 句柄只能被设置到 stream 上一次。若业务逻辑需要切换 label 绑定的 stream,应重新创建 label 或先执行释放操作,而不是复用同一个已设置的 label 再次调用设置接口。
此外,同一个 label 若被设置到另一个不同的 stream,虽然返回的是另一错误码RT_ERROR_LABEL_STREAM(对应EE1017),但从调用序列角度看同样属于"状态不一致"问题。这两处检查共同保证了 label 与 stream 的绑定关系是稳定、可预期的。
场景二:设置 Label 前未创建 Label 列表
在Label::Set中还有另一处 EE1018 检查,针对较新版本的 TS(TS_VERSION_MORE_LABEL):
COND_RETURN_AND_MSG_OUTER( ((devDstAddr_ == nullptr) && (dev->GetTschVersion() >= static_cast<uint32_t>(TS_VERSION_MORE_LABEL))), RT_ERROR_LABEL_PHY_ADDR_NULL, ErrorCode::EE1018, "aclrtSetLabel", "Before setting the label using aclrtSetLabel, you need to call aclrtCreateLabelList to create a label list");它约束了 API 的调用顺序:在使用aclrtSetLabel设置 label 之前,必须先调用aclrtCreateLabelList创建 label 列表(对应Label::SetLabelDevAddr写入devDstAddr_)。若跳过该前置步骤直接设置 label,将触发 EE1018,错误信息会明确提示"先调用 aclrtCreateLabelList 创建 label 列表"。
场景三:算子内核函数重复注册
在 api_error.cc 中,注册算子内核函数时同样使用 EE1018 表示"重复注册":
error == RT_ERROR_KERNEL_DUPLICATE, error, ErrorCode::EE1018, "Registering an operator kernel function",即相同的内核函数被注册了两次,属于典型的"重复执行单次操作"类非法调用序列。
场景四:Host 内存重复注册与解注册
在 api_error.cc 中有两处:
error == RT_ERROR_HOST_MEMORY_ALREADY_REGISTERED, error, ErrorCode::EE1018, "Host memory address registration", error == RT_ERROR_HOST_MEMORY_NOT_REGISTERED, error, ErrorCode::EE1018, "Unregistering host memory",- 对已注册的 Host 内存地址再次执行注册操作 → 触发 EE1018;
- 对未注册过的 Host 内存地址执行解注册操作 → 触发 EE1018。
这要求注册/解注册接口严格配对使用,且同一地址不可重复注册。
场景五:Profiling 分析重复使能或停止
在 runtime.cc 中,启动 profiling 分析时检查了使能状态,若 profiler 已经被使能则报:
ErrorCode::EE1018, "Starting profiling analysis", "profiler is already enabled, cannot set repeatedly"而 runtime.cc 中停止 profiling 分析也使用 EE1018 标识状态异常。这意味着 profiling 的启动/停止必须遵循"未使能时启动、已使能时停止"的调用节奏,不可嵌套或重复。
场景六:模型运行实例(Model RI)构建与执行
在 model.cc 中,aclmdlRIBuildEnd、模型执行等多个环节均以 EE1018 表达调用序列错误,例如:
endGraphNum_ != 1U→ "Ending model running instance build"(结束模型构建的次数异常);streams_.empty()→ 模型构建结束前未绑定任何 stream;aclmdlRIBuildEnd在未处于"构建中"状态时被调用(RT_ERROR_MODEL_NOT_END);- 模型执行时模型尚未结束构建(
RT_ERROR_MODEL_NOT_END, ErrorCode::EE1018, "Model execution")。
这些场景的共同规律是:模型运行实例的生命周期状态机(创建 → 构建 → 执行 → 销毁)中的每一步都必须严格按序推进,跳步或重复推进都会落入 EE1018。
场景七:Stream 捕获(ACL Graph 捕获)状态异常
在 ACL Graph 捕获相关代码中,EE1018 被用于表达捕获状态的非法流转,例如 capture_session.cc:
status == RT_STREAM_CAPTURE_STATUS_NONE, RT_ERROR_STREAM_NOT_CAPTURED, ErrorCode::EE1018, "Stream end capture",以及 v100/api_impl_aclgraph.cc 中的rtStreamAddCondTask检查。当对未处于捕获状态的 stream 执行"结束捕获"或在捕获状态下执行不支持的追加任务时,会触发 EE1018。
场景八:设备重置、上下文校验与事件等待等其他场景
- 设备重置:api_error.cc 中
RT_ERROR_CONTEXT_DEL对应 "Resetting the device",设备重置操作与上下文生命周期存在顺序约束; - 上下文校验:context_manage.cc 中 "Context validation";
- 事件等待:event.cc 中 "Waiting for an event" 的两次状态检查;
- 设备保留计数:api_impl.cc 中设备 retain 次数异常;
- 回调注册:api_impl.cc 中未注册回调时执行相关操作(
RT_ERROR_STREAM_NO_CB_REG); - 流停止:stream.cc 中 "rtsStreamStop"。
从这些分散在 api_error.cc、api_impl.cc、stream.cc、event.cc、runtime.cc 等文件中的触发点可以看出:EE1018 是 Runtime 中最通用的"状态机校验"错误码,任何"重复设置、未初始化即使用、生命周期顺序错乱"类问题都可能映射到该错误码。
如何定位与解决 EE1018
根据文档的解决方法指引"按照报错提示定位问题"(Please locate the issue based on the prompts in the error message),建议按以下步骤排查:
第一步:解析报错中的两个占位符
EE1018 的报错信息%s failed. Reason: %s.已经精确指出了问题位置和原因:
- 第一个
%s指出哪个 API 或哪个阶段出错,例如rtsLabelSet、aclrtSetLabel、aclrtProfilingInit、aclmdlRIBuildEnd等; - 第二个
%s指出具体的非法调用情形,例如The label cannot be set repeatedly、profiler is already enabled, cannot set repeatedly、Before setting the label using aclrtSetLabel, you need to call aclrtCreateLabelList to create a label list。
第二步:对照 API 生命周期检查调用序列
根据报错中的 API 名,检查业务代码中的调用顺序是否满足该 API 的前置条件:
- 是否重复调用:单次性操作(注册、使能、设置)是否被重复执行?例如 label 重复设置、内核函数重复注册、Host 内存重复注册、profiler 重复使能;
- 是否遗漏前置步骤:使用某个资源前是否完成了必要的初始化?例如
aclrtSetLabel前是否调用了aclrtCreateLabelList; - 是否跳步/乱序:状态机类流程(模型构建、stream 捕获、profiling 启停、内存注册/解注册配对)是否严格按序执行?
- 是否配对使用:注册与解注册、使能与停止、创建与销毁是否成对出现?
第三步:结合日志与源码定位
- 在启用 plog 日志后(参考 日志相关环境变量),可以在 Runtime 日志中搜索报错 API 名或错误码 EE1018,查看其前的调用上下文;
- 结合本文列出的源码触发点(如 label.cc、api_error.cc),确认代码路径中具体是哪一条状态检查条件未满足。
与相邻错误码的区分
EE1018 与 RTS 错误码系列中的其他"参数类"错误容易混淆,定位时应先区分:
- EE1017:同样以
%s failed.开头,但格式为%s failed. Parameter %s is invalid. Reason: %s.,多了一个param占位符,表示参数本身非法(如 label 与 stream 所属模型不一致、stream 与 label 已关联 stream 不一致),定义见 error_code.json; - EE1018:格式为
%s failed. Reason: %s.,表示参数合法但调用序列非法(重复调用、顺序错乱、前置缺失)。
二者的本质区别在于:参数值有没有问题。若报错聚焦在某个具体参数的值上,大概率是 EE1017;若报错描述的是"不能重复/需要先调用/状态不匹配"等时序问题,则是 EE1018。
小结
- EE1018
Invalid_Argument_API_Call_Sequence是 CANN Runtime 用于标识"API 调用序列非法"的通用错误码,信息格式为%s failed. Reason: %s.,依次填充"报错阶段/API 名"与"报错原因"; - 典型触发场景包括 label 重复设置、设置 label 前未创建 label 列表、内核函数重复注册、Host 内存重复注册/解注册、profiler 重复使能、模型运行实例构建/执行乱序、stream 捕获状态异常等,均可从 label.cc、api_error.cc、model.cc 等源码中逐一印证;
- 排查时应优先解析报错中的 API 名与原因描述,对照"重复调用、前置缺失、跳步乱序、配对缺失"四类模式检查调用序列,必要时结合 Runtime 日志确认触发路径。
更多 RTS 错误码请参考 RTS-Errors 错误码索引,完整错误码注册信息见 error_code.json。若需要在代码中复现 label 相关调用序列,可参考仓库示例 0_simple_label(含 main.cpp 与运行脚本),其配套文档见 示例 README。
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考