CANN opbase 算子参数值校验日志宏 OP_LOGE_FOR_INVALID_VALUE 使用指南
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
导读
OP_LOGE_FOR_INVALID_VALUE是 CANN opbase 基础框架库为算子与 aclnn 接口实现提供的参数值校验日志宏,用于在算子的某个参数取值与预期不符时,输出 ERROR 级别日志并同步上报 EZ0024 预定义错误码。本指南围绕该宏的功能说明、函数原型、参数语义、底层实现与调用示例展开,帮助算子开发者在宿主侧(Host)的参数合法性检查场景中,用一行代码完成"日志打印 + 错误码上报"的标准化错误处理。
功能说明
在算子实现(尤其是 Shape 推导、Tiling 计算等 Host 侧逻辑)中,经常需要对算子参数(Attribute 或输入参数)的取值范围、枚举值进行合法性校验。当校验失败时,如果只写普通的printf或裸的OP_LOGE,往往存在两个问题:日志格式不统一、错误信息无法被上层框架结构化解析。
OP_LOGE_FOR_INVALID_VALUE解决的就是这个问题:它记录并上报参数值校验错误。当算子的指定参数值与预期不符时,该宏会:
- 输出一条 ERROR 级别日志(带文件名、行号、函数名、线程 ID、算子名等上下文信息);
- 通过
REPORT_PREDEFINED_ERR_MSG("EZ0024", ...)上报 EZ0024 预定义错误码,将参数名、算子名、错误值、正确值四个字段以键值对形式写入错误消息,供上层框架解析与定位。
该宏属于"仅供算子或 aclnn 实现使用"的接口,声明与实现在 include/op_common/log/log.h 中。
函数原型
OP_LOGE_FOR_INVALID_VALUE(entityName, paramName, incorrectValue, correctValue)宏的使用方式与函数一致,调用时直接传入四个参数即可,不需要加分号外的额外处理。该宏在 include/op_common/log/log.h#L733-L747 中的完整定义如下:
#define OP_LOGE_FOR_INVALID_VALUE(entityName, paramName, incorrectValue, correctValue) \ do { \ std::string _safe_entityName_(entityName); \ std::string _safe_paramName_(paramName); \ std::string _safe_incorrectValue_(incorrectValue); \ std::string _safe_correctValue_(correctValue); \ OP_LOGE_LIBOPAPI_REPORT(_safe_entityName_.c_str(), \ "Parameter %s of %s has incorrect value %s. It should be %s.", \ _safe_paramName_.c_str(), _safe_entityName_.c_str(), \ _safe_incorrectValue_.c_str(), _safe_correctValue_.c_str());\ const std::vector<const char*> msgKey = {"param_name", "op_name", "incorrect_value", "correct_value"}; \ const std::vector<const char*> msgvalue = {_safe_paramName_.c_str(), _safe_entityName_.c_str(), \ _safe_incorrectValue_.c_str(), _safe_correctValue_.c_str()}; \ REPORT_PREDEFINED_ERR_MSG("EZ0024", msgKey, msgvalue); \ } while (0)从定义可以看出:
- 宏体被
do { ... } while (0)包裹,可以安全地用在if/else分支中,不会产生悬挂 else 问题; - 四个参数都会先被拷贝为局部
std::string,再通过.c_str()传入日志与错误上报接口,避免传入临时对象或字面量时产生悬垂指针; - 日志与错误码上报共用同一组格式化参数,保证"日志里写的"和"错误码里报的"完全一致。
参数说明
| 参数名 | 输入/输出 | 说明 |
|---|---|---|
| entityName | 输入 | 算子名称或 aclnn 接口名称,支持const char*或std::string类型。 |
| paramName | 输入 | 参数名称,支持const char*或std::string类型。 |
| incorrectValue | 输入 | 实际参数值,支持const char*或std::string类型。 |
| correctValue | 输入 | 预期参数值,支持const char*或std::string类型。 |
返回值说明:无。宏仅负责输出日志与上报错误码,不改变程序返回值。
约束说明:无。该宏对使用场景无特殊限制,但按照其设计意图,应仅在参数值校验失败的分支中调用。
日志输出与错误码上报的底层链路
日志格式
OP_LOGE_FOR_INVALID_VALUE内部调用OP_LOGE_LIBOPAPI_REPORT(定义在 include/op_common/log/log.h#L106-L115),其格式化模板为:
[文件名:行号][OP_SUBMOD_NAME][函数名][线程ID] OpName:[算子名] Parameter %s of %s has incorrect value %s. It should be %s.其中OP_SUBMOD_NAME默认值为"OPS_BASE"(include/op_common/log/log.h#L52-L54),线程 ID 通过syscall(__NR_gettid)获取(include/op_common/log/log.h#L56-L60)。日志级别为DLOG_ERROR(值为 3,见 include/op_common/log/log.h#L38-L40),输出前会先通过CheckLogLevel检查日志开关,避免在关闭 ERROR 日志的场景下产生额外开销。
错误码 EZ0024
宏上报的错误码为EZ0024,对应的消息模板与解决建议见 docs/zh/error_code/Operator-Errors/EZ0024-Invalid_Argument.md:
Parameter %s of %s has incorrect value %s. It should be %s.占位符%s的含义依次为:参数名、算子名或接口名、错误值、正确值。上报时以键值对形式携带四个字段:param_name、op_name、incorrect_value、correct_value,便于上层错误管理框架(如op_error_manager)结构化解析与聚合去重。
与普通日志宏的差异
与OP_LOGE(上报 EZ9999 通用错误码,见 include/op_common/log/log.h#L1076-L1080)相比,OP_LOGE_FOR_INVALID_VALUE携带了EZ0024 专属错误码,能够精确表达"参数值错误"这一错误类别,而不是落入笼统的内部错误。这也是 opbase 在 include/op_common/log/log.h 中维护 EZ0008~EZ0038 一整套"通用参数校验宏"(General Parameter Validation Macros,见 include/op_common/log/log.h#L285-L288)的初衷:针对形状、维度、size、format、dtype、value、stride、list size 等不同维度给出语义明确的错误码,实现错误信息标准化。
调用示例
以下示例来自原文档,展示了对算子参数进行范围校验的典型用法。关键代码示例如下,仅供参考,不支持直接拷贝运行:
// 预期输出: 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; }将示例扩展为更贴近真实算子实现的完整形态:
// 对枚举类参数做取值校验 if (update_type_ != 0 && update_type_ != 1) { // 预期输出: Parameter update_type of AttentionUpdate has incorrect value 2. // It should be 0 or 1. OP_LOGE_FOR_INVALID_VALUE("AttentionUpdate", "update_type", std::to_string(update_type_), "0 or 1"); return ge::GRAPH_FAILED; } // 对字符串参数做取值校验 if (paddingMode != "SAME" && paddingMode != "VALID") { OP_LOGE_FOR_INVALID_VALUE("Conv2D", "paddingMode", paddingMode, "SAME or VALID"); return ge::GRAPH_FAILED; }实践要点:
incorrectValue建议通过std::to_string()将数值转成字符串,或直接传入已格式化的字符串;日志接口统一按%s打印,避免类型不匹配;correctValue既可以描述具体的预期值(如"0 or 1"),也可以描述取值范围(如"in range of [1, 16]"),描述越精确,用户越容易快速修复;- 宏不改变返回值,调用后仍需显式
return错误码(如ge::GRAPH_FAILED),建议与OP_CHECK_IF等组合使用(OP_CHECK_IF定义见 include/op_common/log/log.h#L1082-L1088)。
仓库中的实际使用场景
在本仓库源码中,同族宏OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(上报 EZ0026)被大量用于 reduce 模板 Tiling 参数校验,例如 src/op_common/atvoss/reduce/reduce_tiling.cpp#L389-L415 对vectorCoreNum、ubSize、cacheLineSize、ubBlockSize、vRegSize等 Tiling 关键参数的合法性检查,以及同文件 src/op_common/atvoss/reduce/reduce_tiling.cpp#L972-L1020 中对ubSize、basicBlock的校验。其调用模式与本宏完全一致:
if (ubSize_ <= 0) { OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(context_->GetNodeName(), "ubSize", std::to_string(ubSize_), "larger than 0"); return false; }可见"if校验失败 → 调用日志宏 → 返回错误"是 opbase 内部统一的参数校验范式。其中entityName可以直接使用context_->GetNodeName()动态获取当前算子名,无需硬编码。
相关宏对比
该宏属于 log 接口家族的一员,完整的接口清单见 docs/zh/api/op_common/log/log.md。与参数值校验相关的三个宏对比如下:
| 宏 | 上报错误码 | 语义 | 适用场景 |
|---|---|---|---|
OP_LOGE_FOR_INVALID_VALUE | EZ0024 | 单参数值错误,带正确值 | 校验失败时能明确给出预期值/范围 |
OP_LOGE_FOR_INVALID_VALUE_WITH_REASON | EZ0026 | 单参数值错误,带失败原因 | 能解释为什么非法,例如"超出硬件支持上限" |
OP_LOGE_FOR_INVALID_VALUES_WITH_REASON | EZ0027 | 多参数值错误,带失败原因 | 多个参数同时校验、一起上报 |
各宏的详细说明分别见 docs/zh/api/op_common/log/OP_LOGE_FOR_INVALID_VALUE.md、docs/zh/api/op_common/log/OP_LOGE_FOR_INVALID_VALUE_WITH_REASON.md 与 docs/zh/api/op_common/log/OP_LOGE_FOR_INVALID_VALUES_WITH_REASON.md。
如果校验的是形状、维度、size、format、dtype 而非取值,应改用同族宏OP_LOGE_FOR_INVALID_SHAPE(EZ0008)、OP_LOGE_FOR_INVALID_SHAPEDIM(EZ0011)、OP_LOGE_FOR_INVALID_SHAPESIZE(EZ0014)、OP_LOGE_FOR_INVALID_FORMAT(EZ0017)、OP_LOGE_FOR_INVALID_DTYPE(EZ0019)等,各宏定义均位于 include/op_common/log/log.h,定义处注释中标注了对应的错误码。
使用建议
- 与错误码文档联动排查:当线上出现 EZ0024 错误码时,可直接对照 docs/zh/error_code/Operator-Errors/EZ0024-Invalid_Argument.md 中的报错示例与解决方法来定位问题——检查参数值是否正确。
- 保持参数语义一致:
entityName应使用对外可见的算子名或 aclnn 接口名(动态场景可用context_->GetNodeName()),不要使用内部类名,否则用户难以理解报错归属。 - 优先使用专用宏:凡是参数类校验失败,优先使用带 EZ 错误码的专用宏,而不是裸
OP_LOGE,以便错误码上报链路能够按类别聚合统计。 - 校验失败立即返回:宏只负责"记录与上报",真正的中断逻辑(
return)必须由调用方完成,避免只打日志不报错的"静默失败"。
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考