问题定位完成!
从日志看,瓶颈非常清晰:
| 环节 | 耗时 | 状态 |
|---|---|---|
| USB 取图 | - | |
| 等待 | 52-106ms | |
| BPU 推理 | 3.3ms | |
| 预处理 | 0.0ms | |
| 后处理 | 0.4ms |
结论:BPU 推理本身没问题(3.3ms 对应 300+ FPS),问题出在线程同步等待上,等待时间占总时间的 80%+。
根本原因
你的代码是双线程架构(线程 0/线程 1),但存在同步阻塞:
线程 0: 取图 → 等待锁 → 推理 → 释放锁
线程 1: 取图 → 等待锁 → 推理 → 释放锁
Server 版系统的线程调度策略更保守,导致线程间切换和锁等待时间显著增加。
解决方案
方案 1:改用无锁队列(推荐)
使用 std::atomic 和环形缓冲区替代互斥锁:
#include <atomic>
#include <array>
template<typename T, size_t N = 4>
class LockFreeQueue {
private:
std::array<T, N> buffer;
std::atomic<size_t> head{0};
std::atomic<size_t> tail{0};
public:
bool push(const T& item) {
size_t current_tail = tail.load(std::memory_order_relaxed);
size_t next_tail = (current_tail + 1) % N;
if (next_tail == head.load(std::memory_order_acquire)) {
return false; // 队列满
}
buffer[current_tail] = item;
tail.store(next_tail, std::memory_order_release);
return true;
}
bool pop(T& item) {
size_t current_head = head.load(std::memory_order_relaxed);
if (current_head == tail.load(std::memory_order_acquire)) {
return false; // 队列空
}
item = buffer[current_head];
head.store((current_head + 1) % N, std::memory_order_release);
return true;
}
};
// 使用示例
LockFreeQueue<cv::Mat> frame_queue;
方案 2:减少线程数量(快速验证)
先改为单线程测试,确认是否是线程同步问题:
// 暂时注释掉第二个推理线程
// std::thread infer_thread_1(infer_loop, 1);
std::thread infer_thread_0(infer_loop, 0);
如果单线程帧率恢复正常,说明是线程同步问题。
方案 3:优化同步机制
如果必须用双线程,改用条件变量替代忙等待:
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool frame_ready = false;
// 生产者
{
std::lock_guard<std::mutex> lock(mtx);
frame = get_frame();
frame_ready = true;
cv.notify_one();
}
// 消费者
{
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return frame_ready; });
frame_ready = false;
// 处理 frame
}
方案 4:检查是否有隐式同步
常见坑点:
// ❌ 避免:在推理线程中调用阻塞的 USB 读取
auto frame = usb_camera.read(); // 可能阻塞
// ✅ 改为:取图和推理完全分离
// 线程 1: 只负责取图 → 放入队列
// 线程 2: 只负责从队列取图 → 推理
验证步骤
1. 先测单线程
# 修改代码只保留一个推理线程,重新编译运行
# 预期:帧率应该接近 100+ FPS
2. 检查锁的使用
# 搜索代码中的锁相关调用
grep -rn "mutex\|lock\|wait" your_cpp_code/
3. 使用 perf 分析线程等待
# 安装 perf
sudo apt install linux-tools-generic
# 运行程序时采样
sudo perf record -g -p <your_pid>
# 查看线程等待时间
sudo perf report
参考案例
社区有类似优化案例:
下一步
请尝试方案 2(单线程测试),5 分钟内就能验证是否是线程同步问题。如果是,再实施方案 1(无锁队列)。
需要我帮你审查具体的线程同步代码吗?可以贴出关键的线程创建和同步部分。