5.9 KiB
5.9 KiB
DroneScrewServer 崩溃诊断日志增强
📊 崩溃日志分析结果
问题复现
- 运行时间: 约 19 分钟
- 处理帧数: 约 2100+ 帧
- 崩溃点: 处理第 1000 次检测帧后
- 退出码: 255 (EXCEPTION)
关键发现
-
没有 C++ 异常日志
- 已添加的 try-catch 没有捕获到任何异常
- 说明崩溃不是由可捕获的 C++ 异常引起
-
内存监控失败
[HEARTBEAT] rss=N/A vmPeak=N/A vmSize=N/A threads=N/A/proc/self/status读取失败- 无法通过心跳日志监控内存增长
-
检测线程挂起
- 最后日志:
[PUB-raw] #1000 frame=2244 - 5 秒后程序崩溃
- 检测线程在第 1000 帧后没有新的日志输出
- 最后日志:
怀疑根因
1. PNG 压缩导致卡死(最可能)
- 4096x3000 双目图像 PNG 压缩非常消耗 CPU
- 可能导致:
- 内存耗尽 - 压缩过程中申请大量临时内存
- 线程阻塞 - 压缩时间过长
- 超时死锁 - 与其他线程竞争资源
2. ZeroMQ 发布阻塞
- 发布 10MB+ 数据包可能导致阻塞
- 如果接收端处理不及时,发送端卡住
3. 算法库段错误
- Stub 算法库可能有内存访问错误
- 段错误无法被 try-catch 捕获
🔍 新增诊断日志
1. 检测线程详细日志
位置: DroneScrewServerPresenter.cpp::detectThreadFunc()
// 原始图像发布前后
LOG_DEBUG("[DETECT] frame #%d before rawImageReady emit, left=%llu right=%llu\n", ...);
emit rawImageReady(leftImg, rightImg);
LOG_DEBUG("[DETECT] frame #%d after rawImageReady emit\n", ...);
// 算法调用前后
LOG_DEBUG("[DETECT] frame #%d before algo Detect, left=%llu right=%llu\n", ...);
m_pAlgo->Detect(inLeft, inRight, result);
LOG_DEBUG("[DETECT] frame #%d after algo Detect, boxes=%zu\n", ...);
目的:精确定位崩溃发生在哪个步骤
2. PNG 编码日志
位置: DroneScrewZmqProtocol.cpp::publishRawImage()
LOG_DEBUG("[PUB-raw] enter frame=%llu left=%ux%u right=%ux%u\n", ...);
LOG_DEBUG("[PUB-raw] before PNG encode frame=%llu\n", ...);
// PNG 压缩
LOG_DEBUG("[PUB-raw] after PNG encode frame=%llu usePng=%d leftSize=%zu rightSize=%zu\n", ...);
目的:监控 PNG 压缩耗时和是否卡死
3. ZeroMQ 发布日志
位置: DroneScrewZmqProtocol.cpp::publishRawImage()
LOG_DEBUG("[PUB-raw] before ZMQ publish frame=%llu payloadSize=%d\n", ...);
const int ret = m_pZmqRawPublisher->Publish(...);
LOG_DEBUG("[PUB-raw] after ZMQ publish frame=%llu ret=%d\n", ...);
LOG_DEBUG("[PUB-raw] exit frame=%llu\n", ...);
目的:监控 ZeroMQ 发布是否阻塞
🧪 测试步骤
1. 重新编译部署
cd GrabBagPrj
qmake GrabBagPrj.pro
make
# 部署到设备
2. 运行测试(至少 30 分钟)
sudo systemctl restart dronescrewserver
sudo journalctl -u dronescrewserver.service -f
3. 分析新日志
场景 A: PNG 编码卡死
[DETECT] frame #1001 before rawImageReady emit, left=xxx right=xxx
[PUB-raw] enter frame=xxx
[PUB-raw] before PNG encode frame=xxx
(没有 after PNG encode 日志) → PNG 压缩时卡死
解决方案:
- 关闭 PNG 压缩,改用原始格式
- 降低图像分辨率
- 使用更快的压缩库
场景 B: ZeroMQ 发布阻塞
[PUB-raw] after PNG encode frame=xxx usePng=1 leftSize=xxx rightSize=xxx
[PUB-raw] before ZMQ publish frame=xxx payloadSize=xxx
(没有 after ZMQ publish 日志) → ZeroMQ 发布时阻塞
解决方案:
- 设置 ZeroMQ 发送超时
- 使用非阻塞模式
- 限制发送队列大小
场景 C: 算法库段错误
[DETECT] frame #1001 after rawImageReady emit
[DETECT] frame #1001 before algo Detect, left=xxx right=xxx
(没有 after algo Detect 日志) → 算法调用时崩溃
解决方案:
- 检查算法库实现
- 验证输入数据有效性
- 使用 gdb 或 coredump 定位
场景 D: emit detectionResult 阻塞
[DETECT] frame #1001 after algo Detect, boxes=0
(没有后续日志) → Qt 信号槽处理时阻塞
解决方案:
- 检查 slot 函数实现
- 确认信号槽连接方式(Qt::DirectConnection 可能阻塞)
📈 预期日志输出
正常流程(每 100 帧)
[DETECT] frame #100 before rawImageReady emit, left=xxx right=xxx
[PUB-raw] enter frame=xxx left=4096x3000 right=4096x3000
[PUB-raw] before PNG encode frame=xxx
[PUB-raw] after PNG encode frame=xxx usePng=1 leftSize=2000000 rightSize=2000000
[PUB-raw] before ZMQ publish frame=xxx payloadSize=4000088
[PUB-raw] after ZMQ publish frame=xxx ret=0
[PUB-raw] #100 frame=xxx compression=png left=4096x3000 right=4096x3000 payload=4000088
[PUB-raw] exit frame=xxx
[DETECT] frame #100 after rawImageReady emit
[DETECT] frame #100 before algo Detect, left=xxx right=xxx
[DETECT] frame #100 after algo Detect, boxes=0
[DETECT] frame #100 id=xxx rawPub=1 boxes=0
崩溃前的最后日志
查看崩溃前最后一条带有 [DETECT] 或 [PUB-raw] 的日志,就能知道卡在哪里。
🔧 后续优化建议
根据测试结果,可能需要:
-
关闭 PNG 压缩(如果 PNG 编码卡死)
- 修改
encodeImagePng直接返回 false - 使用原始格式传输
- 修改
-
异步发布(如果 ZeroMQ 阻塞)
- 将 ZeroMQ 发布放到独立线程
- 使用队列缓存待发布的数据
-
限制发布频率(如果性能不足)
- 每 N 帧发布一次原始图像
- 降低图像分辨率
-
修复算法库(如果算法崩溃)
- 联系算法提供方
- 增加输入数据验证
📝 修改文件清单
-
App/DroneScrewbolt/DroneScrewServer/DroneScrewServerPresenter.cppdetectThreadFunc()- 增加检测流程各阶段日志
-
App/DroneScrewbolt/DroneScrewServer/DroneScrewZmqProtocol.cpppublishRawImage()- 增加 PNG 编码和 ZeroMQ 发布日志
-
App/DroneScrewbolt/DIAGNOSTIC_LOG_ENHANCEMENT.md- 本文档