OpenMP:并行不做任何事情
OpenMP: parallel for doesn't do anything
我正在尝试在 OpenCV 中制作并行版本的 SIFT 算法。
特别是 sift.cpp
:
static void calcDescriptors(const std::vector<Mat>& gpyr, const std::vector<KeyPoint>& keypoints,
Mat& descriptors, int nOctaveLayers, int firstOctave )
{
...
#pragma omp parallel for
for( size_t i = 0; i < keypoints.size(); i++ )
{
...
calcSIFTDescriptor(img, ptf, angle, size*0.5f, d, n, descriptors.ptr<float>((int)i));
...
}
在四核机器上已经从 84ms
提速到 52ms
。规模不大,但加1行代码就已经很不错了。
无论如何,循环内的大部分计算都是由 calcSIFTDescriptor()
执行的,但无论如何它平均需要 100us
。因此,大部分计算时间是由 非常高 的 calcSIFTDescriptor()
调用次数(数千次)给出的。所以累积所有这些 100us
导致几个 ms
.
无论如何,我正在尝试优化 calcSIFTDescriptor()
性能。特别是代码在两个 for
和下面的代码之间平均 60us
:
for( k = 0; k < len; k++ )
{
float rbin = RBin[k], cbin = CBin[k];
float obin = (Ori[k] - ori)*bins_per_rad;
float mag = Mag[k]*W[k];
int r0 = cvFloor( rbin );
int c0 = cvFloor( cbin );
int o0 = cvFloor( obin );
rbin -= r0;
cbin -= c0;
obin -= o0;
if( o0 < 0 )
o0 += n;
if( o0 >= n )
o0 -= n;
// histogram update using tri-linear interpolation
float v_r1 = mag*rbin, v_r0 = mag - v_r1;
float v_rc11 = v_r1*cbin, v_rc10 = v_r1 - v_rc11;
float v_rc01 = v_r0*cbin, v_rc00 = v_r0 - v_rc01;
float v_rco111 = v_rc11*obin, v_rco110 = v_rc11 - v_rco111;
float v_rco101 = v_rc10*obin, v_rco100 = v_rc10 - v_rco101;
float v_rco011 = v_rc01*obin, v_rco010 = v_rc01 - v_rco011;
float v_rco001 = v_rc00*obin, v_rco000 = v_rc00 - v_rco001;
int idx = ((r0+1)*(d+2) + c0+1)*(n+2) + o0;
hist[idx] += v_rco000;
hist[idx+1] += v_rco001;
hist[idx+(n+2)] += v_rco010;
hist[idx+(n+3)] += v_rco011;
hist[idx+(d+2)*(n+2)] += v_rco100;
hist[idx+(d+2)*(n+2)+1] += v_rco101;
hist[idx+(d+3)*(n+2)] += v_rco110;
hist[idx+(d+3)*(n+2)+1] += v_rco111;
}
所以我尝试在它之前添加 #pragma omp parallel for private(k)
,奇怪的事情发生了:没有任何反应!!!
引入此 parallel for
使代码计算平均 53ms
(相对于之前的 52ms
)。我预计会出现以下一个或多个结果:
- 取
>52ms
的开销给了一个新的parallel for
- 取
<52ms
给定的增益parallel for
- 结果中存在某种不一致,因为如您所见,共享向量
hist
是同时更新的。这一切都没有发生:结果仍然正确,并且没有使用 atomic
或 critical
。
我是一个 OpenMP 新手,但从我的角度来看,这个内部 parllel for
就像被忽略了一样。为什么会这样?
注意:所有报告的时间都是相同输入 10.000 次的平均时间。
更新:
我试图删除第一个 parallel for
,将第一个留在 calcSIFTDescriptor
中,结果如我所料:由于缺少任何线程,已观察到 不一致 -安全机制。在更新 hist
之前引入 #pragma omp critical(dataupdate)
再次提供了一致性 但现在的表现很糟糕: 245ms
平均。
我认为这是因为 calcSIFTDescriptor
中 parallel for
给出的开销,不值得并行化 30us
.
但问题仍然存在:为什么第一个版本(有两个 parallel for
)没有产生任何变化 (在性能和一致性方面)?
我自己找到了答案:第二个(嵌套)parallel for
不会产生 任何 效果,原因如下:
OpenMP parallel regions can be nested inside each other. If nested
parallelism is disabled, then the new team created by a thread
encountering a parallel construct inside a parallel region consists
only of the encountering thread. If nested parallelism is enabled,
then the new team may consist of more than one thread.
因此,由于第一个 parallel for
占用了所有可能的线程,第二个将遇到的线程本身作为团队。所以什么也没有发生。
为自己干杯!
我正在尝试在 OpenCV 中制作并行版本的 SIFT 算法。
特别是 sift.cpp
:
static void calcDescriptors(const std::vector<Mat>& gpyr, const std::vector<KeyPoint>& keypoints,
Mat& descriptors, int nOctaveLayers, int firstOctave )
{
...
#pragma omp parallel for
for( size_t i = 0; i < keypoints.size(); i++ )
{
...
calcSIFTDescriptor(img, ptf, angle, size*0.5f, d, n, descriptors.ptr<float>((int)i));
...
}
在四核机器上已经从 84ms
提速到 52ms
。规模不大,但加1行代码就已经很不错了。
无论如何,循环内的大部分计算都是由 calcSIFTDescriptor()
执行的,但无论如何它平均需要 100us
。因此,大部分计算时间是由 非常高 的 calcSIFTDescriptor()
调用次数(数千次)给出的。所以累积所有这些 100us
导致几个 ms
.
无论如何,我正在尝试优化 calcSIFTDescriptor()
性能。特别是代码在两个 for
和下面的代码之间平均 60us
:
for( k = 0; k < len; k++ )
{
float rbin = RBin[k], cbin = CBin[k];
float obin = (Ori[k] - ori)*bins_per_rad;
float mag = Mag[k]*W[k];
int r0 = cvFloor( rbin );
int c0 = cvFloor( cbin );
int o0 = cvFloor( obin );
rbin -= r0;
cbin -= c0;
obin -= o0;
if( o0 < 0 )
o0 += n;
if( o0 >= n )
o0 -= n;
// histogram update using tri-linear interpolation
float v_r1 = mag*rbin, v_r0 = mag - v_r1;
float v_rc11 = v_r1*cbin, v_rc10 = v_r1 - v_rc11;
float v_rc01 = v_r0*cbin, v_rc00 = v_r0 - v_rc01;
float v_rco111 = v_rc11*obin, v_rco110 = v_rc11 - v_rco111;
float v_rco101 = v_rc10*obin, v_rco100 = v_rc10 - v_rco101;
float v_rco011 = v_rc01*obin, v_rco010 = v_rc01 - v_rco011;
float v_rco001 = v_rc00*obin, v_rco000 = v_rc00 - v_rco001;
int idx = ((r0+1)*(d+2) + c0+1)*(n+2) + o0;
hist[idx] += v_rco000;
hist[idx+1] += v_rco001;
hist[idx+(n+2)] += v_rco010;
hist[idx+(n+3)] += v_rco011;
hist[idx+(d+2)*(n+2)] += v_rco100;
hist[idx+(d+2)*(n+2)+1] += v_rco101;
hist[idx+(d+3)*(n+2)] += v_rco110;
hist[idx+(d+3)*(n+2)+1] += v_rco111;
}
所以我尝试在它之前添加 #pragma omp parallel for private(k)
,奇怪的事情发生了:没有任何反应!!!
引入此 parallel for
使代码计算平均 53ms
(相对于之前的 52ms
)。我预计会出现以下一个或多个结果:
- 取
>52ms
的开销给了一个新的parallel for
- 取
<52ms
给定的增益parallel for
- 结果中存在某种不一致,因为如您所见,共享向量
hist
是同时更新的。这一切都没有发生:结果仍然正确,并且没有使用atomic
或critical
。
我是一个 OpenMP 新手,但从我的角度来看,这个内部 parllel for
就像被忽略了一样。为什么会这样?
注意:所有报告的时间都是相同输入 10.000 次的平均时间。
更新:
我试图删除第一个 parallel for
,将第一个留在 calcSIFTDescriptor
中,结果如我所料:由于缺少任何线程,已观察到 不一致 -安全机制。在更新 hist
之前引入 #pragma omp critical(dataupdate)
再次提供了一致性 但现在的表现很糟糕: 245ms
平均。
我认为这是因为 calcSIFTDescriptor
中 parallel for
给出的开销,不值得并行化 30us
.
但问题仍然存在:为什么第一个版本(有两个 parallel for
)没有产生任何变化 (在性能和一致性方面)?
我自己找到了答案:第二个(嵌套)parallel for
不会产生 任何 效果,原因如下:
OpenMP parallel regions can be nested inside each other. If nested parallelism is disabled, then the new team created by a thread encountering a parallel construct inside a parallel region consists only of the encountering thread. If nested parallelism is enabled, then the new team may consist of more than one thread.
因此,由于第一个 parallel for
占用了所有可能的线程,第二个将遇到的线程本身作为团队。所以什么也没有发生。
为自己干杯!