【问题标题】:Segmentation fault with openmp in Fortran 90 program [duplicate]Fortran 90程序中openmp的分段错误[重复]
【发布时间】:2020-03-19 13:01:55
【问题描述】:

我正在编写一个小程序来练习 Fortran 90openmp。以下示例代码在我使用gfortran -fopenmp heat.f90 -o heat 编译时返回分段错误,但在编译没有 -fopenmp 选项时运行良好。有人可以帮我理解为什么会这样吗?

我在我的 shell 中设置 export OMP_NUM_THREADS=4(Windows 10 上的 Ubuntu 上的 Bash)

program heat

    use omp_lib
    implicit none

    integer, parameter :: nx = 1000
    integer, parameter :: ny = 800
    real, parameter :: H = 1.
    real, parameter :: alpha = 1.e-4
    real, parameter :: dt = 0.001
    real, parameter :: physical_time = 50.

    real aspect, L, dx, dy
    real, dimension(nx,ny) :: T

    aspect = real(nx)/real(ny)
    L = H*aspect
    dx = L/real(nx)
    dy = H/real(ny)

    T = initialize_T()
    call evolve_field()

    contains

        function initialize_T() result(T)
            implicit none
            real, parameter :: sigma = 0.2
            integer i, j
            real x, y
            real, dimension(nx,ny) :: T
            do i=1, nx
                do j=1, ny
                    x = real(i)/real(nx)*L
                    y = real(j)/real(ny)*H
                    T(i,j) = 10. + &
                             2.* ( &
                                   1./(2.*3.14*sigma**2.) * &
                                   exp(-1. * ( (x-L/2.)**2. + (y-H/2.)**2. ) / (2.*sigma**2.)) &
                                 )
                enddo
            enddo
        end function initialize_T

        subroutine heat_eqn()
            implicit none
            real, dimension(nx,ny) :: Tn
            real d2Tdx2, d2Tdy2
            integer i, j

            Tn(:,:) = T(:,:)

            !$omp parallel shared(T) private(i,j,d2Tdx2,d2Tdy2)
            !$omp do
            do i=2, nx-1
                do j=2, ny-1            
                    d2Tdx2 = ( Tn(i+1,j) - 2.*Tn(i,j) + Tn(i-1,j) ) / dx**2.
                    d2Tdy2 = ( Tn(i,j+1) - 2.*Tn(i,j) + Tn(i,j-1) ) / dy**2.
                    T(i,j) =  Tn(i,j) + dt*(alpha*(d2Tdx2 + d2Tdy2))
                end do
            end do
            !$omp end do                     
            !$omp end parallel

            T(:, 1)  = T(:, 2)
            T(:, ny) = T(:, ny-1)
            T(1, :)  = T(2, :)
            T(nx, :) = T(nx-1, :)

        end subroutine heat_eqn

        subroutine evolve_field()
            implicit none
            integer ts, total_ts, frames_total, output_period_ts, pic_counter
            real progress_pct
            character(len=16) :: pic_counter_str

            total_ts = ceiling(physical_time/dt)
            frames_total = 30*20
            output_period_ts = int(total_ts/frames_total)

            pic_counter = 0

            do ts = 0, total_ts

                if (mod(ts,output_period_ts) .eq. 0) then

                    progress_pct = 100.*real(ts)/real(total_ts)
                    print '(I8, F7.2, A)', ts, progress_pct, "%"

                    !! -- for plotting

                    !open(3, file="T.dat", access="stream")
                    !write(3) T(:,:)
                    !close(3)

                    !write (pic_counter_str,'(I5.5)') pic_counter
                    !call system('gnuplot -c plot3d.gnu '//trim(pic_counter_str))
                    !pic_counter = pic_counter + 1

                end if

                ! -----

                call heat_eqn()

                ! -----

            end do

        end subroutine evolve_field

end program heat

【问题讨论】:

  • 您可能已经用尽了可用的堆栈内存。我不使用 Ubuntu,因此无法帮助增加堆栈大小。在 Windows 10 下运行 Ubuntu 可能会加剧这个问题。
  • @IanBush 不错!我已将问题更新为没有该错误。不幸的是,这并不能解决段错误。

标签: segmentation-fault fortran openmp gfortran fortran90


【解决方案1】:

正如 cmets 中的 evets 所建议的,由于堆栈内存不足,程序崩溃了。也就是说,您创建了太多太大的自动(堆栈分配)数组。作为指示,您可以在 Valgrind 中运行该程序

> gfortran -fopenmp heat.f90
> valgrind ./a.out

在打印很多“无效写入”错误之前,它会输出类似

==31723== Warning: client switching stacks?  SP change: 0x1ffefffbc0 --> 0x1ffecf2740
==31723==          to suppress, use: --max-stackframe=3200128 or greater

当堆栈内存不足时,经常会出现“客户端切换堆栈”的警告。

在现实世界的程序中,您将使用allocatable 数组,这不是人为限制的。然而,在这个简单的例子中,我成功使用了标志 -fno-automatic,它避免了使用自动(堆栈分配)数组,而是将它们放入不同类型的内存中:

> gfortran -fno-automatic -fopenmp heat.f90
> ./a.out
       0   0.00%
     500   0.17%
    1000   0.33%
    1500   0.50%
...

您可以在手册页中阅读有关该选项的详细信息。

注意:我在不同的 Linux 发行版中测试了该程序(不是在 Windows 中)。

【讨论】:

  • 堆栈溢出的工作示例应该得到两分!当一个人得到一个相对较大的程序时,这是很常见的......而且与过去相比显然超级大。
  • 支持可分配数组评论 - 这是解决此问题的正确方法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-25
  • 1970-01-01
  • 1970-01-01
  • 2013-04-22
  • 2020-11-01
  • 2014-02-24
相关资源
最近更新 更多