TBB并行管道:过滤器时序不一致

时间:2020-05-12 17:01:14

标签: c++ multithreading tbb

我正在编写一个使用`tbb :: parallel_pipeline'处理视频流的应用程序。我的第一个过滤器包含两个重要的操作,一个必须紧接另一个执行。

我的测试表明,当我将max_number_of_live_tokens设置为6(我拥有的过滤器数量)时,两次操作之间的延迟介于3到20毫秒之间,而当max_number_of_live_tokens为2时,则始终保持3到4毫秒1.第一种情况下的抖动对于我的应用程序是不可接受的,但是我需要允许多个令牌同时运行以利用并行性。

这是我的管道设置:

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尽可能彼此靠近(以便陀螺仪值反映捕获帧时的值)。

我的猜测是,在同时运行多个令牌时发生的抖动是由与第一个过滤器在同一线程上运行并在grabFrame()执行时中断它的其他过滤器的任务引起的。我已经浏览了一些TBB文档,但找不到关于parallel_pipeline如何将过滤器分解为任务的任何信息,因此我不清楚TBB是否以某种方式将grabFrame()分解为多个TBB任务。

这个假设正确吗?如果是这样,我如何告诉tbb不要通过其他任务中断操作A和操作B之间的第一个过滤器?

1 个答案:

答案 0 :(得分:5)

OpenCV内部本身正在使用TBB进行各种操作。因此,如果这实际上与TBB有关,则不是因为您在A和B之间被打扰,而是OpenCV本身正在与其余过滤器链争夺优先权。虽然不太可能。

所以我不清楚TBB是否以某种方式将handleFrame()分解为多个TBB任务。

那是永远不会发生的。除非其中有部分通过TBB明确调度,否则它没有任何作用。 TBB并不是神奇地将您的功能拆分为任务。

但这可能甚至不是您唯一的问题。如果您的过滤器恰好占用了很大的内存带宽,则可能是由于同时执行图像处理而大大降低了实际捕获过程的速度。

好像您正在通过5个过滤器连续运行完整图像,对吗?全分辨率,不是平铺?如果是这样,那么这些过滤器中的大多数可能不受ALU的限制,而是受内存带宽的限制,因为您也不是处于CPU缓存范围之内。

如果希望并行处理,则必须在过滤器阶段之间消除对主存储器的回写。唯一的方法是要么在过滤器链的输入过滤器中平铺图像,要么编写自定义的多合一过滤器内核。如果您在该链中具有空间相关性的过滤器,显然这不像我说的那么简单,那么您必须在上层阶段包括一些重叠。

max_number_of_live_tokens实际上具有真正的意义。这是飞行中的“平铺”数量。这样做的主要目的不是将每个筛选器阶段限制为仅一个并发执行(无论如何都不会发生),而是要控制最大工作集大小。

例如如果您知道每个磁贴现在的大小为128kB,则知道每个过滤器(源和目标)涉及2个副本,并且您知道有2MB的L3缓存,那么您就可以负担得起在飞行中有8个令牌,不会溢出到主内存中。如果您还恰好具有(至少)8个CPU内核,那么这将产生理想的吞吐量,但是即使您没有,也至少不会冒超出缓存大小的风险。当然,您可以对主内存进行一些溢出(过去算是安全的),但是随后您必须对系统进行深入的分析,以查看是否受到限制。

相关问题