OpenMP:并行不做任何事情

时间:2016-07-05 10:34:36

标签: c++ opencv parallel-processing openmp

我试图在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)。我希望得到以下一个或多个结果:

  1. 根据新>52ms
  2. 的开销给出parallel for
  3. 根据<52ms
  4. 获得的收益给出parallel for
  5. 结果中存在某种不一致性,因为您可以看到共享向量hist同时更新。没有发生这种情况:结果仍然正确,并且未使用atomiccritical
  6. 我是一个OpenMP新手,但是从我看来就像这个内部parllel for被忽略了。为什么会这样?

    注意:所有报告的时间是相同输入的平均时间为10.000次。

    更新 我尝试删除第一个parallel for,将calcSIFTDescriptor中的一个删除,并且发生的事情是我期待的:由于缺少任何线程安全机制,已经观察到不一致 。在更新#pragma omp critical(dataupdate)之前引入hist会再次提供一致性但现在表现非常糟糕: 245ms平均。

    我认为这是因为parallel for中的calcSIFTDescriptor所带来的开销,并不值得并行化30us

    但问题仍然存在:为什么第一个版本(有两个parallel for)没有产生任何更改(性能和一致性) )?

1 个答案:

答案 0 :(得分:1)

我自己找到了答案:第二个(嵌套的)parallel for因为这里描述的原因没有任何效果:

  

OpenMP并行区域可以互相嵌套。如果嵌套   并行性被禁用,然后是由线程创建的新团队   在并行区域内遇到并行构造   只有遇到的线程。如果启用了嵌套并行,   那么新团队可能包含多个帖子。

因此,由于第一个parallel for占用了所有可能的线程,所以第二个拥有遇到线程本身的团队。没有任何反应。

为自己干杯!

相关问题