OpenMP 并行代码与串行代码的输出不同

Posted

技术标签:

【中文标题】OpenMP 并行代码与串行代码的输出不同【英文标题】:OpenMP parallel code has not the same output as the serial code 【发布时间】:2015-09-02 13:24:31 【问题描述】:

我不得不更改和扩展我的算法以进行某些信号分析(使用 polyfilterbank 技术)并且无法使用我的旧 OpenMP 代码,但在新代码中结果与预期不符(结果位于与串行运行相比,该数组在某种程度上不正确[串行代码显示预期结果])。

所以在第一个循环 tFFTin 中,我有一些 FFT 数据,我将其与窗口函数相乘。

目标是一个线程为每个多相因子运行内部循环。为了避免锁定,我使用了归约编译指示(标准没有定义复杂归约,所以我使用我的一个,其中每个线程的 omp_priv 变量都使用 omp_orig [所以使用 tFFTin] 进行初始化)。我使用有序编译指示的原因是结果应该以有序的方式添加到输出向量中。

typedef std::complex<float> TComplexType;
typedef std::vector<TComplexType> TFFTContainer;

#pragma omp declare reduction(complexMul:TFFTContainer:\
        transform(omp_in.begin(), omp_in.end(),\
                omp_out.begin(), omp_out.begin(),\
                std::multiplies<TComplexType>()))\
                initializer (omp_priv(omp_orig))


void ConcreteResynthesis::ApplyPolyphase(TFFTContainer& tFFTin, TFFTContainer& tFFTout, TWindowContainer& tWindow, *someparams*) ;

  
    #pragma omp parallel for shared(tWindow) firstprivate(sFFTParams) reduction(complexMul: tFFTin) ordered  if(iFFTRawDataLen>cMinParallelSize)
    for (int p = 0; p < uPolyphase; ++p) 
        int iPolyphaseOffset = p * uFFTLength;
        for (int i = 0; i < uFFTLength; ++i) 
            tFFTin[i] *= tWindow[iPolyphaseOffset + i]; ///< get FFT input data from raw data
            

        #pragma omp ordered
        
//using the overlap and add method
        for (int i = 0; i < sFFTParams.uFFTLength; ++i) 
            pDataPool->GetFullSignalData(workSignal)[mSignalPos + iPolyphaseOffset + i] += tFFTin[i];
        
        

    

    mSignalPos = mSignalPos + mStep;

是否存在竞争条件或其他东西,在开始时会产生错误的输出?还是我有一些逻辑错误?

另一个问题是,我不太喜欢使用有序编译指示的解决方案,是否有更好的方法(我也尝试为此使用缩减模型,但编译器不允许我使用指针类型)?

【问题讨论】:

您是否尝试过并行化内部循环而不是外部循环?在这种情况下,您不需要自定义减少,也不需要订购。 我看到它的方式是,例如在第二个线程中(例如在两个线程中),tFFTin 以与第一个线程中的 tFFTin 相同的初始值开始,而它应该从第一个线程中累积的乘积开始,因此将值添加到 workSignal会错的。 @Zboson 我不想使用它,因为我在某处读到并行化内循环的扩展性不如外循环。 @HristoIliev 好吧,我没看到。是否有编译指示以某种方式将 ot 传递给其他线程,或者我应该按照 Z boson 的建议并行化内部循环? 我的意思是尝试并行化内部循环,看看你是否得到正确的答案。如果你这样做了,那么你会学到一些东西,这可能有助于你理解如何让外循环正确。如果它也很快,那就更好了。测试非常简单。您必须更改几行代码并重新编译。 【参考方案1】:

我认为您的问题是您为 tFFTin 实现了一个非常酷的自定义缩减。但是这种减少是在平行区域的末端应用的。 这是在您使用 tFFTin 中的数据之后。另一件事是 H. Iliev 提到外循环的第二次迭代依赖于在前一次迭代中计算的数据 - 一个经典的依赖关系。

我认为你应该尝试并行化内部循环。

【讨论】:

以上是关于OpenMP 并行代码与串行代码的输出不同的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有串行内循环的openMP并行化外循环以进行数组添加

OpenMP 循环运行代码比串行循环慢

openMP C++ 简单并行区域 - 输出不一致

串行输入输出和并行输入输出的区别解析

在不同的线程下运行相同的代码有啥意义 - openMP?

OpenMP 并行代码运行速度较慢