如何有效地合并来自 TBB 线程的结果
How to efficiently merge results from TBB threads
我正在研究对象的视觉检测,我使用 Opencv 的级联分类器。它运作良好,但对我来说太慢了。我使用 Vtune 获取所有热点,我发现在 140 秒的执行时间(CPU 时间,实际约为 60 秒),有 123 秒的开销时间。 cvCascadeClassifier 使用 TBB 速度更快,但似乎所有 TBB 线程等待的时间都超过了应有的时间。
有代码:
void operator()(const Range& range) const
{
Ptr<FeatureEvaluator> evaluator = classifier->featureEvaluator->clone();
Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), cvRound(classifier->data.origWinSize.height * scalingFactor));
int y1 = range.start * stripSize;
int y2 = min(range.end * stripSize, processingRectSize.height);
for( int y = y1; y < y2; y += yStep )
{
for( int x = 0; x < processingRectSize.width; x += yStep )
{
if ( (!mask.empty()) && (mask.at<uchar>(Point(x,y))==0)) {
continue;
}
double gypWeight;
int result = classifier->runAt(evaluator, Point(x, y), gypWeight);
#if defined (LOG_CASCADE_STATISTIC)
logger.setPoint(Point(x, y), result);
#endif
if( rejectLevels )
{
if( result == 1 )
result = -(int)classifier->data.stages.size();
if( classifier->data.stages.size() + result < 4 )
{
mtx->lock();
rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), winSize.width, winSize.height));
rejectLevels->push_back(-result);
levelWeights->push_back(gypWeight);
mtx->unlock();
}
}
else if( result > 0 )
{
mtx->lock();
rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor),
winSize.width, winSize.height));
mtx->unlock();
}
if( result == 0 )
x += yStep;
}
}
}
我认为问题出在结果的合并上。互斥锁过多,线程需要等待的次数过多。这部分代码被调用了很多时间,线程很少(在我的例子中是 3 个)。我尝试为每个线程创建本地向量(我没有尝试使用列表,因为 Rect 类型非常小)并在最后合并所有这些向量。该解决方案减少了开销时间(在 CPU 时间的 140 秒上少于 10 秒)但我想要更多。
这是我的问题:
有没有办法有效地合并来自不同 TBB 线程的结果(也就是减少开销时间)?
编辑:
就我而言,我在链接过程中发现了一个错误。创建本地向量并在末尾使用互斥量合并效果很好。现在,我在 140 秒的 CPU 时间上有 0.1 秒的开销。这是一个特殊情况,只有很少的元素非常小。安东的回答似乎更笼统
您可以尝试使用TBB concurrent_vector。
grow_by 接口可以帮助您减少插入的开销:您可以在堆栈上创建小的(例如 16 个元素)数组并将其中的所有元素合并到 concurrent_vector.
您还可以将 push_back
替换为 emplace_back
,使用由 concurrent_vector 驱动的 C++11。
还有另一种可能更有效的组合结果的方法。使用 combinable or "ets" 类 以便为每个 thread/task 收集 .local()
结果(不要直接使用线程),然后使用 .combine()
[= 合并结果13=]
我正在研究对象的视觉检测,我使用 Opencv 的级联分类器。它运作良好,但对我来说太慢了。我使用 Vtune 获取所有热点,我发现在 140 秒的执行时间(CPU 时间,实际约为 60 秒),有 123 秒的开销时间。 cvCascadeClassifier 使用 TBB 速度更快,但似乎所有 TBB 线程等待的时间都超过了应有的时间。 有代码:
void operator()(const Range& range) const
{
Ptr<FeatureEvaluator> evaluator = classifier->featureEvaluator->clone();
Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), cvRound(classifier->data.origWinSize.height * scalingFactor));
int y1 = range.start * stripSize;
int y2 = min(range.end * stripSize, processingRectSize.height);
for( int y = y1; y < y2; y += yStep )
{
for( int x = 0; x < processingRectSize.width; x += yStep )
{
if ( (!mask.empty()) && (mask.at<uchar>(Point(x,y))==0)) {
continue;
}
double gypWeight;
int result = classifier->runAt(evaluator, Point(x, y), gypWeight);
#if defined (LOG_CASCADE_STATISTIC)
logger.setPoint(Point(x, y), result);
#endif
if( rejectLevels )
{
if( result == 1 )
result = -(int)classifier->data.stages.size();
if( classifier->data.stages.size() + result < 4 )
{
mtx->lock();
rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), winSize.width, winSize.height));
rejectLevels->push_back(-result);
levelWeights->push_back(gypWeight);
mtx->unlock();
}
}
else if( result > 0 )
{
mtx->lock();
rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor),
winSize.width, winSize.height));
mtx->unlock();
}
if( result == 0 )
x += yStep;
}
}
}
我认为问题出在结果的合并上。互斥锁过多,线程需要等待的次数过多。这部分代码被调用了很多时间,线程很少(在我的例子中是 3 个)。我尝试为每个线程创建本地向量(我没有尝试使用列表,因为 Rect 类型非常小)并在最后合并所有这些向量。该解决方案减少了开销时间(在 CPU 时间的 140 秒上少于 10 秒)但我想要更多。
这是我的问题: 有没有办法有效地合并来自不同 TBB 线程的结果(也就是减少开销时间)?
编辑: 就我而言,我在链接过程中发现了一个错误。创建本地向量并在末尾使用互斥量合并效果很好。现在,我在 140 秒的 CPU 时间上有 0.1 秒的开销。这是一个特殊情况,只有很少的元素非常小。安东的回答似乎更笼统
您可以尝试使用TBB concurrent_vector。 grow_by 接口可以帮助您减少插入的开销:您可以在堆栈上创建小的(例如 16 个元素)数组并将其中的所有元素合并到 concurrent_vector.
您还可以将 push_back
替换为 emplace_back
,使用由 concurrent_vector 驱动的 C++11。
还有另一种可能更有效的组合结果的方法。使用 combinable or "ets" 类 以便为每个 thread/task 收集 .local()
结果(不要直接使用线程),然后使用 .combine()
[= 合并结果13=]