CANN Runtime 错误码 EE1003 Invalid_Argument 深度解析:从报错格式到源码排查实战
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
导读:EE1003 是 CANN Runtime(RTS)对外暴露的“参数非法(Invalid Argument)”错误码,用于在运行时接口收到超出合法范围的输入参数时给出统一的、带四段式结构化信息的报错。本文以官方错误码参考文档为主体,结合
cann/runtime仓库中的错误码定义表(src/dfx/error_manager/error_code.json)、RTS 接口声明(pkg_inc/runtime/runtime/rts/rts_stream.h)以及错误码上报宏实现(src/runtime/core/inc/base.hpp、src/runtime/core/inc/common/error_message_manage.hpp)进行纵深解读,帮助开发者准确读懂 EE1003 报错信息、快速定位非法参数根因,并掌握参数范围校验与接口调用关系的排查方法。
1. EE1003 是什么:RTS 错误码家族中的“参数校验哨兵”
CANN Runtime 在运行过程中会通过统一的错误码体系向 Host 侧上报异常,错误码以EE前缀标识 Execution Error(执行类错误)。在docs/en/error_code_ref/RTS-Errors/目录下,围绕同一类问题往往有多个细分错误码,例如:
EE1001Invalid_Argument:参数无效,报错格式为The argument is invalid. Reason: %s,通过附加信息说明原因;EE1003Invalid_Argument:参数值非法(本文主题),报错中直接给出非法参数值、参数名与期望值;EE1004Invalid_Argument_Null_Pointer:参数为空指针,报错格式为%s failed because %s cannot be a NULL pointer.;EE1005Not_Supported:当前系统或设备不支持该功能。
其中 EE1003 的特点在于报错信息自带“回放”能力——它把出错的函数、传入的非法值、参数名以及期望值四项关键信息全部嵌入错误文本,开发者无需额外的上下文即可判断是哪一次调用、哪个参数、传了什么值、应该传什么值。
在仓库的错误码定义表 src/dfx/error_manager/error_code.json 中,EE1003 的登记信息如下:
{ "errClass": "RTS Errors", "errTitle": "Invalid_Argument", "ErrCode": "EE1003", "ErrMessage": "%s failed because value %s for parameter %s is invalid. Expected value: %s.", "Arglist": "func, value, param, expect", "suggestion": { "Possible Cause": "N/A", "Solution": "1. Check the input parameter range of the function. 2. Check the function invocation relationship." } }这里ErrMessage中的四个%s占位符与Arglist中的func, value, param, expect一一对应,构成了 EE1003 报错的固定模板,也是本文第 2 节将详细拆解的格式来源。
2. 读懂 EE1003 的报错格式:四个占位符的含义
根据官方错误码参考文档(EE1003-Invalid_Argument.md),EE1003 的报错模板为:
%s failed because value %s for parameter %s is invalid. Expected value: %s.其中各占位符%s的语义按出现顺序依次为:
| 序号 | 占位符 | 含义 | 示例 |
|---|---|---|---|
| 1 | %s | 报错阶段(Error stage)或发起调用的 API 名称 | rtsStreamSetAttribute |
| 2 | %s | 传入的非法参数值(Parameter value) | -5 |
| 3 | %s | 参数名(Parameter name) | stmAttrId |
| 4 | %s | 期望值(Expected value),即该参数的合法取值范围 | [0, 5) |
文档给出的完整报错示例如下:
rtsStreamSetAttribute failed because value -5 for parameter stmAttrId is invalid. Expected value: [0, 5).逐段解读这行报错:
- 报错发生在
rtsStreamSetAttribute接口调用中; - 开发者向该接口的
stmAttrId(Stream 属性 ID)参数传入了-5; -5不在stmAttrId的合法取值区间[0, 5)内,因此接口校验失败并返回错误。
说明:报错示例中的期望值
[0, 5)是演示用区间,用于展示“区间/范围”类期望值的写法(左闭右开)。实际合法范围以当前版本的头文件与接口校验逻辑为准——例如当前仓库 pkg_inc/runtime/runtime/rts/rts_stream.h 中rtStreamAttr枚举的合法值为 1~6(详见第 4 节),不同版本、不同 SoC 上的合法范围可能不同。期望值也可能以(a, b]、[a, b]、>= x、枚举名列表等其它形式呈现。
3. 从源码看 EE1003 是如何被“拼装”出来的
EE1003 的报错文本并非由各接口自行printf,而是由 Runtime 的错误上报宏统一生成。理解这条链路,有助于你反推“报错里的每个字段到底从哪来”。
3.1 核心上报宏
在 src/runtime/core/inc/base.hpp 中定义了 EE1003 专用的上报宏:
// EE1003错误码上报 #define RT_LOG_OUTER_MSG_INVALID_PARAM(parm, ...) \ RT_LOG_OUTER_MSG_WITH_FUNC(ErrorCode::EE1003, (parm), #parm, ##__VA_ARGS__)其作用是把错误码EE1003、当前函数名(通过__func__注入,见RT_LOG_OUTER_MSG_WITH_FUNC)以及参数名(通过#parm字符串化)组合成一次错误上报。继续追踪RT_LOG_OUTER_MSG_IMPL(同样位于 base.hpp):
#define RT_LOG_OUTER_MSG_WITH_FUNC(error_code, ...) RT_LOG_OUTER_MSG_IMPL((error_code), __func__, ##__VA_ARGS__) #define RT_LOG_OUTER_MSG_IMPL(error_code, ...) \ do { \ ErrorCodeProcess((error_code), __FILE__, __LINE__, &__func__ [0], { RT_ERRVAL_VALUES(__VA_ARGS__) }); \ } while (false)ErrorCodeProcess内部(base.hpp 第 280 行附近)会进一步调用ProcessErrorCodeImpl与ErrorManager::GetInstance().ATCReportErrMessage(...),将错误码文本与参数值一起上报给错误管理模块(ErrorManager),最终以文档第 2 节所述模板输出。可见:
- 报错阶段/API 名(第 1 个 %s)= 出错处所在函数的
__func__; - 参数名(第 3 个 %s)= 宏中
#parm字符串化后的源码参数名; - 参数值(第 2 个 %s)= 宏调用时显式传入的可读值表达式,通常用
ToString(var)之类的转换得到; - 期望值(第 4 个 %s)= 宏的可变参数部分追加传入。
3.2 配合条件判断的“判参即上报”宏
在 src/runtime/core/inc/common/error_message_manage.hpp 中,还封装了“条件不满足 → 上报 EE1003 → 返回错误码”的惯用宏:
// EE1003错误码使用,value与参数名分开传入 #define COND_RETURN_AND_MSG_OUTER_WITH_PARAM_NAME(COND, RTERRCODE, value, paramName, ...) \ if (unlikely((COND))) { \ RT_LOG_OUTER_MSG_WITH_FUNC(ErrorCode::EE1003, (value), (paramName), ##__VA_ARGS__); \ return (RTERRCODE); \ }该宏的注释明确说明了两个实参的约定:
value:可读值表达式(运行时求值),如ToString(var);paramName:参数名的字符串字面量(如"level"、"flag")。
从源码结构可以推断:Runtime 各接口在校验输入时,若发现参数超出合法区间,会优先走这套宏组合,从而保证同一错误码(EE1003)的报错格式在全仓库范围内完全一致——这正是错误码参考文档能用一个统一模板覆盖所有场景的原因。
4. 以示例接口rtsStreamSetAttribute为例:参数范围到底怎么查
EE1003 报错示例中出现的是rtsStreamSetAttribute,这是 RTS 层(pkg_inc/runtime/runtime/rts/)提供的 Stream 属性设置接口。查看其声明 pkg_inc/runtime/runtime/rts/rts_stream.h:
/** * @ingroup dvrt_stream * @brief set stream attribute * @param [in] stm stream handle * @param [in] stmAttrId stream attribute id * @param [in] attrValue stream attribute value * @return RT_ERROR_NONE for ok * @return RT_ERROR_INVALID_VALUE for error input */ RTS_API RT_DEPRECATED_MESSAGE(RT_RUNTIME_DEPRECATED_MESSAGE) rtError_t rtsStreamSetAttribute(rtStream_t stm, rtStreamAttr stmAttrId, rtStreamAttrValue_t* attrValue);注意接口返回值的注释:成功返回RT_ERROR_NONE,参数错误返回RT_ERROR_INVALID_VALUE——这与 EE1003 的“非法值”定位一致。下面拆解stmAttrId的合法范围。
4.1 参数类型:rtStreamAttr枚举
stmAttrId的类型rtStreamAttr在 rts_stream.h 中定义:
typedef enum { RT_STREAM_ATTR_FAILURE_MODE = 1, // 遇错模式(继续执行 / 遇错即停) RT_STREAM_ATTR_FLOAT_OVERFLOW_CHECK = 2, // 浮点溢出检查开关 RT_STREAM_ATTR_USER_CUSTOM_TAG = 3, // 用户自定义标签 RT_STREAM_ATTR_CACHE_OP_INFO = 4, // 算子缓存信息开关 RT_STREAM_ATTR_PRIORITY = 5, // Stream 优先级 RT_STREAM_ATTR_LAUNCH_BLOCKING_MODE = 6, // Launch 阻塞模式 RT_STREAM_ATTR_MAX = 7, // 哨兵值:属性总数 } rtStreamAttr;因此当前仓库中stmAttrId的合法取值为枚举成员 1~6,RT_STREAM_ATTR_MAX是用于表示“属性个数/上限”的哨兵值,不应作为合法属性 ID 传入。
4.2 参数类型:rtStreamAttrValue_t联合体
attrValue的类型rtStreamAttrValue_t是一个联合体,不同属性复用同一块存储,按属性类型解释:
typedef union { uint64_t failureMode; // RT_STREAM_ATTR_FAILURE_MODE:0=继续执行,1=遇错即停 uint32_t overflowSwitch; // RT_STREAM_ATTR_FLOAT_OVERFLOW_CHECK uint32_t userCustomTag; // RT_STREAM_ATTR_USER_CUSTOM_TAG uint32_t cacheOpInfoSwitch;// RT_STREAM_ATTR_CACHE_OP_INFO uint32_t streamPriority; // RT_STREAM_ATTR_PRIORITY uint32_t launchBlockingMode;// RT_STREAM_ATTR_LAUNCH_BLOCKING_MODE uint32_t rsv[4]; } rtStreamAttrValue_t;例如RT_STREAM_ATTR_FAILURE_MODE的取值可参考同一头文件中的宏定义:
#define RT_STREAM_FAILURE_MODE_CONTINUE_ON_FAILURE (0x0U) // 默认值,task出错时处理完异常后继续执行流上的任务 #define RT_STREAM_FAILURE_MODE_STOP_ON_FAILURE (0x1U) // 遇错即停4.3 排查思路的落地
对照上述头文件,报错示例中stmAttrId被传入-5:该值既不是rtStreamAttr枚举中的任何成员,也不在 1~6 的取值范围内,接口在校验阶段即判定非法,从而触发 EE1003 上报。这直观展示了“检查接口输入参数范围”在实践中的做法——以头文件中的枚举定义、宏定义、以及接口注释中标注的取值范围为准,而不是凭经验猜值。
5. 官方解决方法逐条展开:两步定位 EE1003
官方参考文档给出的解决方法是两条:
- Check the input parameter range of the function.(检查接口的输入参数范围)
- Check the function invocation relationship.(检查接口的调用关系)
下面结合仓库实际展开这两步。
5.1 第一步:核对接口输入参数范围
这是 EE1003 的首要排查方向,因为报错本身已经明确告诉了你“哪个参数、什么值、期望什么”。排查建议:
- 读报错中的参数名与期望值:报错第 3、4 段已经给出了参数名和合法范围,直接对比即可确认是否为“值越界”;
- 回查头文件中的枚举/宏定义:对于枚举类型参数,核对传入值是否为枚举成员(参考第 4.1 节的
rtStreamAttr);对于布尔开关,核对是否为 0/1(如 rts_stream.h 中的RT_STREAM_FAILURE_MODE_*、RT_STREAM_LAUNCH_BLOCKING_MODE_*等宏); - 确认传参类型与接口签名一致:注意
rtStreamAttrValue_t是联合体,若按错误的成员类型赋值(例如给uint64_t字段填入超过uint32_t的值),也可能触发校验失败; - 关注接口注释的返回值说明:如
rtsStreamSetAttribute注释所示,非法输入会返回RT_ERROR_INVALID_VALUE,与 EE1003 语义一致。
5.2 第二步:检查接口的调用关系
当“传入值本身合法、但仍报 EE1003”时,问题往往出在调用上下文而非参数值本身。典型场景包括:
- 接口未初始化前置依赖:例如在 Stream 创建/上下文绑定完成之前就调用属性设置接口,导致接口内部校验到流句柄或上下文状态异常,间接以参数非法形式返回;
- 多线程/多 Device 场景下的参数串扰:调用方在不同线程间复用了同一参数缓存或未初始化内存(如
attrValue指向的联合体未被正确赋值),读出的“参数值”不可预期; - 版本能力差异:某些属性或取值仅在特定 SoC(如 Arch 版本)上支持,跨版本复用参数可能导致校验失败——仓库中
runtime_api_stub_catalog.def、arch5162_unsupported_runtime_api.def等文件的存在,说明不同芯片架构对外暴露的 Runtime API 集合存在差异,这是排查时值得留意的一点。
此时建议梳理从应用入口到出错接口的完整调用链(初始化 → Device/Context 绑定 → Stream 创建 → 属性设置),确认每一环的返回值与调用顺序是否符合接口文档要求。
6. EE1003 与相邻错误码的区分与联动
排查 EE1003 时,常常会遇到“报错相似但错误码不同”的情况,区分它们有助于快速收敛方向:
| 错误码 | 标题 | 报错模板 | 典型触发场景 |
|---|---|---|---|
| EE1001 | Invalid_Argument | The argument is invalid. Reason: %s | 参数语义不合法,原因以附加信息给出 |
| EE1003 | Invalid_Argument | %s failed because value %s for parameter %s is invalid. Expected value: %s. | 参数值超出合法范围(本文主题) |
| EE1004 | Invalid_Argument_Null_Pointer | %s failed because %s cannot be a NULL pointer. | 指针参数为空,参见 EE1004 文档 |
| EE1005 | Not_Supported | The current system or device does not support %s. | 当前系统/设备不支持某功能 |
以上模板均可从 error_code.json 的ErrMessage字段逐一核对。简化的判断口诀:
- 报错里出现非法值 + 期望值→ EE1003;
- 报错里只提空指针→ EE1004;
- 报错里说明设备不支持→ EE1005;
- 报错里仅给出通用原因描述→ EE1001。
7. 快速自查清单(FAQ 式小结)
Q1:EE1003 报错中的“期望值 [0, 5)”是全局统一的范围吗?不是。期望值由具体接口及其所在版本的校验逻辑决定,报错示例中的[0, 5)仅用于演示格式。实际范围请以当前版本的头文件枚举、宏定义与接口文档为准。
Q2:报错里的函数名一定是我调用的那个 API 吗?通常是。EE1003 模板第 1 个%s由上报宏自动填充当前函数名(__func__),即错误发生处所属的接口;如果你的代码直接调用了该接口,那么它就是报错者;如果是间接调用,则需要沿调用链回溯。
Q3:为什么参数明明“看起来合法”还是会报 EE1003?优先按第 5.2 节检查调用关系与上下文状态(初始化、Device/Context 绑定、并发与版本能力差异),并确认传给接口的参数对象(尤其是指针指向的联合体/结构体)确实被正确初始化。
Q4:EE1003 与 EE1004 有什么区别?EE1004 专用于空指针参数(模板含cannot be a NULL pointer);EE1003 用于非空但值越界的参数。两者同属 RTS Errors 的 Invalid_Argument 类别,可对照 RTS 错误码总览 查看完整家族。
8. 结语
EE1003 是 CANN Runtime 对外输出“参数非法”信息的标准化通道:一方面,它以固定模板承载了函数名、非法值、参数名、期望值四要素,让报错信息本身具备极强的自解释性;另一方面,仓库在 error_code.json、base.hpp、error_message_manage.hpp 中的实现保证了全仓库错误文本格式统一、可被日志与上层工具稳定解析。遇到 EE1003 时,先读清四段式报错内容,再对照对应接口头文件的枚举与宏定义核查参数范围,最后审视调用关系与上下文状态,即可快速定位并消除问题。
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考