207 lines
5.9 KiB
Markdown
207 lines
5.9 KiB
Markdown
# 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` - 本文档
|