关于acc例程的一些问题
Some questions about acc routine
一个 MPI 代码,我试图用 openacc 并行化它的一个简单循环,但输出不是预期的。
在这里,循环有一个调用,我在子例程中添加了一个 'acc routine seq' 。如果我手动将此调用内联并删除子例程,结果将是正确的。我是否正确使用了 OpenACC“例程”指令?还是其他错误?
- 运行时环境
MPI版本:openmpi4.0.5
高性能计算 SDK 20.11
CUDA 版本:10.2
!The main program
program test
use simple
use mpi
implicit none
integer :: i,id,size,ierr,k,n1
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD,id,ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierr)
allocate(type1(m))
do i=1,m
allocate(type1(i)%member(n))
type1(i)%member=-1
type1(i)%member(i)=i
enddo
!$acc update device(m,n)
do k=1,m
n1=0
allocate(dev_mol(k:2*k))
dev_mol=type1(k)%member(k:2*k)
!$acc update device(dev_mol(k:2*k))
!$acc parallel copy(n1) firstprivate(k)
!$acc loop independent
do i=k,2*k
call test1(k,n1,i)
enddo
!$acc end parallel
!$acc update self(dev_mol(k:2*k))
type1(k)%member(k:2*k)=dev_mol
write(*,"('k=',I3,' n1=',I2)") k,n1
deallocate(dev_mol)
enddo
do i=1,m
write(*,"('i=',I2,' member=',I3)") i,type1(i)%member(i)
deallocate(type1(i)%member)
enddo
deallocate(type1)
call MPI_Barrier(MPI_COMM_WORLD,ierr)
call MPI_Finalize(ierr)
end
!Here is the module
module simple
implicit none
integer :: m=5,n=2**15
integer,parameter :: p1=15
integer,allocatable :: dev_mol(:)
type type_related
integer,allocatable :: member(:)
end type
type(type_related),allocatable :: type1(:)
!$acc declare create(m,n,dev_mol)
!$acc declare copyin(p1)
contains
subroutine test1(k,n1,i)
implicit none
integer :: k,n1,i
!$acc routine seq
if(dev_mol(i)>0) then
!write(*,*) 'gpu',k,n1,i
n1=dev_mol(i)
dev_mol(i)=p1
else
if(i==k)write(*,*) 'err',i,dev_mol(i)
endif
end
end
- MPI
编译命令:mpif90 test.f90 -o test
运行 命令:mpi运行 -n 1 ./test
结果如下:
k= 1 n1= 1
k= 2 n1= 2
k= 3 n1= 3
k= 4 n1= 4
k= 5 n1= 5
i= 1 member= 15
i= 2 member= 15
i= 3 member= 15
i= 4 member= 15
i= 5 member= 15
- MPI+OpenACC
编译命令:mpif90 test.f90 -o test -ta=tesla:cuda10.2 -Minfo=accel
运行 命令:mpi运行 -n 1 ./test
错误结果如下:
k= 1 n1= 0
k= 2 n1= 0
k= 3 n1= 0
k= 4 n1= 0
k= 5 n1= 0
i= 1 member= 1
i= 2 member= 2
i= 3 member= 3
i= 4 member= 4
i= 5 member= 5
问题在于“i”是通过引用传递的(Fortran 的默认设置)。最简单的解决方案是按值传递它:
contains
subroutine test1(k,n1,i)
implicit none
integer, value :: i
integer :: n1, k
现在有一个小的编译器错误,因为“i”是循环索引变量,所以应该隐式私有化该变量。然而,由于它是通过引用传递的,这导致它被共享。我们将在未来的编译器版本中修复此问题。虽然通常建议尽可能按值传递标量。
更新示例 运行:
% mpif90 test2.f90 -acc -Minfo=accel -V21.2 ; mpirun -np 1 a.out
test1:
16, Generating acc routine seq
Generating Tesla code
test:
48, Generating update device(m,n)
53, Generating update device(dev_mol(k:k*2))
54, Generating copy(n1) [if not already present]
Generating Tesla code
56, !$acc loop gang, vector(128) ! blockidx%x threadidx%x
60, Generating update self(dev_mol(k:k*2))
k= 1 n1= 1
k= 2 n1= 2
k= 3 n1= 3
k= 4 n1= 4
k= 5 n1= 5
i= 1 member= 15
i= 2 member= 15
i= 3 member= 15
i= 4 member= 15
i= 5 member= 15
一个 MPI 代码,我试图用 openacc 并行化它的一个简单循环,但输出不是预期的。 在这里,循环有一个调用,我在子例程中添加了一个 'acc routine seq' 。如果我手动将此调用内联并删除子例程,结果将是正确的。我是否正确使用了 OpenACC“例程”指令?还是其他错误?
- 运行时环境
MPI版本:openmpi4.0.5
高性能计算 SDK 20.11
CUDA 版本:10.2
!The main program
program test
use simple
use mpi
implicit none
integer :: i,id,size,ierr,k,n1
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD,id,ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierr)
allocate(type1(m))
do i=1,m
allocate(type1(i)%member(n))
type1(i)%member=-1
type1(i)%member(i)=i
enddo
!$acc update device(m,n)
do k=1,m
n1=0
allocate(dev_mol(k:2*k))
dev_mol=type1(k)%member(k:2*k)
!$acc update device(dev_mol(k:2*k))
!$acc parallel copy(n1) firstprivate(k)
!$acc loop independent
do i=k,2*k
call test1(k,n1,i)
enddo
!$acc end parallel
!$acc update self(dev_mol(k:2*k))
type1(k)%member(k:2*k)=dev_mol
write(*,"('k=',I3,' n1=',I2)") k,n1
deallocate(dev_mol)
enddo
do i=1,m
write(*,"('i=',I2,' member=',I3)") i,type1(i)%member(i)
deallocate(type1(i)%member)
enddo
deallocate(type1)
call MPI_Barrier(MPI_COMM_WORLD,ierr)
call MPI_Finalize(ierr)
end
!Here is the module
module simple
implicit none
integer :: m=5,n=2**15
integer,parameter :: p1=15
integer,allocatable :: dev_mol(:)
type type_related
integer,allocatable :: member(:)
end type
type(type_related),allocatable :: type1(:)
!$acc declare create(m,n,dev_mol)
!$acc declare copyin(p1)
contains
subroutine test1(k,n1,i)
implicit none
integer :: k,n1,i
!$acc routine seq
if(dev_mol(i)>0) then
!write(*,*) 'gpu',k,n1,i
n1=dev_mol(i)
dev_mol(i)=p1
else
if(i==k)write(*,*) 'err',i,dev_mol(i)
endif
end
end
- MPI
编译命令:mpif90 test.f90 -o test
运行 命令:mpi运行 -n 1 ./test
结果如下:
k= 1 n1= 1
k= 2 n1= 2
k= 3 n1= 3
k= 4 n1= 4
k= 5 n1= 5
i= 1 member= 15
i= 2 member= 15
i= 3 member= 15
i= 4 member= 15
i= 5 member= 15
- MPI+OpenACC
编译命令:mpif90 test.f90 -o test -ta=tesla:cuda10.2 -Minfo=accel
运行 命令:mpi运行 -n 1 ./test
错误结果如下:
k= 1 n1= 0
k= 2 n1= 0
k= 3 n1= 0
k= 4 n1= 0
k= 5 n1= 0
i= 1 member= 1
i= 2 member= 2
i= 3 member= 3
i= 4 member= 4
i= 5 member= 5
问题在于“i”是通过引用传递的(Fortran 的默认设置)。最简单的解决方案是按值传递它:
contains
subroutine test1(k,n1,i)
implicit none
integer, value :: i
integer :: n1, k
现在有一个小的编译器错误,因为“i”是循环索引变量,所以应该隐式私有化该变量。然而,由于它是通过引用传递的,这导致它被共享。我们将在未来的编译器版本中修复此问题。虽然通常建议尽可能按值传递标量。
更新示例 运行:
% mpif90 test2.f90 -acc -Minfo=accel -V21.2 ; mpirun -np 1 a.out
test1:
16, Generating acc routine seq
Generating Tesla code
test:
48, Generating update device(m,n)
53, Generating update device(dev_mol(k:k*2))
54, Generating copy(n1) [if not already present]
Generating Tesla code
56, !$acc loop gang, vector(128) ! blockidx%x threadidx%x
60, Generating update self(dev_mol(k:k*2))
k= 1 n1= 1
k= 2 n1= 2
k= 3 n1= 3
k= 4 n1= 4
k= 5 n1= 5
i= 1 member= 15
i= 2 member= 15
i= 3 member= 15
i= 4 member= 15
i= 5 member= 15