GrabBag/App/DroneScrewbolt/DIAGNOSTIC_LOG_ENHANCEMENT.md

207 lines
5.9 KiB
Markdown
Raw Normal View History

2026-06-26 17:55:15 +08:00
# DroneScrewServer 崩溃诊断日志增强
## 📊 崩溃日志分析结果
### 问题复现
- **运行时间**: 约 19 分钟
- **处理帧数**: 约 2100+ 帧
- **崩溃点**: 处理第 1000 次检测帧后
- **退出码**: 255 (EXCEPTION)
### 关键发现
1. **没有 C++ 异常日志**
- 已添加的 try-catch 没有捕获到任何异常
- 说明崩溃不是由可捕获的 C++ 异常引起
2. **内存监控失败**
```
[HEARTBEAT] rss=N/A vmPeak=N/A vmSize=N/A threads=N/A
```
- `/proc/self/status` 读取失败
- 无法通过心跳日志监控内存增长
3. **检测线程挂起**
- 最后日志:`[PUB-raw] #1000 frame=2244`
- 5 秒后程序崩溃
- 检测线程在第 1000 帧后没有新的日志输出
### 怀疑根因
#### 1. **PNG 压缩导致卡死**(最可能)
- 4096x3000 双目图像 PNG 压缩非常消耗 CPU
- 可能导致:
- **内存耗尽** - 压缩过程中申请大量临时内存
- **线程阻塞** - 压缩时间过长
- **超时死锁** - 与其他线程竞争资源
#### 2. **ZeroMQ 发布阻塞**
- 发布 10MB+ 数据包可能导致阻塞
- 如果接收端处理不及时,发送端卡住
#### 3. **算法库段错误**
- Stub 算法库可能有内存访问错误
- 段错误无法被 try-catch 捕获
## 🔍 新增诊断日志
### 1. 检测线程详细日志
**位置**: `DroneScrewServerPresenter.cpp::detectThreadFunc()`
```cpp
// 原始图像发布前后
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()`
```cpp
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()`
```cpp
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. 重新编译部署
```bash
cd GrabBagPrj
qmake GrabBagPrj.pro
make
# 部署到设备
```
### 2. 运行测试(至少 30 分钟)
```bash
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]` 的日志,就能知道卡在哪里。
## 🔧 后续优化建议
根据测试结果,可能需要:
1. **关闭 PNG 压缩**(如果 PNG 编码卡死)
- 修改 `encodeImagePng` 直接返回 false
- 使用原始格式传输
2. **异步发布**(如果 ZeroMQ 阻塞)
- 将 ZeroMQ 发布放到独立线程
- 使用队列缓存待发布的数据
3. **限制发布频率**(如果性能不足)
- 每 N 帧发布一次原始图像
- 降低图像分辨率
4. **修复算法库**(如果算法崩溃)
- 联系算法提供方
- 增加输入数据验证
## 📝 修改文件清单
1. `App/DroneScrewbolt/DroneScrewServer/DroneScrewServerPresenter.cpp`
- `detectThreadFunc()` - 增加检测流程各阶段日志
2. `App/DroneScrewbolt/DroneScrewServer/DroneScrewZmqProtocol.cpp`
- `publishRawImage()` - 增加 PNG 编码和 ZeroMQ 发布日志
3. `App/DroneScrewbolt/DIAGNOSTIC_LOG_ENHANCEMENT.md` - 本文档