首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Fortran OpenMP代码中的劣质缩放和分割错误

Fortran OpenMP代码中的劣质缩放和分割错误
EN

Stack Overflow用户
提问于 2019-03-11 16:01:36
回答 1查看 401关注 0票数 2

我在执行一个并行的程序时遇到了一些麻烦。这是一个测试代码。

代码语言:javascript
复制
module test
use, intrinsic :: iso_fortran_env, only: dp => real64
implicit none
contains

subroutine Addition(x,y,s)
    real(dp),intent(in) :: x,y
    real(dp), intent(out) :: s
    s = x+y
end subroutine Addition

function linspace(length,xi,xf) result (vec)
! function to create an equally spaced vector given a begin and end point
    real(dp),intent(in) :: xi,xf
    integer, intent(in) :: length
    real(dp),dimension(1:length) :: vec
    integer ::i
    real(dp) :: increment

    increment = (xf-xi)/(real(length)-1)
    vec(1) = xi
    do i = 2,length
        vec(i) = vec(i-1) + increment
    end do
end function linspace
end module test

program paralleltest
use, intrinsic :: iso_fortran_env, only: dp => real64
use test
use :: omp_lib
implicit none
integer, parameter :: length = 1000
real(dp),dimension(length) :: x,y
real(dp) :: s
integer:: i,j
integer :: num_threads = 8
real(dp),dimension(length,length) :: SMatrix

 x = linspace(length,.0d0,1.0d0)
 y = linspace(length,2.0d0,3.0d0)

!$ call omp_set_num_threads(num_threads)
!$OMP PARALLEL DO
do i=1,size(x)
    do j = 1,size(y)
    call Addition(x(i),y(j),s)
    SMatrix(i,j) = s
    end do
end do
!$OMP END PARALLEL DO

open(unit=1,file ='Add6.dat')
do i= 1,size(x)
    do j= 1,size(y)
        write(1,*) x(i),";",y(j),";",SMatrix(i,j)
    end do
end do
close(unit=1)
end program paralleltest

我正在以下面的方式运行这个程序,gfortran-8 -fopenmp paralleltest.f03 -o pt.out -mcmodel=medium,然后export OMP_NUM_THREADS=8,这个简单的代码给我带来了至少两个关于并行do的大问题。第一种情况是,如果我使用length = 1100或更高版本运行,我会收到Segmentation fault (core dump)错误消息,但如果使用较小的值,则不会出现问题。第二个问题是所需的时间。当我使用length = 1000 (与time ./pt.out一起运行)运行它时,所需的时间是1,732s,但是如果我按顺序运行它(不调用-fopenmp库和taskset -c 4 time./pt.out ),则需要1,714s。我猜这两种方式之间的区别出现在一个更长、更复杂的代码中,在这种代码中,并行更有用。事实上,当我尝试用更复杂的计算与八个线程并行运行时,时间减少了一半,是按顺序进行的,但不是我预期的八分之一。鉴于此,我的问题是,是否有任何优化总是可用的,还是它依赖于代码?第二,是否有一种友好的方式来控制哪个线程运行哪个迭代?这是第一次运行第一个length/8迭代,以此类推,就像用不同的代码执行几个taskset,其中每个代码都是我想要的迭代。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-03-11 16:14:45

正如我所评论的,分段错误已经在其他为什么分割错误发生在这个openmp代码中?中处理过,我将使用一个可分配的数组,但您也可以使用ulimit -s设置堆栈大小。

关于时间,几乎所有的运行时都用于将数组写入外部文件。

但是,即使您删除了它,并且使用omp_get_wtime()度量了只在并行部分中花费的时间,并且增加了问题的大小,它仍然不能很好地扩展。这是因为CPU所要做的计算非常少,并且有很多数组写入内存(访问主内存是慢缓存丢失的)。

正如所指出的,您的循环顺序是错误的,使得访问内存的速度更慢。一些编译器可以用更高的优化级别(-O2-O3)来改变这一点,但只有其中的一部分。

更糟糕的是,正如吉姆·考尼所指出的,你有一个种族条件。多个线程尝试使用相同的s进行读写,程序无效。您需要使用s使private(s)成为私有的。

通过上面的修正,我得到了一个大约快两倍的并行部分,它有四个核心和四个线程。不要试图使用超线程,它会减慢程序的速度。

如果您让CPU做更多的计算工作,比如s = Bessel_J0(x)/Bessel_J1(y),它对我来说是很好的扩展,有四个线程的速度快了将近四倍,而超线程确实使它加快了一点点。

最后,我建议只是删除手动设置的线程数,这是一个痛苦的测试。如果您删除了它,您可以很容易地使用OMP_NUM_THREADS=4 ./a.out

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55105856

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档