【问题标题】:What is this Read after Write dependency?写后读依赖是什么?
【发布时间】:2017-05-03 13:39:37
【问题描述】:

我有这个循环这个函数:

Mat HessianDetector::hessianResponse(const Mat &inputImage, float norm)
{
   //...
   const float *in = inputImage.ptr<float>(1);
   Mat outputImage(rows, cols, CV_32FC1);
   float      *out = outputImage.ptr<float>(1) + 1;
   //...
   for (int r = 1; r < rows - 1; ++r)
   {
      float v11, v12, v21, v22, v31, v32;      
      v11 = in[-stride]; v12 = in[1 - stride];
      v21 = in[      0]; v22 = in[1         ];
      v31 = in[+stride]; v32 = in[1 + stride];
      in += 2;
      for (int c = 1; c < cols - 1; ++c, in++, out++)
      {
         /* fetch remaining values (last column) */
         const float v13 = in[-stride];
         const float v23 = *in;
         const float v33 = in[+stride];

         // compute 3x3 Hessian values from symmetric differences.
         float Lxx = (v21 - 2*v22 + v23);
         float Lyy = (v12 - 2*v22 + v32);
         float Lxy = (v13 - v11 + v31 - v33)/4.0f;

         /* normalize and write out */
         *out = (Lxx * Lyy - Lxy * Lxy)*norm2;

         /* move window */
         v11=v12; v12=v13;
         v21=v22; v22=v23;
         v31=v32; v32=v33;

         /* move input/output pointers */
      }
      out += 2;
   }
   return outputImage;
}

调用方式:

#pragma omp for collapse(2) schedule(dynamic)
for(int i=0; i<levels; i++)
    for (int j = 1; j <= scaleCycles; j++)
    {
        int scaleCyclesLevel = scaleCycles * i;
        float curSigma = par.sigmas[j];
        hessResps[j+scaleCyclesLevel] = hessianResponse(blurs[j+scaleCyclesLevel], curSigma*curSigma);
    }

特别是,Intel Advisor 表示内部循环非常耗时,应该进行矢量化:

for (int c = 1; c < cols - 1; ++c, in++, out++)

但是,它也表示在这两行存在读写依赖:

阅读:

float Lyy = (v12 - 2*v22 + v32);

写:

hessResps[j+scaleCyclesLevel] = hessianResponse(blurs[j+scaleCyclesLevel], curSigma*curSigma);

但我真的不明白为什么会发生这种情况(即使我知道 RAW 依赖的含义)。

这是优化报告:

   LOOP BEGIN at /home/luca/Dropbox/HKUST/CloudCache/cloudcache/CloudCache/Descriptors/hesaff/pyramid.cpp(92,7)
      remark #17104: loop was not parallelized: existence of parallel dependence
      remark #17106: parallel dependence: assumed ANTI dependence between *(in+cols*4) (95:28) and *out (105:11)
      remark #17106: parallel dependence: assumed FLOW dependence between *out (105:11) and *(in+cols*4) (95:28)
      remark #15344: loop was not vectorized: vector dependence prevents vectorization
      remark #15346: vector dependence: assumed ANTI dependence between *(in+cols*4) (95:28) and *out (105:11)
      remark #15346: vector dependence: assumed FLOW dependence between *out (105:11) and *(in+cols*4) (95:28)
   LOOP END

第 95 行是:

     const float v13 = in[-stride];

第 105 行是:

     *out = (Lxx * Lyy - Lxy * Lxy)*norm2;

【问题讨论】:

    标签: c++ parallel-processing vectorization intel-advisor


    【解决方案1】:

    优化报告告诉您的是,循环的一次迭代中有一些值依赖于前一次迭代的值。特别是,“移动窗口”块在局部变量之间复制值,以便下一次迭代中的v11v12 等的值取决于本次迭代中的v12v23 等的值。这可以防止编译器对循环进行向量化。

    解决方案是在 c 循环体中初始化所有 9 个 v 变量。

    我不知道修复此问题是否会解决原始 RAW 问题。

    另一个调整是将scaleCyclesLevel 移出j 循环(因此它是i 循环),因为它的值不依赖于j

    【讨论】:

    • 我明白你的意思,但正如你所见,in 在外部v 声明之后移动,所以如果我在c 循环内声明它们,它们的值会有所不同。我错了吗?
    • @justHelloWorld 他们的价值观不会不同。通过:在第一次迭代中,v11=in[-stride]v12=in[1-stride]。下一次迭代,使用v11=v12v11 的值是(在增加in 之后)in[-stride],因为in 上升一个,所以下标下降一个。
    • 请您看看thisthis 的问题好吗?
    • 能否请您看一下this的问题?
    【解决方案2】:

    我不知道inputImageoutputImage 是如何传递给函数的。如果不将它们传递为restricted,编译器不知道数据是否重叠,因此写入*out 是不安全的,因为它可能会覆盖下一次迭代的*in

    看看如何告诉编译器图像数据不重叠。对于gcc,它是restrict

    【讨论】:

    • 感谢您的回答。但是,outPutImage 在函数内部被删除(正如我在更新的问题中所写的那样),所以问题似乎不是你所描述的。
    • 能否请您看一下this的问题?
    猜你喜欢
    • 2018-04-10
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 2010-10-11
    • 2012-03-09
    • 2018-03-18
    • 2015-04-13
    • 2018-02-08
    相关资源
    最近更新 更多