并行 fortran 程序将在某个时间休眠

Posted

技术标签:

【中文标题】并行 fortran 程序将在某个时间休眠【英文标题】:parallel fortran program willl sleep at a certain time 【发布时间】:2015-11-05 09:05:28 【问题描述】:

最近我不得不将一个用 fortran 编写的串行程序更改为并行版本,以便更快地获得结果。但是我遇到了一些问题。

我使用的是 ubuntu os 和 gfortran 编译器,至于并行 API,我使用的是 OpeMP。在以前的(串行)版本中,我使用许多模块来共享数据,但在 openmp 版本中,我将变量设置为线程私有属性,其中一些变量具有可分配属性。在之前的版本中,我在do-loop之前为变量分配了空间,但是在openmp版本中,如果我这样做,程序会报错为无效的内存引用,虽然我给了它threadprivate属性。所以我在循环中分配变量并在循环中释放它。我在并行区域中进行了循环。它没有错误,程序可以运行。但是还有另一个问题。由于它运行大约 800 分钟 cpu 时间,我使用 ps -ux 命令查看这个并行程序的状态,它的状态从 Rl 变为 Sl。我搜索S的意思,它代表

可中断睡眠(等待事件完成)

那么为什么会出现这个问题呢?是因为我经常分配和释放空间吗?以下是示例代码:

module variables
real, dimension(:), allocatable, save :: a
real, dimension(:,:), allocatable, save :: b
!$omp threadprivate(a,b)
integer, parameter :: n=100
contains
   subroutine alloc_var
   integer :: status
   allocate(a(100),stat=status)
   allocate(b(100:100),stat=status)
   end subroutine
   subroutine free_var
   integer :: status
   deallocate(a,stat=status)
   deallocate(b,stat=status)
   end subroutine
end module

对于其他子程序,有一些使用变量a和b。

subroutine cal_sth
use variables, only a
...
end subroutine

串行版主程序

program main
implicit none   
external :: cal_sth
use variables, only alloc_var,free_var
integer :: i, j
call alloc_var
do j=1, count1
...
other expresion ...
do i=1, count2
   call cal_sth
end do
end do
call free_var
end program

对于平行区域,

program main
implicit none  
external :: cal_sth 
use variables, only alloc_var, free_var
integer :: i,j
!$omp parallel do private(i,j)
do j=1, count1
...
other expression ...
do i=1, count2
   call alloc_var
   call cal_sth
   if (logical expression) then
       call free_var
       cycle
   end if
   call free_var
end do
end do
end program

【问题讨论】:

为什么不在一个专用的parallel 区域内一劳永逸地初始化ab?喜欢:!$omp parallelcall alloc_var!$omp end parallel 【参考方案1】:

要么拆分组合的parallel do 指令并重写并行循环,因此:

!$omp parallel
call alloc_var
!$omp do
do i=1, count
   call cal_sth
end do
!$omp end do
call free_var
!$omp end parallel

或根据 Gilles 的评论使用专用的并行区域:

program main
implicit none  
external :: cal_sth 
use variables, only alloc_var, free_var
integer :: i
!$omp parallel
call alloc_var
!$omp end parallel
...
!$omp parallel do
do i=1, count
   call cal_sth
end do
!$omp end parallel do
...
! other OpenMP regions
...
!$omp parallel
call free_var
!$omp end parallel
end program

【讨论】:

如果我拆分parallel do指令还有一个问题,因为在并行区域,有些情况我需要cycle循环,我忘记在示例代码中添加。此外,不仅有一个循环。我将示例代码更改一下,请再看一遍。【参考方案2】:

对于您更新的代码,我认为您有两条不同的途径可以探索提高性能:

内存分配:如前所述,对alloc_varfree_var 的调用只需要在parallel 区域内进行,但绝对不一定在do 循环内。通过将parallel do 拆分为parallel,然后是do,它为您提供了在进入循环之前调用alloc_var 和在退出循环之后调用free_var 的空间。并且可能提前退出内部循环,可能需要释放/重新分配内存本身并不是阻止您这样做的约束。 (有关如何完成此操作的示例,请参见下面的代码)

调度:一些内部迭代的提前终止可能会转化为线程之间的负载不平衡。这可以解释你实验的等待时间。将调度显式设置为dynamic 可能会减少这种影响并提高性能。这需要进行一些试验才能找到要应用的最佳调度策略,但dynamic 似乎是一个很好的起点。

所以这是你的代码,一旦这两个想法实现,它可能看起来像:

program main
    implicit none  
    external :: cal_sth 
    use variables, only alloc_var, free_var
    integer :: i,j

    !$omp parallel schedule(dynamic)
    call alloc_var
    !$omp do private(i,j)
    do j=1, count1
        ...
        other expression ...
        do i=1, count2
            call cal_sth
            if (logical expression) then
                !uncomment these only if needed for some reasons
                !call free_var
                !call alloc_var
                cycle
            end if
        end do
    end do
    !$omp end do
    call free_var
    !$omp end parallel
end program

【讨论】:

如果我删除schedule 子句,我仍然有一个问题,即在某个时间进度会进入休眠状态。但是如果我加上这个子句,程序会跳转一些循环,比如从j=0到j=6,j=1到5的循环不执行,你知道这是为什么吗?

以上是关于并行 fortran 程序将在某个时间休眠的主要内容,如果未能解决你的问题,请参考以下文章

请看看则个fortran结合openmp并行程序,为啥老出错?

OpenACC + MPI Fortran 程序入门

开始尝试在 Win7 下使用 OpenMP 编写 fortran 并行程序

openmp+fortran程序,双重do循环外面都加并行,结果好像并行了,但是threadid都是0,请问到底并行没有?

如何在由 MPI 并行化的 fortran 中调用子例程?

在 Fortran 中逐行读取逗号分隔的文本文件