GrabBag/App/DroneScrewbolt/DIAGNOSTIC_LOG_ENHANCEMENT.md
2026-06-26 17:55:15 +08:00

207 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` - 本文档