【问题标题】:How to repair a [Segmentation fault] in parallelizing a for loop with OpenMP?如何在使用 OpenMP 并行化 for 循环时修复 [分段错误]?
【发布时间】:2018-05-15 16:43:09
【问题描述】:

我在尝试并行化 for-loop 时遇到分段错误,我无法理解原因。

代码如下:

#pragma omp parallel for schedule(static) reduction(+:ptx,pty)
    for(int i=0;i<numSteps;i++)
    {
        float energy=0;
        for(int idx=0;idx<patternNum;idx++)
        {
            float hitColor = getInterpolatedElement31(frame->dI,
                                        (float)(ptx+rotatetPattern[idx][0]),
                                        (float)(pty+rotatetPattern[idx][1]),
                                        wG[0]);

            if(!std::isfinite(hitColor)) {energy+=1e5; continue;}

            float residual = hitColor - (float)(hostToFrame_affine[0] * color[idx] + hostToFrame_affine[1]);
            float hw = fabs(residual) < setting_huberTH ? 1 : setting_huberTH / fabs(residual);
            energy += hw *residual*residual*(2-hw);
        }

        if(debugPrint)
            printf("step %.1f %.1f (id %f): energy = %f!\n",
                    ptx, pty, 0.0f, energy);

        errors[i] = energy;
        if(energy < bestEnergy)
        {
            bestU = ptx; bestV = pty; bestEnergy = energy; bestIdx = i;
        }

        ptx+=dx;
        pty+=dy;
    }
std::cout << "hello\n";

这个for-loop所在的函数被多次调用,分段错误只是在这个函数的多次迭代之后引起的。

这就是我放置cout &lt;&lt; "hello" 的原因,以查看"hello" 被打印了多少次。

然而,即使前几次迭代没有产生错误,我认为正在执行的计算的结果是不正确的,这是一个 SLAM 代码,所以在输出中我可以看到结果,在我得到分割之前错误,不是它应该是的。

你能在这个循环中看到任何可能使用这个编译指示产生这个错误的东西吗?

【问题讨论】:

  • 请将代码转换为minimal reproducible example,并说明您自己调试的结果。
  • 代码运行时是否没有错误,是否在串行中给出了正确的结果?你的第一句话听起来像,但对我来说并不完全清楚。
  • @Shadow 是的

标签: for-loop parallel-processing segmentation-fault openmp


【解决方案1】:

首先,我相信 reduction(+:ptx,pty) 不是你需要的。串行代码假设 ptx 和 pty 在每次下一次迭代中递增,因为它们的值在 getInterpolatedElement31 调用中使用。但是随着减少,您将在每次迭代中获得相同的值 = ptx (pty) 的初始值。

第二,共享变量bestUbestVbestEnergybestIdx可能会被多个线程同时更新

bestU = ptx; bestV = pty; bestEnergy = energy; bestIdx = i;

因此,您需要在此处进行一些同步。

【讨论】:

  • 你是对的@Milad Rashidi,分段错误是由缩减子句引起的。虽然现在我没有分段错误,但这种并行化并没有给我正确的结果。我在你说需要同步的那条线上添加了一个关键的 pragma omp,但仍然有不好的结果
  • 您是否相应地更改了ptx+=dx; pty+=dy; 以使其在每次迭代中都不同?
  • 我没有改变那个没有。但既然你指出了这一点,我想了想,也许这个循环是不可并行的,由于 ptx 和 pty 值的变化,每次迭代都依赖于前一次迭代,对吧?
【解决方案2】:

在输出中我可以看到 结果,在我得到分段错误之前,不是它应该是的。

好吧,在内容方面正确工作的代码上审查问题是公平的。然而,让我概述一些关于主要问题可能出现的提示,或者如何使用石器时代的策略来确定根本原因......

通常的做法是拥有具有已知解决方案的数据集,以便及早检测错误/确认过程设计对产生的结果的有效性,只需重新运行已知的测试集即可。


遇到分段错误...我无法理解为什么

一般嫌疑人是:
声明/寻址相关,见:
idx == patternNum - 1 : rotatetPattern[idx][ {0|1} ]
idx强> == patternNum - 1 : color[idx]
i == numStep : errors[i]
@ 987654331@ hostToFrame_affine[]
? wG[]

调用签名和/或实现细节,见:
floatgetInterpolatedElement31(...){ ... }
floatfabs@ 987654342@


最简单的下一步?先观察确凿的线索......总是......

目前最简单的步骤是在每个执行的行之后添加一个 DEBUG-trailing-stop 行:

FLINTSTONEs_DEBUG_LOG( 0 ); // ------------------------------------------------

#pragma omp parallel for schedule(static) reduction(+:ptx,pty)
    for( int i =  0;
             i <  numSteps;
             i++
             )
    {   
        FLINTSTONEs_DEBUG_LOG( 1 ); // ----------------------------------------

        float energy = 0;

        FLINTSTONEs_DEBUG_LOG( 2 ); // ----------------------------------------

        for ( int idx =  0;
                  idx <  patternNum;
                  idx++
                  )
        {   FLINTSTONEs_DEBUG_LOG( 3 ); // ------------------------------------

            float hitColor = getInterpolatedElement31(
                                         frame->dI,
                                 (float)( ptx
                                        + rotatetPattern[idx][0]
                                          ),
                                 (float)( pty
                                        + rotatetPattern[idx][1]
                                          ),
                                        wG[0]
                                 );

            FLINTSTONEs_DEBUG_LOG( 4 ); // -----------------------------------

            if ( !std::isfinite( hitColor ) )
            {    
                  FLINTSTONEs_DEBUG_LOG( 5 ); // -----------------------------

                  energy += 1e5;

                  FLINTSTONEs_DEBUG_LOG( 6 ); // -----------------------------

                  continue;

                  FLINTSTONEs_DEBUG_LOG( 7 ); // -------------------------- ;)
            }

            float residual = hitColor
                           - (float) ( hostToFrame_affine[0]
                                     * color[idx]
                                     + hostToFrame_affine[1]
                                       );

            FLINTSTONEs_DEBUG_LOG( 8 ); // -----------------------------------

            float hw = setting_huberTH > fabs( residual )
                     ? 1
                     : setting_huberTH / fabs( residual );

            FLINTSTONEs_DEBUG_LOG( 9 ); // -----------------------------------

            energy += hw
                    * residual
                    * residual
                    * ( 2 - hw );

            FLINTSTONEs_DEBUG_LOG( 10 ); // ----------------------------------

        }

        FLINTSTONEs_DEBUG_LOG( 11 ); // --------------------------------------
        ...
        ..
        .

使用:

        void FLINTSTONEs_DEBUG_LOG( int TracePOINT )
        {    printf( "ACK: thread[%d]'s smoke-trail has reached TracePOINT( %d )\n",
                     omp_get_thread_num(),
                     TracePOINT
                     );
        }

当然,这不是火箭科学,但可能会在下一个 SegFault 出现后轻松地向您展示烟雾轨迹,所以在这里也值得一提。

Yabba Dabba Doo,去让它坚如磐石,一步一个脚印。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多