CANN Runtime Profiling 错误码 EK9999(System_Terminated)深度解析:错误语义、产生场景与日志定位指南
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
导读
EK9999(System_Terminated)是 CANN/runtime 仓库中 Profiling(性能采集)子系统用于兜底的“未知内部错误”错误码,其对外呈现为一句高度抽象的提示An unknown error occurred. Please check the log.。本文以 EK9999-System_Terminated.md 为主线,结合 error_code.json 中 EK9999 的注册定义,以及 msprof 采集链路中所有上报 EK9999 的真实代码点位,说明该错误码的定位方式、常见触发场景与日志排查路径,帮助你快速建立“看到 EK9999 后下一步该做什么”的完整思路。
EK9999 错误码的定位:Profiling 子系统的“内部错误兜底码”
官方错误码表中的地位
在 CANN/runtime 的 Profiling 错误码族(EK前缀)中,EK9999 是专门留给“系统/内部未知错误”的兜底码。其语义在官方文档中表述为:
- 英文文档:EK9999-System_Terminated.md
- 中文文档:EK9999-System_Terminated.md
官方给出的“错误信息(Symptom)”为:
An unknown error occurred. Please check the log.即:错误本身未知,需要借助日志进一步定位。中文版文档的“解决方法”进一步说明:内部错误,请根据日志进一步定位问题,或联系华为工程师。
错误码注册表:error_code.json 中的定义
该错误码并非仅在文档中存在,而是注册在 CANN/runtime 的错误码管理配置文件 src/dfx/error_manager/error_code.json 中(第 1315~1325 行附近)。其注册结构如下:
{ "errClass": "Profiling Errors", "errTitle": "System_Terminated", "ErrCode": "EK9999", "ErrMessage": "An unknown error occurred. Please check the log.", "Arglist": "", "suggestion": { "Possible Cause": "N/A", "Solution": "N/A" } }从这份注册表可以读出三个关键信息:
- 错误归类:
errClass为Profiling Errors,与 EK0001~EK0204 等错误码同属 Profiling 错误族; - 无参数化占位:
Arglist为空字符串,说明 EK9999 的对外信息中不含任何可动态填充的参数,用户侧永远只会看到那句固定的提示; - 无标准建议:
Possible Cause与Solution均为N/A,与文档中 "Solution: N/A" 完全对应。这从机制上确认了:EK9999 不是一个可以给出通用解决方案的错误码,其解决路径只能依赖日志。
命名约定:K 前缀的含义
在 CANN/runtime 的错误码体系(详见 macro-selection-guide.md)中,错误码第一个字母代表错误所属模块域:
| 前缀字母 | 模块域 | 典型码位 |
|---|---|---|
| E | 执行错误(Execution) | EE9999(Runtime 内部错误) |
| K | Profiling | EK9999 |
| L | Driver | EL9999 |
| Z | NPU 公共 / TBE | EZ9999 |
| E2 | FE(前端编译) | E29999 |
| E3 | AICPU | E39999 |
| I | HCCL | EI9999 |
Runtime 核心代码 base_info.hpp 中集中定义了这些“内部兜底码”常量,其中与本文直接相关的一行是:
static constexpr const char_t* RT_PROFILE_INNER_ERROR = "EK9999";可以看到,EK9999 在 Runtime 侧被显式命名为“Profiling 内部错误”(RT_PROFILE_INNER_ERROR),与 EE9999(Runtime 内部错误)、EZ9999(NPU 公共内部错误)、E29999(FE 内部错误)等并列。这进一步证实:只要 Profiling 链路中出现了未能映射到具体 EK 错误码的未知失败,统一收敛到 EK9999。
EK9999 的典型产生场景:来自 msprof 采集链路的真实证据
EK9999 并非只在极端情况下出现。从源码看,msprof 采集链路中有大量具体失败场景最终以 EK9999 上报。这些场景主要分布在 src/dfx/msprof/collector/dvvp 下的任务管理、引擎回调、作业包装器(job wrapper)与适配层中。
场景一:采集任务管理与生命周期(prof_task / prof_manager)
任务创建与设备初始化阶段是 EK9999 的高发区,参见 prof_task.cpp:
- 生成
info.json失败时上报"EK9999", "Failed to generate info.json."; - 设备已在采集中(重复启动)时上报
"EK9999", "Device %s is already running profiling, skip the device."; - 设备 init 失败时上报
"EK9999", "Device %s init failed, ret: %d."; - 设备 start 失败时上报
"EK9999", "Device %s start failed, ret: %d."。
任务调度侧 prof_manager.cpp 也有对应场景:
- 设备已在采集中:
"EK9999", "Device is already in profiling, device id: %s, job id: %s."; - 启动采集任务失败:
"EK9999", "Failed to launch profiling task, device id: %s, job id: %s."; - 处理采集任务失败:
"EK9999", "Failed to handle profiling task, device id: %s, job id: %s."; - 解析采样配置失败:
"EK9999", "Failed to parse sample config."; - 生成
sample.json失败:"EK9999", "Failed to create sample.json."; - 参数检查失败:
"EK9999", "Failed to check profiling params."。
要点:这些点位说明,重复对同一设备启动采集、设备初始化/启动异常、配置解析失败等,都会收敛到 EK9999 这个兜底码。
场景二:引擎回调与订阅管理(prof_acl_mgr)
引擎管理与订阅管理是另一个 EK9999 密集区域,参见 prof_acl_mgr.cpp:
- 回调 init/start/stop/finalize 失败:如
"EK9999", "Failed to callback init."、"EK9999", "Failed to callback start on device %u."、"EK9999", "Failed to callback stop on device %u."、"EK9999", "Failed to callback finalize."; - 订阅管理失败:如
"EK9999", "%s has not been subscribed."、"EK9999", "Failed to close subscribe fd %d."、重复订阅时"EK9999", "Failed to pass subscribe check, key %s has been subscribed"; - 工具链兼容性场景:
"EK9999", "Params created by msprof in oam-tools can not be analyzed by ..."(提示 msprof 工具产生的参数与当前分析组件不兼容)。
场景三:作业包装器与宿主进程(prof_host_job / prof_perf_job)
Host 侧采集作业管理同样会收敛到 EK9999,参见 prof_host_job.cpp 与 prof_perf_job.cpp:
ProfHostService初始化/启动/停止失败:如"EK9999", "Failed Init profHostService_"、"EK9999", "Failed Start profHostService_";- 宿主采集进程异常:如
"EK9999", "Failed to kill process %s, ret=%d, exitCode=%d"、"EK9999", "Failed to wait process %d, ret=%d, exitCode=%d"、pid 无效时"EK9999", "ProfHostCcaMsJob pid: %d is invalid."; - perf 采集文件打开失败:
"EK9999", "Failed to open %s, dev_id=%d"。
场景四:msproftx 打点与适配层
- msprof_tx_manager.cpp 中 msproftx 打点数据上报失败:
"EK9999", "Failed to report msproftx stamp data."; - msprofiler_impl.cpp 中回调 init 失败:
"EK9999", "Failed to callback init."。
EK9999 的上报机制:MSPROF_INNER_ERROR
上述所有点位都通过宏MSPROF_INNER_ERROR上报错误,该宏在 msprof_error_manager.h 中定义:
#define MSPROF_INPUT_ERROR(errorCode, key, value) \ Analysis::Dvvp::MsprofErrMgr::MsprofErrorManager::instance()->ReportErrorMessage(errorCode, key, value) #define MSPROF_ENV_ERROR MSPROF_INPUT_ERROR #define MSPROF_INNER_ERROR REPORT_INNER_ERR_MSG #define MSPROF_CALL_ERROR MSPROF_INNER_ERRORMSPROF_INNER_ERROR展开为REPORT_INNER_ERR_MSG,即通过MsprofErrorManager::ReportErrorMessage将“错误码 + 具体错误文本”送入错误上报通道。这正是 EK9999 区别于其他 EK 错误码的地方:虽然用户侧最终看到的都是同一句An unknown error occurred. Please check the log.,但伴随上报的日志中会携带上述源码中看到的具体失败原因文本(如Failed to callback start on device 0.)。因此,“看日志”不是一句空话——日志中记录的往往是比 EK9999 本身更有价值的精确信息。
排查路径:拿到 EK9999 后如何继续定位
由于官方文档明确 "Solution: N/A",EK9999 的定位只能依赖日志,建议按以下顺序排查:
第一步:确认错误码来源模块
- 先确认报错上下文是否与 Profiling 相关:EK 前缀 = Profiling,即 msprof 采集链路;
- 若同时出现其他前缀错误码(如 EE/LZ/EL),按错误码表(Profiling-Errors.md)与 macro-selection-guide.md 中的模块域映射,判断是否由底层模块失败传导而来。
第二步:定位伴随的具体错误日志
- 检索日志中 EK9999 前后的上下文字段,对照上文列出的真实上报点位,确认属于哪一类失败:
- 任务/设备管理类 → prof_task.cpp、prof_manager.cpp;
- 引擎回调/订阅类 → prof_acl_mgr.cpp;
- 宿主/采集进程类 → prof_host_job.cpp、prof_perf_job.cpp;
- 打点上报类 → msprof_tx_manager.cpp。
- 例如日志中出现
Failed to launch profiling task, device id: 0, job id: xxx,则对应 prof_manager.cpp 中启动采集任务失败的路径,应围绕设备状态与任务并发冲突排查;若出现Device 0 is already running profiling,则应检查是否有重复的采集任务在并发执行。
第三步:结合具体失败原因处理
常见原因与对应处置参考如下:
| 日志中的失败文本(示例) | 常见诱因 | 处置方向 |
|---|---|---|
Device %s is already running profiling | 同一设备被重复启动采集 | 等待上一轮采集结束,或复用同一任务句柄,避免并发重复启动 |
Device %s init/start failed, ret: %d | 设备侧采集初始化/启动失败 | 检查设备状态、驱动与资源可用性,结合ret值进一步定位 |
Failed to parse sample config/Failed to check profiling params | 采集配置非法 | 核对 prof 配置文件的参数格式与取值范围 |
Failed to callback start/stop on device %u | 引擎回调异常 | 检查对应采集引擎是否正常加载,必要时重新初始化 |
Failed to generate info.json/Failed to create sample.json | 结果文件目录不可写或磁盘空间不足 | 检查采集输出目录权限与剩余空间(Profiling flush 至少需要一定存储空间,参见 EK0204 的 20MB 提示) |
Failed to kill/wait process %s, ret=%d | Host 侧采集子进程异常退出 | 检查进程存活状态与退出码,必要时清理残留进程后重试 |
需要说明:上表“常见诱因/处置方向”属于基于源码上报文本的合理推断,实际根因需结合现场日志(日志级别、设备侧信息)进一步确认;若上述步骤无法定位,按中文文档建议联系华为工程师并提供日志。
第四步:无法定位时
- 保留完整日志(Host 侧与设备侧)与采集配置;
- 按 Profiling-Errors.md 的目录索引,确认 EK9999 是否与其他 EK 错误码(EK0001~EK0204)并列出现,缩小问题范围;
- 将日志提供给技术支持时,重点提供 EK9999 出现前、后的上下文,以及
ret/exitCode/fd等数值字段。
延伸理解:EK9999 与相邻兜底错误码的分工
EK9999 不是仓库中唯一的“未知错误兜底码”。从 base_info.hpp 可见,Runtime 为各模块域都定义了对应的内部兜底码:
| 常量 | 错误码 | 模块域 |
|---|---|---|
RT_INNER_ERROR | EE9999 | Runtime 执行域 |
RT_PROFILE_INNER_ERROR | EK9999 | Profiling 域 |
RT_DRV_INNER_ERROR | EL9999 | Driver 域 |
RT_NPU_COMMON_INNER_ERROR | EZ9999 | NPU 公共/TBE |
RT_FE_INNER_ERROR | E29999 | FE 前端 |
RT_AICPU_INNER_ERROR | E39999 | AICPU |
RT_HCCL_INNER_ERROR | EI9999 | HCCL |
理解这一“一域一兜底码”的分工后,排查时的第一步就非常明确:看到 EK9999,优先把注意力收敛到 Profiling 采集链路(msprof)的日志,而非全量 Runtime 日志。这也是官方只给出“检查日志”这一条指引、却未提供通用修复步骤的根本原因——EK9999 本身只是一个“入口错误码”,真正的答案藏在它背后那句具体的失败文本里。
总结
- EK9999 是什么:Profiling 域的“未知内部错误”兜底码,注册于 error_code.json,对外固定输出
An unknown error occurred. Please check the log.,无参数化信息、无通用解决方案(Solution: N/A)。 - 从哪来:msprof 采集链路中所有未映射到具体 EK 码的失败,包括任务创建与调度、设备重复采集、引擎回调、订阅管理、Host 采集子进程异常、msproftx 打点上报失败等,统一经
MSPROF_INNER_ERROR(msprof_error_manager.h)上报为 EK9999。 - 怎么办:以日志为准。对照本文列出的真实上报点位,找到 EK9999 伴随的具体失败文本,按上表方向处置;无法定位时保留完整日志联系华为工程师。
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考