Fortran:分段错误

时间:2015-11-03 12:42:20

标签: fortran openmp f2py

我知道我曾经做过类似的话题,但那个话题不同。这次,添加print语句不会改变我是否得到段错误。

    call omp_set_num_threads(omp_get_max_threads())
    !$omp parallel do  &
    !$omp default(firstprivate) &
    !$omp private(present_surface) &
    !$omp lastprivate(fermi)
    do m = 1, fourth 
        do n = 1, third
            do j = 1, second
                do i = 1, first
                    !current angle is phi[i,j,ii,jj]
                    !we have to find the current fermi surface
                    present_surface = 0.
                    do a = 1, fourth    
                        if (angle(i,j,n,m) == angle_array(a)) then
                            present_surface = surface(a)
                        end if
                    end do 
                    if (radius(i,j,n,m) >= present_surface) then 
                        fermi(i,j,n,m) = 0.
                    else 
                        fermi(i,j,n,m) = 1.
                    end if          
                end do      
            end do      
        end do
    end do  
    !$omp end parallel do

我不确定最后的私人(费米)声明,但此刻并不重要。 shared给出了相同的行为。

所以,我运行这个脚本时会增加'第一,第二,第三,第四'。典型输出:

[10] Time elapsed is 0.001 [s].
[15] Time elapsed is 0.002 [s].
[20] Time elapsed is 0.005 [s].
./compile: line 2:  4310 Segmentation fault      python fortran_test.py

那么,如何继续。我看了gdb python;运行fortran_test.py,找到:

(gdb) run fortran_test.py 
Starting program: /usr/bin/python fortran_test.py
[Thread debugging using libthread_db enabled]
[New Thread 0x7fffed9b0700 (LWP 4251)]
[New Thread 0x7fffe8ba5700 (LWP 4252)]
[New Thread 0x7fffe83a4700 (LWP 4253)]
[New Thread 0x7fffe7ba3700 (LWP 4254)]
[10] Time elapsed is 0.008 [s].
[15] Time elapsed is 0.004 [s].
[20] Time elapsed is 0.005 [s].

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffe7ba3700 (LWP 4254)]
0x00007fffe8dc0bb7 in __populate_MOD_fermi_integrand._omp_fn.0 () at     populate.f90:31
31                              do n = 1, third

如果我改变内循环中的东西 - 例如,移除j,i循环并将它们置于常量 - 那么我只是将segfault放在不同的行上。

认为这与内存有关,因为它会随着N的增加而触发。但是,我尝试过的东西(导出GOMP_STACKSIZE,OMP_STACKSIZE,ulimit)还没有修复它,我发现使用它们没什么区别。 (目前,我删除了它们。)

最后,编译命令(它在f2py中):

 f2py --fcompiler=gfortran --f90flags="-fopenmp -g" -lgomp -m -c populate populate.f90

正如你所看到的,我很困惑。我希望你们中的一些人知道如何解决这个问题。

我的目标是快速运行N = 100(因此openMP fortran函数),但这对于fortran代码应该无关紧要,是吗?

如果您想知道,4GB RAM和我的交换是3.1G(Linux Swap / Solaris)。

谢谢!

2 个答案:

答案 0 :(得分:4)

default(firstprivate) lastprivate(fermi)表示每个帖子都会收到angleradiusfermi的私人副本,每个副本的大小为first x second x third x fourth。根据我的经验,私有数组总是在堆栈上分配,即使在给出自动将大数组转换为堆数组的选项时也是如此。由于堆栈空间不足,您的代码很可能崩溃。

您应该真正了解数据依赖关系并选择正确的数据共享类,而不是将所有内容都设置为私有。永远不会写angleangle_arraysurfaceradius,因此它们都应该是sharedpresent_surface正在修改,应为privatefermi被写入,但从不在同一位置由多个线程写入,因此它也应该是shared。另外,请注意lastprivate不会获得预期的结果,因为它使得它在执行m - 循环的逻辑上最后一次迭代的线程中具有的相应变量的值可用。 firstsecondthirdfourth仅被视为常量,应为shared。当然,循环变量是private,但这是由编译器自动完成的。

!$omp parallel do private(present_surface)
do m = 1, fourth 
    do n = 1, third
        do j = 1, second
            do i = 1, first
                !current angle is phi[i,j,ii,jj]
                !we have to find the current fermi surface
                present_surface = 0.
                do a = 1, fourth    
                    if (angle(i,j,n,m) == angle_array(a)) then
                        present_surface = surface(a)
                    end if
                end do 
                if (radius(i,j,n,m) >= present_surface) then 
                    fermi(i,j,n,m) = 0.
                else 
                    fermi(i,j,n,m) = 1.
                end if          
            end do      
        end do      
    end do
end do  
!$omp end parallel do

答案 1 :(得分:0)

一个非常可能的原因是堆栈限制。首先运行ulimit -s,以检查该进程的堆栈限制。您可以使用ulimit -s unlimited将其设置为无限制。然后,如果仍然崩溃,请尝试通过将OMP_STACKSIZE环境变量设置为一个巨大的值(例如100MB)来增加OPENMP的堆栈。

英特尔在https://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors进行了讨论。它具有有关堆栈和堆内存的更多信息。