CANN Runtime 错误码 EP0004 全解析:Dump 配置文件解析失败的定位与修复指南
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
导读
EP0004(File Operation Error - Parse)是 CANN Runtime 中 adump 数据采集组件上报的"配置文件解析失败"错误码,用于标识acl.json等 Dump 配置 JSON 文件无法通过语法解析的场景。本文基于开源仓库cann/runtime中的错误码参考文档,结合src/dfx/adump下的真实实现与单元测试,完整拆解该错误码的报文格式、触发链路、典型原因与排查方法。读者阅读后可准确解读 EP0004 报错中的每个占位符含义,并据此快速修复异常的 Dump 配置文件。
错误码概览:EP 系列在 Dump 错误体系中的定位
EP0004 属于 "DUMP Errors"(Dump 错误)错误类,在 Dump 错误码索引 中与其姊妹错误码共同构成一套完整的 Dump 配置校验错误体系:
| 错误码 | 错误标题 | 语义 |
|---|---|---|
| EP0001 | Config Error | 配置项内容无效 |
| EP0002 | Config Error | 配置项取值无效(给出期望值) |
| EP0003 | Config Error | 配置项取值无效(给出原因) |
| EP0004 | File Operation Error - Parse | 配置文件解析失败 |
| EP0005 | Config Error | 配置项之间存在冲突 |
| EP0006 | Invalid Argument | 参数取值无效 |
| EP0007 | Invalid Argument - Null Pointer | 参数为空指针 |
| EP0008 | Invalid Argument - API Call Sequence | API 调用顺序错误 |
从语义上看,EP0004 是其中唯一一个面向"文件整体解析"(而非单个配置项)的错误码:当 Dump 配置 JSON 文件在语法层面无法被解析时触发,而字段类型、取值、冲突等语义层面的问题则分别由 EP0001/EP0002/EP0003/EP0005 负责。这一分工可以在仓库的错误码注册表中得到直接印证,见 error_code.json:
{ "errClass": "DUMP Errors", "errTitle": "File_Operation_Error_Parse", "ErrCode": "EP0004", "ErrMessage": "Failed to parse file %s. Reason: %s.", "Arglist": "path,reason", "suggestion": { "Possible Cause": "N/A", "Solution": "N/A" } }错误信息格式与字段含义
EP0004 的标准报错格式(见 官方文档):
Failed to parse file %s. Reason: %s.两个占位符%s的含义依次为:
| 占位符 | 含义 | 对应 Arglist |
|---|---|---|
第 1 个%s | 配置文件路径(file name / path) | path |
第 2 个%s | 解析失败的具体原因(error cause / reason) | reason |
官方给出的报错示例如下:
Failed to parse file /home/test_dump/acl.json. Reason: [json.exception.type_error.302] type must be array, but is string.在这个例子中,/home/test_dump/acl.json是待解析的配置文件路径,而[json.exception.type_error.302] type must be array, but is string则是底层 JSON 解析器抛出的异常描述。从异常前缀json.exception.type_error.302可以推断,解析工作由 nlohmann/json 库执行——这一点与下文源码实现中的调用保持一致。
触发链路:EP0004 从哪里来
EP0004 并非由人工手写抛出,而是由 adump 组件在 Dump 配置转换流程中自动上报。整条链路如下:
1. 上报宏定义
EP0004 的上报入口封装在 adump_error_manager.h 中:
// EP0004 Parse Error Report Macro - Inline for performance #define REPORT_EP0004_PARSE_ERROR(moduleName, reason, configPath) \ do { \ IDE_LOGE("[%s] Parse failed: %s", moduleName, ADUMP_TO_CSTR(reason)); \ ADUMP_INPUT_ERROR( \ "EP0004", std::vector<std::string>({"path", "reason"}), std::vector<std::string>({configPath, reason})); \ } while (0)该宏做了两件事:
- 通过
IDE_LOGE在本地日志中记录[模块名] Parse failed: 原因; - 通过
ADUMP_INPUT_ERROR将错误码EP0004及参数path(配置文件路径)、reason(解析原因)上报到错误管理模块,最终按error_code.json中的模板格式化输出。
注意宏体中传入的path参数名为configPath,说明该错误码的"文件"实际上特指 Dump 配置文件。
2. JSON 语法解析:JsonParser::ParseJsonFromMemory
EP0004 的根因在于 JSON 语法解析失败,解析动作由 json_parser.cpp 中的ParseJsonFromMemory完成:
int32_t JsonParser::ParseJsonFromMemory( const char* dumpConfigData, size_t dumpConfigSize, nlohmann::json& js, std::string& errMsg) { errMsg.clear(); if ((dumpConfigData == nullptr) || (dumpConfigSize == 0U)) { errMsg = "Invalid input parameters"; IDE_LOGD("Parse json from memory failed: invalid input parameters."); return ADUMP_INPUT_FAILED; } try { std::string_view jsonString(dumpConfigData, dumpConfigSize); IDE_LOGI("Parse json string: %.*s", static_cast<int>(jsonString.size()), jsonString.data()); js = nlohmann::json::parse(jsonString); IDE_LOGD("Parse json successfully."); return ADUMP_SUCCESS; } catch (const nlohmann::json::parse_error& e) { errMsg = e.what(); IDE_LOGE("JSON parse error: %s", e.what()); } catch (const std::exception& e) { errMsg = e.what(); IDE_LOGE("Unexpected error while parsing JSON from memory: %s", e.what()); } return ADUMP_INPUT_FAILED; }关键实现细节:
- 使用nlohmann/json库的
nlohmann::json::parse对配置内存数据进行解析,这与报错示例中的json.exception.type_error.302异常前缀完全吻合; - 配置数据为空(空指针或长度为 0)时,
errMsg被置为Invalid input parameters; - 捕获
nlohmann::json::parse_error(纯语法错误)和其他std::exception(运行时异常,如类型错误),异常描述e.what()会原样写入errMsg,作为 EP0004 报错的 Reason 部分透传出来。
3. 错误上报入口:DumpConfigConverter::Convert
dump_config_converter.cpp 中的Convert是 Dump 配置转换的主流程,也是 EP0004 仅有的两处上报点:
上报点 1:JSON 语法解析失败
nlohmann::json js; std::string errMsg; needDump = false; int32_t ret = JsonParser::ParseJsonFromMemory(dumpConfigData_, dumpConfigSize_, js, errMsg); if (ret != ADUMP_SUCCESS) { REPORT_EP0004_PARSE_ERROR("Convert", errMsg, configPath_); return ADUMP_FAILED; }当ParseJsonFromMemory返回失败时,立即上报 EP0004,Reason 即为解析器返回的errMsg,随后整个配置转换流程以失败结束。
上报点 2:后续处理中的运行时异常
try { ... dumpJs_ = js.at(ADUMP_DUMP); ... } catch (const std::exception& e) { REPORT_EP0004_PARSE_ERROR("Convert", std::string(e.what()), configPath_); return ADUMP_FAILED; }即使在语法解析通过之后,若对 JSON 内容的后续访问(如js.at(ADUMP_DUMP)取值、类型转换等)抛出std::exception(典型的如官方示例中的type_error.302:期望数组实际是字符串),同样会走 EP0004 上报路径。
由此可以归纳出触发 EP0004 的完整条件:Dump 配置文件在语法或底层类型层面无法被 nlohmann/json 正常解析/访问。而字段语义层面的校验(如dump必须是对象、dump_list必须是数组等)则走 EP0001 路径,两者在源码中分工明确。
典型报错场景与原因分类
结合 单元测试用例TestJsonSyntaxErrors,EP0004 覆盖的典型失败场景包括:
| 输入配置(JSON) | 问题描述 | 期望错误码 |
|---|---|---|
{"dump": {"dump_op_switch": "on" | 花括号未闭合,JSON 语法不完整 | EP0004 |
{"dump": {"dump_list": [{"model_name": "model1"}) | 方括号/圆括号混用、括号不匹配 | EP0004 |
asdf{ | 完全不是合法 JSON | EP0004 |
测试辅助函数TestFailureHelper(同文件)会构造DumpConfigConverter并调用Convert,断言返回值为ADUMP_FAILED且上报的错误码正是EP0004:
void TestFailureHelper( const std::string& configData, const std::string& configPath, const std::string& expectedErrorCode) { ... DumpConfigConverter converter{configData.c_str(), configData.size(), configPath.c_str()}; int32_t ret = converter.Convert(dumpType, dumpConfig, IsNeedDump, dumpDfxConfig); EXPECT_EQ(ret, ADUMP_FAILED); EXPECT_FALSE(IsNeedDump); EXPECT_EQ(GetLastReportedErrorCode(), expectedErrorCode); }需要注意的是,同一测试文件中另有TestDumpFieldTypeErrors(L483-L492),其中{"dump": true}、{"dump": []}等语法合法但类型错误的输入期望的是 EP0001 而非 EP0004。这说明:凡是能通过 JSON 语法解析的问题,都不会报 EP0004;EP0004 严格对应"文件本身无法被解析"这一层。
排查与修复步骤
按照官方文档的解决方法,修复思路是按照 Reason 中的提示检查并修改。结合源码实现,可以细化出以下排查路径:
步骤 1:先读 Reason,区分错误大类
EP0004 报错中的 Reason 直接来自 nlohmann/json 的异常描述,常见形态包括:
[json.exception.parse_error.101] parse error at line X, column Y: ...—— 纯语法错误,通常是括号不匹配、引号未闭合、尾逗号、非法字符等;[json.exception.type_error.302] type must be array, but is string—— JSON 合法,但代码期望的 JSON 类型与实际类型不一致(如官方示例);Invalid input parameters—— 配置文件内容为空(空指针或长度为 0)。
步骤 2:检查 JSON 语法与括号配对
对配置文件做基本的语法自查:
- 花括号
{}、方括号[]、引号必须成对且闭合; - 键名必须用双引号包裹;
- 不允许尾随逗号(如
"a": 1,}); - 整体必须是单个合法的 JSON 值(对象或数组)。
仓库中的合法示例可参考 0_adump_args/acl.json:
{"dump": {"dump_path": "./", "dump_list": [], "dump_op_switch": "on", "dump_data": "tensor"}}步骤 3:核对配置项取值是否匹配期望类型
当 Reason 中出现type_error时,说明 JSON 语法虽合法,但某个字段的类型与解析代码期望不符。adump 解析代码(dump_config_converter.cpp)对dump对象内各字段的读取方式决定了其期望类型:字符串型字段直接取值,而dump_stats、dump_list、blacklist的pos等字段则要求为字符串数组。类型不匹配会抛异常并触发 EP0004。
步骤 4:确认整体结构
配置文件的顶层应包含dump对象(ADUMP_DUMP键),Dump 配置项均位于该对象内。若缺失dump键,Convert会直接返回成功而不做 Dump,不会触发 EP0004。
步骤 5:修改后重跑验证
修正配置后重新触发采集,确认不再出现Failed to parse file ...报文。若解析通过后仍有问题,报错码会切换为 EP0001(字段类型/内容)、EP0002(取值不在期望集合内)、EP0003(取值非法并给出原因)或 EP0005(配置项冲突),此时需参照对应错误码文档继续排查。
与其他 EP 错误码的边界区分
在实际排障中,最容易与 EP0004 混淆的是 EP0001,二者的边界如下:
- EP0004:文件整体无法解析(JSON 语法错误、解析期类型异常、内容为空)。对应
ParseJsonFromMemory失败或Convert的try块内抛出的std::exception; - EP0001:文件能解析,但配置项的类型或内容非法(如
dump不是对象、dump_path不是字符串),由CheckDumpFieldTypes、CheckDumpFieldValues等校验函数主动上报,Reason 来自 adump_error_manager.h 中预定义的常量(如This configuration item must be of the array type、The configuration item value is empty等); - EP0005:文件能解析且字段合法,但配置项之间存在互斥约束冲突,Reason 模板同样定义在 adump_error_manager.h 中。
简单记忆:EP0004 是"JSON 都读不了",EP0001/0002/0003/0005 是"JSON 读得了但内容不合法"。
测试验证与进一步阅读
若希望复现 EP0004 的上报行为,可直接查看 dump_config_converter_utest.cpp 中的TestJsonSyntaxErrors用例;其错误码模板与参数格式化逻辑在 error_manager_stub.cpp 中有对应桩实现,可供理解上报机制的端到端行为。
进一步阅读建议:
- EP0004 官方文档(英文)
- EP0004 官方文档(中文)
- Dump 错误码索引
- 错误码注册表
- EP0004 上报宏与错误原因常量
- Dump 配置转换主流程
- JSON 解析器实现
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考