我正在编写一个使用 `tbb::parallel_pipeline' 处理视频流的应用程序。我的第一个过滤器包含两个重要的操作,一个必须在另一个之后立即发生。
我的测试表明,当我将 max_number_of_live_tokens
设置为 6(我拥有的过滤器的数量)时,两个操作之间的延迟在 3 到 20 毫秒之间,但当 时始终为 3 到 4 毫秒max_number_of_live_tokens
为 1。第一种情况下的抖动对于我的应用程序来说是 Not Acceptable ,但我需要允许多个 token 同时运行以利用并行性。
这是我的管道设置:
tbb::parallel_pipeline(6, //max_number_of_live_tokens
// 1st Filter
tbb::make_filter< void, shared_ptr<PipelinePacket_t> >(tbb::filter::serial_in_order,
[&](tbb::flow_control& fc)->shared_ptr<PipelinePacket_t>
{
shared_ptr<PipelinePacket_t> pPacket = grabFrame();
return pPacket;
}
)
&
... // 5 other filters that process the image - all 'serial_in_order'
);
这是我的 grabFrame()
函数:
shared_ptr<VisionPipeline::PipelinePacket_t> VisionPipeline::grabFrame() {
shared_ptr<PipelinePacket_t> pPacket(new PipelinePacket_t);
m_cap >> pPacket->frame; // Operation A (use opencv api to capture frame)
pPacket->motion.gyroDeg = m_imu.getGyroZDeg(); // Operation B (read a gyro value)
return pPacket;
}
我需要操作 A 和 B 尽可能彼此靠近(以便陀螺仪值反射(reflect)其在捕获帧时的值)。
我的猜测是,当多个 token 同时运行时发生的抖动是由其他过滤器的任务引起的,该任务与第一个过滤器在同一线程上运行并在 grabFrame()
执行时中断它。我已经翻阅了一些 TBB 文档,但找不到任何关于 parallel_pipeline
如何将过滤器分解为任务的信息,所以我不清楚 TBB 是否以某种方式分解了 grabFrame()
是否进入多个 TBB 任务。
这个假设是否正确?如果是这样,我如何告诉 tbb 不要用其他任务中断操作 A 和 B 之间的第一个过滤器?
最佳答案
OpenCV 在内部使用 TBB 进行各种操作。因此,如果这实际上与 TBB 相关,则不是因为您在 A 和 B 之间被打断,而是 OpenCV 本身正在与过滤器链的其余部分争夺优先级。虽然不太可能。
so it is unclear to me if TBB is somehow breaking up grabFrame() into multiple TBB tasks or not.
那是永远不会发生的。除非其中有部分通过 TBB 明确调度,否则它没有任何效果。 TBB 并没有神奇地将您的功能拆分为任务。
但这可能不是您唯一的问题。如果您的过滤器碰巧占用大量内存带宽,那么您很可能仅仅通过并发执行图像处理就大大减慢了实际捕获过程。
看起来您正在连续通过 5 个滤镜运行完整图像,对吗?全分辨率,不平铺?如果是这样,这些过滤器中的大部分可能不受 ALU 限制,而是受内存带宽限制,因为您也不在 CPU 缓存范围内。
如果你想并行,你必须在过滤阶段之间去掉对主内存的回写。做到这一点的唯一方法是开始在过滤器链的输入过滤器中平铺图像,或者编写一个自定义的一体式过滤器内核。如果您在该链中有具有空间依赖性的过滤器,这显然不像我说的那么容易,那么您必须在上层包含一些重叠。
max_number_of_live_tokens
那么其实是有实际意义的。这是飞行中的“瓷砖”数量。这主要不是为了将每个过滤阶段限制为只有一个并发执行(无论如何都不会发生),而是为了控制最大工作集大小。
例如如果您知道您的每个图 block 现在大小为 128kB,您知道每个过滤器(源和目标)涉及 2 个拷贝,并且您知道您有 2MB L3 缓存,那么您就会知道您可以负担得起在飞行中有 8 个 token 而不会溢出到主内存。如果您碰巧也有(至少)8 个 CPU 内核,这会产生理想的吞吐量,但即使您没有,至少您不会因超过缓存大小而面临成为瓶颈的风险。当然,您可以承受一些溢出到主内存(超过您计算的安全范围),但是您必须对系统执行深入的分析以查看您是否受到限制。
关于c++ - TBB 并行管道 : Filter Timing Inconsistent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61757572/