OpenACC: FORTRAN dynamic pointers

Hey Mat,

I’m having problems getting a program with dynamic pointers working. It seems that its target is not recognized in the UPDATE DEVICE directive, for one thing. This is a cutdown, but in the much larger programming I’m porting, there is a memory allocation that blows the size of memory, then crashes.

program main
use OpenACC

real(8), allocatable,target :: A(:,:)

$acc declare create(A)
allocate(A(10,3))
!$acc update device(A)

call Process
!$acc update self(A)
for index4=1:3
write(,) A(1:10,index4)
end do

contains

subroutine Process
pointer (iPvec,vec)
real(8) :: vec(1:10)

$acc declare create(iPvec)
do index=1,3
  iPvec = loc(A(1,index)

  call acc_attach(iPvec)
  !$acc parallel loop
  do index2=1,10
    vec(index2) = index2 + index
  end do
end do

end routine Process
end program main

Have not been able to generate a cutdown of the original issue; and I’m not sure about using acc_attach() multiple times.

But use of vec(:) is problematic currently.

Thanks in advanced for any help.

Hi Richard,

After fixing the typos, the code works correctly for me. I also cleaned it up a bit since, no, the attach is not needed. I don’t believe we support Cray pointers directly in device code, but here “vec” is an alias for “A”, hence when the present check is done before entering the parallel loop, the correct device location will be used.

For example:

% cat test2.f90
program main
use OpenACC

real(8), allocatable,target :: A(:,:)

!$acc declare create(A)
allocate(A(10,3))
!$acc update device(A)

call Process
!$acc update self(A)
do index4=1,3
write(*,*) A(1:10,index4)
end do

contains

subroutine Process
pointer (iPvec,vec)
real(8) :: vec(1:10)

!acc declare create(iPvec)
do index=1,3
  iPvec = loc(A(1,index))

  !$acc parallel loop default(present)
  do index2=1,10
    vec(index2) = index2 + index
  end do
end do
end subroutine Process
end program main
% nvfortran -Minfo=accel test2.f90 -acc; a.out
main:
      8, Generating update device(a(:,:))
     11, Generating update self(a(:,:))
process:
     26, Generating Tesla code
         27, !$acc loop gang ! blockidx%x
     26, Generating default present(vec(:))
    2.000000000000000         3.000000000000000         4.000000000000000
    5.000000000000000         6.000000000000000         7.000000000000000
    8.000000000000000         9.000000000000000         10.00000000000000
    11.00000000000000
    3.000000000000000         4.000000000000000         5.000000000000000
    6.000000000000000         7.000000000000000         8.000000000000000
    9.000000000000000         10.00000000000000         11.00000000000000
    12.00000000000000
    4.000000000000000         5.000000000000000         6.000000000000000
    7.000000000000000         8.000000000000000         9.000000000000000
    10.00000000000000         11.00000000000000         12.00000000000000
    13.00000000000000

The problem with your first example before the edit was with putting “vec” in the declare create. This would create a separate copy of “vec”. Though since you wanted “vec” to be an alias to “A”, it should be left out. The acc_attach of “P” isn’t needed either since the present check will make the correct association.

 % cat test.f90
program main
use OpenACC

pointer (iPvec,vec)

real(8) :: vec(1:10)
real(8), allocatable,target :: A(:,:)
real(8), pointer :: P(:)

!$acc declare create(A)

allocate(A(10,3))
A=0.0
!$acc update device(A)
do index=1,3
iPvec = loc(A(1,index))
P => A(1:10,index)

!$acc parallel loop default(present)
do index2=1,10
  vec(index2) = index2 + index
end do

!$acc parallel loop default(present)
do index3=1,10
  P(index3) = P(index3)+1
end do
end do

!$acc update self(A)
do index4=1,3
write(*,*) A(1:10,index4)
end do

end program main
% nvfortran -Minfo=accel test.f90 -acc ; a.out
main:
     14, Generating update device(a(:,:))
     19, Generating Tesla code
         20, !$acc loop gang ! blockidx%x
     19, Generating default present(vec(:))
     24, Generating Tesla code
         25, !$acc loop gang ! blockidx%x
     24, Generating default present(p(1:10))
     30, Generating update self(a(:,:))
    3.000000000000000         4.000000000000000         5.000000000000000
    6.000000000000000         7.000000000000000         8.000000000000000
    9.000000000000000         10.00000000000000         11.00000000000000
    12.00000000000000
    4.000000000000000         5.000000000000000         6.000000000000000
    7.000000000000000         8.000000000000000         9.000000000000000
    10.00000000000000         11.00000000000000         12.00000000000000
    13.00000000000000
    5.000000000000000         6.000000000000000         7.000000000000000
    8.000000000000000         9.000000000000000         10.00000000000000
    11.00000000000000         12.00000000000000         13.00000000000000
    14.00000000000000

Thanks Mat, and for your quick reply.

Sorry for the typos; …tried to correct with a quick edit. I’ve not gotten past all my issues, but for now it seems that the dynamic pointer is working better. …more debugging needed.

Again, appreciate it.

Mat,
I know that this might be impossible to comment on, but I’m getting an error when I run, “FATAL ERROR: variable in data clause is partially present on the device: name=wi$f”.

So, I’ve the following:
module Mod
integer,parameter :: height = 6
real(8),allocatable,continguous,target:: Q(:,:),QX(:,:)

!$acc declare create(Q,QX)
end module Mod

allocate(Q(height,width),QX(height,width)) ! “width” is read from file

real(8),pointer : P(:,:)

P => QX

!$acc parallel loop default(present)
do i=1,width
P(1:1,i) = Q(1:1,i)
P(2,i) = Q(2,i)
P(3,i) = Q(3,i)
P(4,i) = Q(4,i)
P(5,i) = Q(5,i)
end loop

When I compile this, I get the following:
xxxx, Generating default present(p(1:5,:))
Generating implicit copy(p$f(:)) if not already present

Just a stab in the dark, but any guesses? I’m a bit worried about the compiler output, as it should be p(1:6,:), right?

Also: p$f is the variable device name. Right?

Not quite. The “$” is referencing a field in the pointer’s descriptor, though I don’t know offhand which field “f” is.

Though it might be something relate information needed for the array syntax since if you change “P(1:1,i) = Q(1:1,i)” to “P(1,i) = Q(1,i)”, the implicit copy will go away.

“FATAL ERROR: variable in data clause is partially present on the device: name=wi$f”

Often partially present errors occur when the size of an array changes but that change isn’t reflected on the device. Though, I’d need a reproducers to understand what’s happening here.

-Mat

I was able to get the program away by removing the pointer and just using the target; but it would be nice to have the original code working.

The original code was a bit more complicated than I led: It was instead using a variable that was set in this case to be 1, as in "P(1:foo,i) = Q(1:foo,i).

I do appreciate there’s not much that you can do w/o a cutdown. Thanks for all.