CANN opbase 算子日志接口 OP_LOGI 使用指南:INFO 级别日志打印的原理与实战
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
导读
OP_LOGI是 CANN opbase(算子库基础框架库)为算子开发者提供的 INFO 级别日志打印宏,用于在算子实现、tiling 逻辑或公共工具函数中输出关键流程信息,配合日志级别过滤机制实现可观测性。本文以 OP_LOGI.md 为骨架,结合 op_log.h 的宏定义与src/nnopbase下的底层实现,讲解该接口的函数原型、参数语义、调用示例、日志级别体系与底层调用链,帮助你正确地在算子代码中埋点打印 INFO 日志并理解其输出行为。
功能说明
OP_LOGI用于打印算子 INFO 级别日志。INFO 级别日志适合记录算子执行过程中的关键状态信息(例如输入输出的 shape、分配的设备扩展信息大小、节点 kernelId 更新等),用于在正常运行流程中提供可追踪的运行轨迹,而不会像 DEBUG 级别日志那样频繁输出、影响性能。
从实现上看,OP_LOGI在 op_log.h 中被定义为宏,非 Android 平台下展开为:
#define OP_LOGI(...) D_OP_LOGI(GetOpName().c_str(), __VA_ARGS__)其中D_OP_LOGI进一步调用OpLogSub(OP_ID, OP_LOG_INFO, opname, fmt, ...),OP_ID为 63(NNOP 子模块),OP_LOG_INFO的值为 1。可见OP_LOGI本质是"NNOP 子模块 + INFO 级别"的日志入口。
函数原型
OP_LOGI(opName, ...)OP_LOGI是可变参数宏:第一个参数opName用于标识日志主体,其余参数为 printf 风格的可变参数(格式化字符串与对应变量),遵循 C 标准库printf的格式化语法(如%d、%ld、%s等)。
参数说明
| 参数名 | 输入/输出 | 说明 |
|---|---|---|
| opName | 输入 | 待打印对象,可以是算子名,表示打印算子信息;也可以是某个函数名,表示打印函数内相关信息。支持const char*或std::string类型。 |
关于opName的进一步说明:
- 传算子名时,日志会带上算子维度的上下文信息,便于在整条执行链路中定位到具体算子;
- 传函数名时,日志表示该函数内部的信息,例如广播维度检查等工具函数;
- 由于宏内部会调用
GetOpName()获取当前算子上下文(见 op_log.h),实际输出中会自动拼接OpName:[...]前缀,opName本身会被作为日志格式前缀的一部分参与输出。
返回值说明
无返回值。
约束说明
- 无参数类型、调用位置的硬性约束,可在算子 host 侧实现、tiling 函数或公共工具函数中自由使用;
- 需包含日志头文件
opdev/op_log.h(通过#include "opdev/op_log.h"引入); - 日志是否真正输出受运行时日志级别控制:只有当前配置的日志级别允许 INFO(即级别过滤通过)时才会落盘,详见下文"级别过滤与底层调用链"。
调用示例
以下示例来自 OP_LOGI.md,展示在广播维度检查函数中使用OP_LOGI打印无法广播的维度信息,仅供参考,不支持直接拷贝运行:
bool BroadcastDim(int64_t& dim1, const int64_t dim2) { if ((dim1 != 1) && (dim2 != 1)) { OP_LOGI("BroadcastDim", "%ld and %ld cannot broadcast!", dim1, dim2); return false; } return true; }在该示例中:
"BroadcastDim"作为opName,标识日志来自BroadcastDim函数;- 格式化串
"%ld and %ld cannot broadcast!"与dim1、dim2两个int64_t变量一一对应,输出类似BroadcastDim: 1024 and 512 cannot broadcast!(实际还会带模块、线程、行列号等前缀,见下节)。
日志级别体系与同级接口
OP_LOGI属于 opbase 日志宏家族中的 INFO 级别一员。在 op_log.h 中定义了完整的级别常量:
#define OP_LOG_DEBUG 0 #define OP_LOG_INFO 1 #define OP_LOG_WARN 2 #define OP_LOG_ERROR 3 #define OP_LOG_EVENT 0x10对应关系如下:
| 宏 | 级别值 | 适用场景 |
|---|---|---|
OP_LOGD | 0(DEBUG) | 调试期详细过程信息 |
OP_LOGI | 1(INFO) | 正常运行的关键状态信息 |
OP_LOGW | 2(WARN) | 可疑但可继续执行的情况 |
OP_LOGE | 3(ERROR) | 错误信息,且会联动错误码上报(见 op_log.h) |
OP_EVENT | 0x10(EVENT) | 事件类日志 |
日志宏完整清单见 log.md。选择建议:能用OP_LOGI表达"正常流程中的关键节点"就不要降级用OP_LOGD刷屏,也不要用OP_LOGE打正常提示;OP_LOGE会额外触发错误码上报(REPORT_ERROR_MESSAGE),成本更高,仅用于真正的错误场景。
底层实现:级别过滤与调用链
OP_LOGI的底层链路在 op_error_manager.cpp 与 op_log.h 中可以看到完整实现:
#define DOplogSub(moduleId, submodule, level, fmt, ...) \ do { \ if (unlikely(CheckLogLevelInner(moduleId, level) == 1)) { \ DlogRecordInner(moduleId, level, "[%s:%d][%s]" fmt, \ GetFileName(__FILE__), __LINE__, submodule, \ ##__VA_ARGS__); \ } \ } while (false)关键点如下:
- 先查级别再打印:
DOplogSub首先调用CheckLogLevelInner(moduleId, level)判断当前模块(NNOP/OP_ID=63)在该级别下是否允许输出,只有允许时才继续拼接日志并调用DlogRecordInner。这样避免了在日志级别被过滤时仍然执行耗时的格式化操作,属于性能优化设计(头文件注释明确说明"call CheckLogLevelInner in advance to optimize performance")。 - 自动补充上下文:日志会携带
[文件名:行号][子模块]前缀,其中文件名通过GetFileName(__FILE__)只保留 basename,行号为宏展开处__LINE__;opName前缀则由GetOpName()从算子执行上下文动态获取(见 op_log.h,其实现op::internal::GetLogApiInfo()位于 op_dfx.cpp)。 - 最终落盘:
DlogRecordInner封装DlogVaList(moduleId, level, fmt, args)将日志交给 dlog 框架(见 op_error_manager.cpp)。
此外,在单元测试/系统测试构建(NNOPBASE_UT/NNOPBASE_ST)下,OP_LOGI会被重定向为OP_TEST_LOG,直接通过fprintf(stdout, ...)输出并带线程号(OpLog::GetTid(),基于syscall(__NR_gettid)获取,见 op_log.h),便于测试工程直接观察日志。相关测试可参考 test_log.cpp,其中对OP_LOGI的实际调用验证了该宏在测试环境下的可用性。
在 AICPU 场景下的对应实现
如果算子运行在 AICPU 侧,日志输出走的是另一套自定义日志通道。aicpu命名空间提供了DumpCustomLog与CustLogInfo等接口(见 cust_op_log.cc 与 cust_dlog_record.cc),其 INFO 级别(DLOG_INFO)日志最终通过CustCpuKernelUtils::CustLogInfo写入工作空间缓冲区,并自动补齐[INFO] CUST_AICPU_OP [时间戳]前缀与换行符,单条消息长度上限为 1024 字节(见 cust_op_log.cc)。该机制与 host 侧的OP_LOGI相互独立,开发者可按运行环境选择对应打印通道。
使用建议与排查要点
- 格式化串与参数必须匹配:
OP_LOGI的参数语义与printf一致,%ld对应int64_t、%s对应const char*,类型不匹配可能导致日志内容错乱; - 日志输出受环境级别控制:若设置日志级别高于 INFO(例如 ERROR),
OP_LOGI会被CheckLogLevelInner过滤而不输出,排查时可通过调整日志级别或确认NNOP子模块级别配置来验证; - 测试构建输出到 stdout:在
NNOPBASE_UT/NNOPBASE_ST构建下日志直接打印到终端,便于调试;正式构建下则走 dlog 框架统一落盘; - INFO 日志不宜过度埋点:INFO 介于 DEBUG 与 WARN 之间,建议只记录对问题定位有直接价值的关键路径信息,避免高频打印影响性能。
相关文档
- 日志宏总览:log.md
- 警告级别日志:OP_LOGW.md
- 调试级别日志:OP_LOGD.md
- 错误级别日志:OP_LOGE.md
- 日志宏头文件定义:op_log.h
- 底层日志实现:op_error_manager.cpp
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考