Fortran Openmp:Ghost线程在分配时中断应用程序

时间:2020-03-22 12:00:37

标签: fortran openmp

我遇到了一个使我发疯的问题。作为大型软件工具的一部分,我正在编写一个Fortran模块来执行天体动力学计算。 主要功能包含在子例程中,该子例程使用OpenMP和其他子例程执行其任务。 工作流程如下:

1)准备-读入文件

2)开始第一个并行omp并行操作

3)基于工作模式,该函数可能会递归调用自身并处理数据的单独部分(从而执行第二个omp do循环)

4)将结果合并到一个派生类型的大数组中

到目前为止,一切都已按预期运行。接下来是失败的部分:

5)使用4中的结果,开始另一个并行循环以继续处理。

步骤5有时会起作用,有时会因访问冲突而停止。这与选择的优化级别无关(名义上我们使用O2,但对于O0也是如此)。 因此,我启动了Intel检查器,并寻找数据争用/死位置,....

它报告了5个非常奇怪的数据竞争,这对我来说毫无意义,因为代码位置位于子例程的定义/末尾,代码行读取线程私有全局变量,Intel MKL例程或读取以下内容的位置局部可分配数组,该数组位于并行区域内的子例程中。 在阅读了一些内容之后,我启用了递归开关以强制本地数组在堆栈上结束。另一个Inspector分析由于相同的访问冲突而中断。加载结果时未检测到错误,但该工具警告说,由于异常的最终数据,可能会丢失。

然后,我试图将整个循环放入OMP关键-就像进行测试一样。现在访问冲突消失了,但是代码很早就被卡住了,在处理15/500对象之后它就停止了。这看起来像一个僵局。 因此,我继续搜索并在步骤5的do循环中注释掉了每个OMP语句。 有趣的是,代码也将在迭代15处停止! 因此,我使用调试器来定位发生无限等待状态的调用。 它是在最终的allocate语句中:

Subroutine doWork(t0, Pert, allAtmosData, considerArray, perigeeFirstTimeStepUncertainties)
real(dp), intent(in)                                            :: t0                                               
type (tPert), intent(in)                                        :: Pert                                            
type (tThermosphereData), dimension(:), allocatable, intent(in) :: allAtmosData                                                                                                                                                                              
integer(i4), dimension(3), intent(in)                           :: considerArray
real(dp), dimension(:,:), allocatable, intent(out)              :: perigeeFirstTimeStepUncertainties
!Locals:
real(dp), dimension(:), allocatable                     :: solarFluxPerigeeUnc, magneticIndexUnc, modelUnc
integer(i4)                                             :: dataPoints

!Allocate memory for the computations
dataPoints = size(allAtmosData, 1)

allocate(solarFluxPerigeeUnc(0:dataPoints-1), source=0.0_dp)
allocate(magneticIndexUnc(0:dataPoints-1),    source=0.0_dp)
allocate(modelUnc(0:dataPoints-1),            source=0.0_dp)


... Subroutine body ...


!Assign outputs
allocate(perigeeFirstTimeStepUncertainties(3, 0:dataPoints-1), source=0.0_dp)
perigeeFirstTimeStepUncertainties(MGN_SOLAR_FLUX_UNCERTAINTY,:) = solarFluxPerigeeUnc
perigeeFirstTimeStepUncertainties(MGN_MAG_INDEX_UNCERTAINTY,:)  = magneticIndexUnc
perigeeFirstTimeStepUncertainties(MGN_MODEL_UNCERTAINTY,:)      = modelUnc

End Subroutine

该子例程在整个程序的其他位置也可以完美地工作 步骤5的14次迭代。但是,在第15次迭代中,它停留在最后一次分配中,或者正如我刚刚设法产生的那样,也会导致访问冲突。 当我使用调试器暂停代码时,我看到以某种方式已经加载了openmp库,并且代码在frontend.cpp中挂起/崩溃,我无法访问: Call Stack at error location

这是怎么回事?在任何OMP语句已被注释掉的循环中,如何简单地分配突然导致的OMP活动? 附带说明:如果我注释掉分配并将大小作为附加参数传递,则代码中的下一个分配会发生相同的错误。

我们非常感谢您提供的任何帮助或解决方法!我已经在Google上搜索了如何关闭任何先前的线程池,以确保绝对没有剩余的omp ghost线程活动,但是显然没有办法。最终,循环还将并行运行。

编辑:我刚刚在使用2018 v5的计算机上进行了第二次测试。它还表明,allocate语句导致先调用for_alloc_allocatable(),然后再调用OMP语句。还会显示程序崩溃的mov语句: enter image description here

我猜想是某种原因可能在第二个递归OMP循环中导致内存损坏,因为以某种方式将分配重定向到线程池内存分配,但是除主线程之外的所有线程都应该是被动的?我看不懂汇编程序,但是我很惊讶地发现OpenMp使用了TBB?这可能是TBB中的错误吗?

0 个答案:

没有答案