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