CANN Runtime 错误码 EK0002 深度解析:Profiling 接口调用顺序错误(Invalid_Argument_API_Call_Sequence)
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
EK0002 是 CANN Runtime 维测组件(msprof)在 Profiling 采集过程中,检测到上层应用以错误的顺序调用 Profiling 接口时上报的参数类错误码。当用户在使用aclprofInit、aclprofStart、aclprofWarmup、aclprofCreateStamp等采集接口时,若跳过前置初始化或越过生命周期阶段,就会收到形如 "Please call the APIs in the following order: call %s first, then %s." 的报错。阅读本文后,你将能够准确解读 EK0002 报错中的两个占位符含义,理解 msprof 内部的状态检查机制,掌握 Profiling 接口的正确调用顺序与排查修复方法。
一、错误码定义与报错格式
EK0002 的完整定义位于错误码注册表 error_code.json 中,归属Profiling Errors错误类:
| 字段 | 值 |
|---|---|
| errClass | Profiling Errors |
| errTitle | Invalid_Argument_API_Call_Sequence |
| ErrCode | EK0002 |
| ErrMessage | Please call the APIs in the following order: call %s first, then %s. |
| Arglist | intf1, intf2 |
从定义可以看到,该错误码的报文模板中携带两个占位符参数:
intf1(第一个%s):必须先调用的接口名;intf2(第二个%s):当前错误调用的接口名。
报错格式
报错文本统一为以下格式(占位符%s均为接口名):
Please call the APIs in the following order: call %s first, then %s.报错示例
以文档中的原始示例为例,当应用在未调用aclprofInit的情况下直接调用aclprofStart时,输出如下:
Please call the APIs in the following order: call aclprofInit first, then aclprofStart.该提示语义清晰:系统要求用户先调用aclprofInit完成 Profiling 模块初始化,再调用aclprofStart启动数据采集。
二、底层实现:EK0002 是如何被触发的
EK0002 并非凭空产生,而是 msprof 组件在各 Profiling 接口入口处对"初始化状态"和"生命周期阶段"做前置校验后,通过统一错误上报机制打出的。整个链路可分为两层。
2.1 统一错误上报宏 MSPROF_INPUT_ERROR
msprof 组件将所有"入参/状态不合法"类错误统一封装进宏MSPROF_INPUT_ERROR,其定义位于 msprof_error_manager.h:
#define MSPROF_INPUT_ERROR(errorCode, key, value) \ Analysis::Dvvp::MsprofErrMgr::MsprofErrorManager::instance()->ReportErrorMessage(errorCode, key, value)调用时传入三个参数:
errorCode:错误码字符串(如"EK0002");key:参数名列表(对 EK0002 固定为{"intf1", "intf2"},对应错误码注册表中的Arglist);value:参数值列表(即两个真实接口名的字符串数组)。
ReportErrorMessage会结合 error_code.json 中的ErrMessage模板,将key/value一一对应地填充进%s占位符,最终生成用户在日志中看到的完整报错文本。
2.2 状态前置校验触发点
从源码结构看,EK0002 主要在以下三类场景中被抛出:
- 启动采集前未初始化:
aclprofStart/aclprofWarmup入口先调用ProfAclMgr::ProfStartPrecheck()做预检查,若返回ACL_ERROR_PROF_NOT_RUN(表示 Profiling 尚未初始化),随即上报 EK0002,提示先调用aclprofInit; - Warmup 与 Start 顺序冲突:
aclprofWarmup若在aclprofStart之后被调用,会因阶段冲突上报 EK0002; - Stamp 创建前未启动采集:msproftx(时间戳打点)管理器
MsprofTxManager未初始化时调用aclprofCreateStamp,上报 EK0002 提示先调用aclprofStart。
这些校验逻辑的具体位置与示例见下一节。
三、典型触发场景与源码佐证
场景一:未调用 aclprofInit 就调用 aclprofStart / aclprofWarmup
在 msprofiler_acl_api.cpp 的ProfWarmup实现中,预检查失败(ACL_ERROR_PROF_NOT_RUN)时上报:
int32_t ret = ProfAclMgr::instance()->ProfStartPrecheck(); if (ret != ACL_SUCCESS) { if (ret == ACL_ERROR_PROF_NOT_RUN) { MSPROF_INPUT_ERROR( "EK0002", std::vector<std::string>({"intf1", "intf2"}), std::vector<std::string>({"aclprofInit", "aclprofWarmup"})); } return ret; }同理,aclprofStart入口的预检查失败路径上报(见 msprofiler_acl_api.cpp):
MSPROF_INPUT_ERROR( "EK0002", std::vector<std::string>({"intf1", "intf2"}), std::vector<std::string>({"aclprofInit", "aclprofStart"}));即:必须先aclprofInit,再aclprofStart——这正是文档示例报错的来源。
场景二:aclprofWarmup 在 aclprofStart 之后调用
aclprofWarmup用于在正式采集前预分配 Profiling 配置资源,代码中通过ProfAclMgr::IsAclApiReady()判断采集是否已启动,若已启动则报错(见 msprofiler_acl_api.cpp):
// ProfWarmup will not work after ProfStart called if (ProfAclMgr::instance()->IsAclApiReady()) { MSPROF_LOGE("aclprofWarmup cannot be called after aclprofStart."); MSPROF_INPUT_ERROR( "EK0002", std::vector<std::string>({"intf1", "intf2"}), std::vector<std::string>({"aclprofWarmup", "aclprofStart"})); return ACL_ERROR_PROF_API_CONFLICT; }场景三:未启动采集就创建时间戳
在 msprof_tx_manager.cpp 的MsprofTxManager::CreateStamp()中,管理器未初始化(isInit_为 false)时上报:
ACL_PROF_STAMP_PTR MsprofTxManager::CreateStamp() const { if (!isInit_) { MSPROF_LOGE("[CreateStamp]MsprofTxManager is not inited yet"); MSPROF_INPUT_ERROR( "EK0002", std::vector<std::string>({"intf1", "intf2"}), std::vector<std::string>({"aclprofStart", "aclprofCreateStamp"})); return nullptr; } return stampPool_->CreateStamp(); }即:必须先aclprofStart,再aclprofCreateStamp。同理,prof_acl_mgr.cpp 中还有多处aclprofInit与各类采集接口之间的顺序校验,均以 EK0002 上报。
四、Profiling 接口的正确调用顺序
根据上述源码中的状态机约束,可以归纳出 Profiling 接口的标准生命周期为:
aclprofInit ──> aclprofStart ──> aclprofStop ──> aclprofFinalize │ └── 采集过程中可使用 aclprofCreateStamp 等打点接口其中各接口的声明可见 acl_prof.h:
aclprofInit:初始化 Profiling 模块,传入结果目录与路径长度;aclprofStart:按aclprofConfig配置启动采集;aclprofStop:停止采集(停止后仍可通过再次aclprofStart续采);aclprofFinalize:去初始化,释放 Profiling 资源;aclprofWarmup:可选,在aclprofStart之前调用以预分配配置资源;aclprofCreateStamp/aclprofDestroyStamp:在采集已启动后用于打点与销毁时间戳。
推荐的正确调用伪代码
#include "acl/acl_prof.h" // 1. 初始化 Profiling(必须先调用) const char *resultPath = "./prof_result"; aclprofInit(resultPath, strlen(resultPath)); // 2. (可选)在启动前预分配资源 aclprofConfig *cfg = ...; // 组装设备、数据类型、指标等配置 aclprofWarmup(cfg); // 3. 启动数据采集 aclprofStart(cfg); // 4. 采集过程中打点 void *stamp = aclprofCreateStamp(); // ... 记录自定义时间戳 ... // 5. 停止采集 aclprofStop(cfg); // 6. 去初始化 aclprofFinalize();注意:上述接口的详细参数说明请参考仓库中的 02_initialization_and_deinitialization.md 与 19-01_data_profiling_apis.md。
五、排查与解决方法
根据文档给出的官方解法并结合源码校验逻辑,处理 EK0002 请按以下步骤进行:
- 读取报错中的两个接口名:确认
intf1(应先调用)与intf2(当前非法调用)。报错语义是"先调用 A,再调用 B",即 B 的执行依赖 A 已成功完成。 - 检查应用调用顺序:对照标准生命周期核对代码。常见根因包括:
- 忘记调用
aclprofInit就直接aclprofStart; - 多个线程/模块并发采集,其中一个线程抢先
aclprofStop或aclprofFinalize,导致另一线程后续接口调用落空; aclprofWarmup放在了aclprofStart之后;- 程序退出清理阶段重复调用
aclprofFinalize。
- 忘记调用
- 补充前置接口调用:在
intf2对应的接口调用之前,确保intf1对应的接口已经成功返回,并妥善处理其返回值(aclError)。 - 注意生命周期与线程安全:从源码看,msprof 对各接口的预检查在全局互斥锁(如 msprofiler_acl_api.cpp 中的
g_profMutex)保护下执行,因此应用侧应避免在多线程中交叉调用aclprofStart/aclprofStop/aclprofFinalize等全局状态接口。 - 对照官方接口清单复核:完整的 Profiling 错误码索引见 Profiling-Errors.md,同族错误码还包括 EK0001(参数值非法)、EK0004(接口不支持)等,可一并参考以区分错误类型。
六、测试验证
仓库单元测试 prof_acl_core_utest.cpp 中通过桩件MsprofUtestStub::GetMsprofLastInputErrorCode()对 EK0002 的上报行为做了断言:
EXPECT_EQ("EK0002", MsprofUtestStub::GetMsprofLastInputErrorCode());该测试文件在多处(如 L4514、L5225、L5440-L5457)针对不同的非法调用顺序场景校验了最终上报错误码是否为 EK0002,读者可以结合这些用例深入理解各触发分支的判定条件。
七、小结
EK0002(Invalid_Argument_API_Call_Sequence)是 msprof Profiling 组件在接口调用顺序违反生命周期约束时上报的参数类错误。其报文通过intf1、intf2两个占位符明确告知"应先调用谁、当前调用了谁"。修复的核心思路非常简单:严格按照aclprofInit → aclprofStart → aclprofStop → aclprofFinalize的顺序调用,并确保aclprofWarmup、aclprofCreateStamp等依赖型接口位于其前置接口之后。理解 error_code.json 中的模板定义与 msprof_error_manager.h 的上报机制,可以帮助你在遇到类似顺序类错误时快速定位问题代码。
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考