ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CANN opbase 算子日志接口 OP_LOGE_WITH_INVALID_INPUT:必选参数为空的校验、日志与错误码上报实战

CANN opbase 算子日志接口 OP_LOGE_WITH_INVALID_INPUT:必选参数为空的校验、日志与错误码上报实战 CANN opbase 算子日志接口 OP_LOGE_WITH_INVALID_INPUT必选参数为空的校验、日志与错误码上报实战【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase导读本文聚焦 CANN 算子库基础框架opbase中op_common/log模块提供的算子日志接口OP_LOGE_WITH_INVALID_INPUT。该接口用于在算子或 aclnn 接口实现中对必选输入参数为空这一高频错误场景统一输出 ERROR 级别日志并同步上报预定义错误码 EZ0004。读完本文你将掌握该接口的函数原型、参数约束、底层日志落盘与错误码上报机制理解其为何被标记为废弃以及如何平滑迁移到OP_LOGE_FOR_INVALID_VALUE与OP_CHECK_NULL_WITH_CONTEXT这两条推荐替代路径。接口定位与功能说明OP_LOGE_WITH_INVALID_INPUT是 CANN 算子开发中用于输入参数空值校验的专用日志宏定义于 include/op_common/log/log.h。它的核心职责是当算子的必需参数为空典型如xDesc nullptr时输出一条ERROR 级别日志同时向框架上报EZ0004 错误码Invalid Input供上层错误码检索与问题定位使用。根据 docs/zh/error_code/Operator-Errors/EZ0004-Invalid_Input.md 的定义EZ0004 对应的错误信息格式为Parameter %s of %s is required, but it is empty.其中两个%s占位符依次为参数名与算子名/接口名。文档中给出的标准报错示例如下Parameter input of Cumsum is required, but it is empty.函数原型与参数说明OP_LOGE_WITH_INVALID_INPUT(entityName, paramName)参数名输入/输出说明entityName输入算子名称或 aclnn 接口名称支持const char*或std::string类型。paramName输入参数名称支持const char*或std::string类型。返回值无。约束说明无。该宏无额外前置约束但在语义上只应被用于参数必须存在却为空的场景。从 log.h 的宏定义可以看到两个入参在进入日志与上报流程前都会先被拷贝为局部std::string_safe_entityName_、_safe_paramName_随后按统一的日志格式输出#define OP_LOGE_WITH_INVALID_INPUT(entityName, paramName) \ do { \ std::string _safe_entityName_(entityName); \ std::string _safe_paramName_(paramName); \ OP_LOGE_LIBOPAPI_REPORT(_safe_entityName_.c_str(), Parameter %s of %s is required, but it is empty., \ _safe_paramName_.c_str(), _safe_entityName_.c_str()); \ const std::vectorconst char* msgKey {param_name, op_name}; \ const std::vectorconst char* msgvalue {_safe_paramName_.c_str(), _safe_entityName_.c_str()}; \ REPORT_PREDEFINED_ERR_MSG(EZ0004, msgKey, msgvalue); \ } while (0)调用示例与预期输出以下关键代码摘自原文档仅供参考不支持直接拷贝运行// 预期输出: Parameter input of MyOp is required, but it is empty. if (xDesc nullptr) { OP_LOGE_WITH_INVALID_INPUT(MyOp, input); return false; }在真实算子实现中典型的组合用法是先校验空指针再返回失败当从 context 中获取到的 shape/tensor 指针为nullptr时记录日志并上报错误码然后由调用方决定返回false或ge::GRAPH_FAILED等错误值。底层机制解析日志如何落盘错误码如何上报该宏实际上封装了两条独立链路理解这两条链路有助于你在排查问题时正确解读日志与错误码1. ERROR 级别日志输出OP_LOGE_LIBOPAPI_REPORTlog.h 中定义的OP_LOGE_LIBOPAPI_REPORT会先调用CheckLogLevel判断模块日志级别是否放行 ERROR 日志模块 ID 为OP_MODULE_ID 63见 log.h再调用DlogRecord写入日志。日志前缀会自动携带文件名、行号、子模块名默认OPS_BASE见 log.h、函数名、线程 ID以及OpName例如[file.cc:123][OPS_BASE][FunctionName][tid 12345] OpName:[MyOp] Parameter input of MyOp is required, but it is empty.因此一条 ERROR 日志本身就足以定位到具体文件、代码行、所在函数与触发线程这是该接口在排障中的最大价值。2. 预定义错误码上报REPORT_PREDEFINED_ERR_MSG宏的第二段通过REPORT_PREDEFINED_ERR_MSG(EZ0004, msgKey, msgvalue)完成错误码上报其中msgKey {param_name, op_name}声明了错误信息中的结构化字段msgvalue {paramName, entityName}填充实际值。这样上层框架可以按参数名 算子名两个维度结构化检索 EZ0004 错误而不只是依赖纯文本日志。EZ0004 错误码的完整描述与解决建议见 EZ0004-Invalid_Input.md其解决方法是检查算子必选参数是否设置正确。接口已废弃推荐的两条替代路径原文档明确标注本接口已废弃建议使用以下两个接口替代方案一OP_LOGE_FOR_INVALID_VALUE参数值校验语义更通用OP_LOGE_FOR_INVALID_VALUE 覆盖参数值与预期不符的通用场景上报的是EZ0024错误码。其原型为OP_LOGE_FOR_INVALID_VALUE(entityName, paramName, incorrectValue, correctValue)参数incorrectValue为实际参数值correctValue为预期参数值均支持const char*或std::string。示例// 预期输出: Parameter sp of AttentionUpdate has incorrect value 17. It should be // in range of [1, 16]. if (sp_ 1 || sp_ 16) { OP_LOGE_FOR_INVALID_VALUE(AttentionUpdate, sp, std::to_string(sp_), in range of [1, 16]); return ge::GRAPH_FAILED; }对应的 EZ0024 错误码格式为Parameter %s of %s has incorrect value %s. It should be %s.详见 EZ0024-Invalid_Argument.md。在 src/op_common/atvoss/reduce/reduce_tiling.cpp 中可以看到该系列接口的真实调用形态例如通过context_-GetNodeName()动态获取算子名后上报vectorCoreNum、ubSize、cacheLineSize等关键参数的非法值OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(context_-GetNodeName(), ubSize, ...);这印证了entityName入参除了手写字符串常量也支持从context中动态取算子节点名从而让日志与错误码自动携带真实算子信息。方案二OP_CHECK_NULL_WITH_CONTEXT空指针校验一体化OP_CHECK_NULL_WITH_CONTEXT 将空指针判断 日志输出 返回失败合并为一个宏语义更贴近OP_LOGE_WITH_INVALID_INPUT原本的典型用法OP_CHECK_NULL_WITH_CONTEXT(context, ptr)context上下文信息类型为InferShapeContext/TilingParseContext/TilingContextptr待判定的指针返回值当ptr为nullptr时返回ge::GRAPH_FAILED。其底层实现log.h会通过context-GetNodeName()获取节点名context 为空或节点名为空时回退为字符串nil记录日志%s is nullptr!并直接返回ge::GRAPH_FAILED。典型用法auto inShape context-GetInputShape(0); OP_CHECK_NULL_WITH_CONTEXT(context, inShape); auto axesTensor context-GetInputTensor(1); OP_CHECK_NULL_WITH_CONTEXT(context, axesTensor); auto outShape context-GetOutputShape(0); OP_CHECK_NULL_WITH_CONTEXT(context, outShape);如何选择迁移路径场景推荐接口仅需校验指针/对象是否为空并快速失败OP_CHECK_NULL_WITH_CONTEXT(context, ptr)需要输出实际值 vs 预期值的对比信息如参数取值越界、取值不合法OP_LOGE_FOR_INVALID_VALUE(entityName, paramName, incorrectValue, correctValue)需要在日志之外附带自定义失败原因OP_LOGE_FOR_INVALID_VALUE_WITH_REASON/OP_LOGE_FOR_INVALID_VALUES_WITH_REASON见 log.h使用建议与注意事项新代码不要继续使用本接口它已被官方标记为废弃继续使用无法享受后续错误码演进与新增语义存量代码在改造时按上述两个替代接口平滑迁移即可。参数校验后必须返回失败日志与错误码上报只是记录手段宏本身不打断执行流因此需要在调用后显式return false/return ge::GRAPH_FAILED避免空指针继续参与后续计算。entityName 尽量使用真实算子名既可以手写字符串常量也可以使用context-GetNodeName()动态获取便于在多算子混跑时快速定位归属算子。同系列接口保持一致性该接口隶属于op_common/log日志宏家族家族内还有OP_LOGE_WITH_INVALID_INPUT_SHAPEEZ0001、OP_LOGE_WITH_INVALID_ATTREZ0002、OP_LOGE_WITH_INVALID_INPUT_SHAPESIZEEZ0005、OP_LOGE_WITH_INVALID_INPUT_FORMATEZ0006、OP_LOGE_WITH_INVALID_INPUT_DTYPEEZ0007等兄弟宏见 log.md 与 log.h。它们遵循完全相同的ERROR 日志 预定义错误码上报双通道设计掌握了本接口的机制即可举一反三。完整的算子错误码清单可参考 Operator-Errors 目录。总结OP_LOGE_WITH_INVALID_INPUT曾是 CANN 算子在必选输入参数为空场景下的标准错误记录手段它通过ERROR 级别日志 EZ0004 错误码上报的双通道设计让空参错误既能在运行时日志中快速定位到源码位置与线程又能以结构化字段参数名、算子名被上层框架检索。尽管该接口现已废弃但其背后日志记录 预定义错误码上报的设计思想依然贯穿 opbase 全部日志宏而OP_LOGE_FOR_INVALID_VALUE与OP_CHECK_NULL_WITH_CONTEXT则分别以更通用的参数值校验语义和更紧凑的空指针校验语义承接了它的职责是当前算子开发中处理参数合法性校验的推荐选择。【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进