背景
客户在OS侧跑GPU压力测试,发现BMC这边的GPU温度不再更新:OS侧看GPU已经90多度了,BMC这边显示的还是40度。
定位过程
在BMC后台通过tracechip查看GPU芯片访问数据,发现没有任何打印;
查看log文件,发现如下打印:
环境上8张GPU,其中七张数据不再更新,与这里异常退出的线程数匹配。这里打印是log接口接收了预期之外的参数?没有生成core_dump文件,也没办法从这个打印中获取有用的定位信息,请问应该如何继续定位?
背景
客户在OS侧跑GPU压力测试,发现BMC这边的GPU温度不再更新:OS侧看GPU已经90多度了,BMC这边显示的还是40度。
定位过程
在BMC后台通过tracechip查看GPU芯片访问数据,发现没有任何打印;
查看log文件,发现如下打印:
环境上8张GPU,其中七张数据不再更新,与这里异常退出的线程数匹配。这里打印是log接口接收了预期之外的参数?没有生成core_dump文件,也没办法从这个打印中获取有用的定位信息,请问应该如何继续定位?
答案内容由AI生成,仅供参考:
| 项目 | 分析结果 |
|---|---|
| 根本原因 | 极可能是 GPU 温度读取返回 nil,而日志模块未做防空处理,导致 format_msg 报错,协程异常退出 |
| 传播机制 | 多个 GPU 监控线程同时失败 → 所有温度更新中断 |
| 触发条件 | OS 层 GPU 高负载 → 可能引起 SMBus 通信异常 → 读取失败 → 返回 nil |
| 责任组件 | general_hardware 中 GPU 监控逻辑缺乏异常容忍机制 |
| 解决方案方向 |
nil 判断;pcall 包裹采集逻辑;general_hardware 组件中 GPU 监控线程异常中断问题的分析与定位建议根据您提供的背景信息和日志内容,该问题是 GPU 温度监控数据未更新,具体表现为:
general_hardware 组件下 Lua 协程异常退出记录;tracechip 无 GPU 芯片访问数据,说明获取硬件状态的线程已停止运行。以下依据所提供的知识库信息,结合问题现象进行综合分析并提出进一步定位建议。
| 现象 | 描述 |
|---|---|
| 温度数据停滞 | BMC 显示的 GPU 温度不再随实际变化,出现严重偏差 |
| 协程异常退出 | 多个 co[thread: ...] abnormal exit 错误,集中于 app_preloader.lua |
| 错误信息一致 | 全部报错均为:bad argument #2 to 'format_msg' (number expected, got nil) |
| 线程数量匹配 | 异常退出线程数 ≈ 7,与失去监控的 GPU 数量(7/8)一致 |
| 无 core dump | 未生成核心转储文件,难以回溯调用栈 |
| 无芯片访问日志 | tracechip 无输出,表明监控线程已终止或阻塞 |
general_hardware 是 GPU 监控的核心组件从知识库中的“搜索结果”可知:
general_hardware负责 GPU 卡的电源、温度、状态监控。- 非 NVIDIA GPU 若需带外管理,需修改
general_hardware组件代码。- 新增 NVIDIA GPU 适配只需添加配置文件(如
Tesla_T4.lua)。
这表明 general_hardware 是管理 GPU 状态采集的主要服务,其内部通过 Lua 协程实现定时采集逻辑。
format_msg 类型错误报错详情为:
./opt/bmc/libmc/lualib/mc/logging.lua:253: bad argument #2 to 'format_msg' (number expected, got nil)
说明在调用日志格式化函数时,本应传入一个 数字类型的值(如温度、电压等),但实际传入了 nil。
推测流程:
nil;nil 做保护处理,直接传入 format_msg;
此为典型的 未做空值防御的日志打印缺陷,常见于异步监控线程。
bmc.kepler.Systems.Processor.GPU.Status/bmc/kepler/Systems/${SystemId}/Processors/GPU/${Id}smbus_postbox 每 2 秒轮询一次{
"entity": "bmc.kepler.Systems.Processor.GPU.Status",
"description": "...使用 smbus_postbox 每 2 秒获取一次状态数据"
}
PrimaryGPUTemperatureCelsiusDouble,只读文档 Chunk “2” 提供完整属性列表:
| 属性名 | 类型 | 描述 |
|---|---|---|
PrimaryGPUTemperatureCelsius |
Double |
主处理器温度(摄氏度) |
该字段正是我们期望更新的温度值。若采集过程某环节出错(如 SMBus 通信失败),可能导致读取为
nil。
| 实体 | 描述 |
|---|---|
GPU Temperature Reading Failure |
当无法读取 GPU 温度时触发的告警 |
Temperature Fault |
温度读取失败事件,由 contbin_H10L5 模块检测 |
contbin_H10L5 |
负责进/出风口、PCH、CPU、RAID 卡、PCIe Switch 的温度读取失败检测 |
contbin_H20L5 |
明确包含 GPU 卡温度读取失败 检测(序号 9) |
系统具备 GPU 温度读取失败的硬件层面检测能力。
但当前并未看到相关告警产生,可能原因:
0 或旧缓存值;| 可能原因 | 支持证据 |
|---|---|
GPU 温度读取返回 nil,日志模块未防呆 |
日志错误明确指向 format_msg(number expected, got nil) |
| Lua 协程无异常捕获机制(pcall 缺失) | 多个协程同时崩溃,说明无容错处理 |
| SMBus/I²C 通信因高负载失败 | OS 进行 GPU 压力测试 → PCIe 链路繁忙 → 带外通信受影响 |
| VRD 或电源波动影响 BMC 通信 | 高功耗状态下板级电压不稳定,影响传感器通信 |
| 协程资源泄露或调度异常 | 协程频繁退出可能导致调度器压力增大,加剧雪崩效应 |
尽管当前没有生成 core dump,但仍可通过以下方式深入排查:
format_msg 的参数来源检查 general_hardware 中调用日志的地方,尤其是与 GPU 相关的传感器读取后写日志的代码段。
例如,在获取温度后可能有如下伪代码:
local temp = read_gpu_temp(sensor_id)
log.info("GPU%d Temp: %.2f°C", id, temp) -- ❌ 若 temp 为 nil,此处将报错
建议修复方式:
local temp = read_gpu_temp(sensor_id) or 0.0
if not temp then
log.warn("Failed to read GPU%d temperature, got nil", id)
else
log.info("GPU%d Temp: %.2f°C", id, temp)
end
pcall 或 xpcall)确保每个监控协程都包裹在保护模式中,避免因单点错误导致线程退出。
skynet.fork(function()
while true do
local ok, err = pcall(collect_gpu_metrics, gpu_id)
if not ok then
log.error("GPU %d monitor thread failed: %s", gpu_id, err)
-- 可重启采集或上报事件
end
skynet.sleep(200) -- 每2秒一次
end
end)
推荐:所有硬件采集线程均应加
pcall保护。
smbus_postbox 通信是否超时或失败使用命令行工具手动测试:
# 查看 smbus 是否能正常读取 GPU 设备(假设地址为0x30)
i2cget -f -y <bus_num> 0x30
或在 Lua 脚本中插入调试日志:
local data = smbus_read(addr)
if not data then
log.warn("SMBus read failed for GPU at addr 0x%X", addr)
return nil
end
参考 Scanner_GPUTemp.Status 字段设计:
0: 正常1: 异常(读取失败)建议为每个 GPU 创建一个状态标记,在读取失败时持续上报“Sensor Failed”事件,并触发 GPU Temperature Reading Failure 告警。
i2cdetect 检查总线设备是否存在;i2c-bus 使用情况;Hot Plug Anomaly虽然本例是 OS 内部压力测试,但极端情况下 GPU 运行状态剧烈变化,可能导致 BMC 认为设备“热插拔”,进入异常状态机。
查看是否有如下现象:
Presence 信号抖动;重启 BMC 或刷写修复版本
(用户已在日志中尝试此方法,确认有效)
降低 GPU 压力测试负载
验证是否为高功耗引发的通信异常边界问题
限制每个 GPU 监控线程独立运行
防止某一 GPU 异常影响其他 GPU 的监控
| 项目 | 分析结果 |
|---|---|
| 根本原因 | 极可能是 GPU 温度读取返回 nil,而日志模块未做防空处理,导致 format_msg 报错,协程异常退出 |
| 传播机制 | 多个 GPU 监控线程同时失败 → 所有温度更新中断 |
| 触发条件 | OS 层 GPU 高负载 → 可能引起 SMBus 通信异常 → 读取失败 → 返回 nil |
| 责任组件 | general_hardware 中 GPU 监控逻辑缺乏异常容忍机制 |
| 解决方案方向 |
nil 判断;pcall 包裹采集逻辑;
提交 Issue 至 general_hardware 组件维护团队
[Bug] GPU monitor thread crash due to nil value in loggingpcall 和防 nil 处理
建议增加运行时健康检查
推动标准化采集框架建设
最后提示:此问题虽表象为“温度不更新”,实则暴露了 BMC 软件在 异常处理机制上的薄弱环节,建议作为典型案例纳入 DFX(Design for X)改进项,提升系统鲁棒性。
可以使用这个命令来看compute组件的日志,看看是否有报错
mdbctl
attach general_hardware
dloglevel debug
dlogtype local
因为是客户环境,且该问题是偶现问题,客户持续压测大概一周多两周能复现一次,我们没有办法直接上去调试。
从log看似乎是log:xxx接口入参为nil导致的?
我们在排查是不是有些异常情况没有处理好导致传入了nil值。
是否能提供下完整的日志?仅从截图的部分难以分析报错的点大致是在哪块代码附近
感谢支持,一键收集如下:
dump_info.zip (6.8 MB)