I am trying to create a Linked list in Cuda Fortran, but when I am trying to call device functions from the kernel, I get a compilation error. Could someone please explain to me why …?
Sample code calling function InsertList is pasted below.
file :p5.f95
MODULE ListModule
IMPLICIT NONE
TYPE ListElem
REAL :: value;
TYPE(ListElem), POINTER :: next;
END TYPE ListElem
CONTAINS
ATTRIBUTES(DEVICE) FUNCTION InsertList(head, elem)
IMPLICIT NONE
type( ListElem ), pointer :: head, elem
type( ListElem ), pointer :: InsertList
elem%next => head
InsertList => elem
END FUNCTION InsertList
END MODULE
MODULE Test
CONTAINS
ATTRIBUTES(GLOBAL) SUBROUTINE KERNEL()
USE ListModule
IMPLICIT NONE
type( ListElem ), pointer :: head
type( ListElem ), pointer :: newElem, h
integer :: i,N = 4
INTEGER(KIND=4),ALLOCATABLE::ND(:)
nullify( head )
allocate( newElem )
newElem%value=1
PRINT*,newElem%value
head => InsertList(head, newElem)
END SUBROUTINE
END MODULE Test
PROGRAM LinkedList
USE TEST
USE CUDAFOR
integer :: N
CALL KERNEL<<<1,1>>>()
N=cudaDeviceSynchronize()
END PROGRAM LinkedList
compilation command:pgf95 -cuda -gpu=rdc p5.f95
Error:
nvvmCompileProgram error 9: NVVM_ERROR_COMPILATION.
Error: /tmp/pgcudaforNnQ1wgcS2LZ.gpu (27, 26): parse use of undefined value '%sym_insertlist_p_356'
ptxas /tmp/pgcudaforxnQf5cb9zEu.ptx, line 1; fatal : Missing .version directive at start of file '/tmp/pgcudaforxnQf5cb9zEu.ptx'
ptxas fatal : Ptx assembly aborted due to errors
NVFORTRAN-F-0155-Compiler failed to translate accelerator region (see -Minfo messages): Device compiler exited with error status code (p5.f95: 1)
NVFORTRAN/x86-64 Linux 21.7-0: compilation aborted
Related
I am trying to create a generic function in Fortran based on the value to be returned, that is, depending on if the output of the function is to be assigned to a single precision real or to a double precision real. The code is:
MODULE kk_M
USE ISO_FORTRAN_ENV
IMPLICIT NONE
INTEGER, PARAMETER :: sp = REAL32
INTEGER, PARAMETER :: dp = REAL64
INTERFACE use_func
MODULE PROCEDURE use_sp_func
MODULE PROCEDURE use_dp_func
END INTERFACE use_func
INTERFACE use_sub
MODULE PROCEDURE use_sp_sub
MODULE PROCEDURE use_dp_sub
END INTERFACE use_sub
CONTAINS
FUNCTION use_sp_func() RESULT(res)
REAL(KIND=sp) :: res
res = 5._sp
END FUNCTION use_sp_func
FUNCTION use_dp_func() RESULT(res)
REAL(KIND=dp) :: res
res = 5._dp
END FUNCTION use_dp_func
SUBROUTINE use_sp_sub(res)
REAL(KIND=sp), INTENT(OUT) :: res
res = 5._sp
END SUBROUTINE use_sp_sub
SUBROUTINE use_dp_sub(res)
REAL(KIND=dp), INTENT(OUT) :: res
res = 5._dp
END SUBROUTINE use_dp_sub
END MODULE kk_M
PROGRAM kk
USE kk_M
IMPLICIT NONE
REAL(KIND=sp) :: num_sp
REAL(KIND=dp) :: num_dp
num_sp = use_func()
WRITE(*,*) num_sp
num_dp = use_func()
WRITE(*,*) num_dp
CALL use_sub(num_sp)
WRITE(*,*) num_sp
CALL use_sub(num_dp)
WRITE(*,*) num_dp
END PROGRAM kk
With the generic subroutines the code compiles and works, but when I add the generic functions it does not compile. I get the following error message with gfortran:
kk.f90:22:3:
FUNCTION use_sp_func() RESULT(res)
1
kk.f90:27:3:
FUNCTION use_dp_func() RESULT(res)
2
Error: Ambiguous interfaces in generic interface 'use_func' for ‘use_sp_func’ at (1) and ‘use_dp_func’ at (2)
kk.f90:46:7:
USE kk_M
1
Fatal Error: Can't open module file ‘kk_m.mod’ for reading at (1): No existe el archivo o el directorio
compilation terminated.
It looks like the compiler cannot distinguish between both functions based on the value to be returned. Is there some way to achieve this?
You cannot distinguish specific functions in a generic interface by their return value. There is no way how the compiler can see what return value type is to be used. A Fortran expression is always evaluated without the surrounding context. Fortran generic disambiguation is based by TKR (type, kind, rank) resolution only using the procedure arguments, not using the return value.
When you have
use_func()
there is no way for the compiler to know which of those two functions should be called. Even when it is used directly in an assignment
x = use_func()
it is evaluated separately. In general, function calls can appear in various complicated expressions. E.g. use_func(use_func()) + use_func(), which one would be which?
This is the reason why several intrinsic functions have another argument that specifies the return type. For example, the transfer() function has a second argument that specifies which type should be returned. Otherwise the compiler would not be able to find out.
Following the advice by Vladimir F, I had a look at the transfer intrisic function and added a mold parameter to my functions to set the return type.
If any input argument to the functions were real they could be used to set the return type as High Performace Mark stated, but since this is not my case I finally used the mold variable.
Now it compiles and work. The code is:
MODULE kk_M
USE ISO_FORTRAN_ENV
IMPLICIT NONE
INTEGER, PARAMETER :: sp = REAL32
INTEGER, PARAMETER :: dp = REAL64
INTERFACE use_func
MODULE PROCEDURE use_sp_func
MODULE PROCEDURE use_dp_func
END INTERFACE use_func
INTERFACE use_sub
MODULE PROCEDURE use_sp_sub
MODULE PROCEDURE use_dp_sub
END INTERFACE use_sub
CONTAINS
FUNCTION use_sp_func(mold) RESULT(res)
REAL(KIND=sp),INTENT(IN) :: mold
REAL(KIND=sp) :: res
IF (.FALSE.) res = mold !To avoid compilation warning about unused variable
res = 5._sp
END FUNCTION use_sp_func
FUNCTION use_dp_func(mold) RESULT(res)
REAL(KIND=dp),INTENT(IN) :: mold
REAL(KIND=dp) :: res
IF (.FALSE.) res = mold !To avoid compilation warning about unused variable
res = 5._dp
END FUNCTION use_dp_func
SUBROUTINE use_sp_sub(res)
REAL(KIND=sp), INTENT(OUT) :: res
res = 5._sp
END SUBROUTINE use_sp_sub
SUBROUTINE use_dp_sub(res)
REAL(KIND=dp), INTENT(OUT) :: res
res = 5._dp
END SUBROUTINE use_dp_sub
END MODULE kk_M
PROGRAM kk
USE kk_M
IMPLICIT NONE
REAL(KIND=sp) :: num_sp
REAL(KIND=dp) :: num_dp
num_sp = use_func(1._sp)
WRITE(*,*) num_sp
num_dp = use_func(1._dp)
WRITE(*,*) num_dp
CALL use_sub(num_sp)
WRITE(*,*) num_sp
CALL use_sub(num_dp)
WRITE(*,*) num_dp
END PROGRAM kk
I'm using Fortran and gfortran 4.7.2. I'm pretty new to Fortran and searched intensively for a solution to my problem. The program I want to use has many functions, which should be aliased based on the given conditions correctly. For that I want to use pointer.
The main program creates pointer based on the interface in the module func_interface. Based on which function I want to alias, I wrote a subroutine which should change the pointer to desired function. Nevertheless I receive a 'Memory Access Error' when trying to run the program - obviously because I didn't understand the pointers in Fortran or how to pass them to a subroutine in order to change them inside the subroutine correctly.
Has somebody an idea how to change the program in order to use it this way? The program is as below.
MODULE func_interface
ABSTRACT INTERFACE
FUNCTION func(z)
DOUBLE PRECISION func
DOUBLE PRECISION, INTENT (IN) :: z
END FUNCTION func
END INTERFACE
END MODULE func_interface
SUBROUTINE assign_pointer(i, func_ptr)
USE func_interface
IMPLICIT NONE
PROCEDURE (func), POINTER, INTENT(INOUT) :: func_ptr => NULL ()
INTEGER, INTENT (IN) :: i
DOUBLE PRECISION f1, f2
EXTERNAL f1, f2
SELECT CASE ( i )
CASE ( 1 )
func_ptr => f1
RETURN
CASE ( 2 )
func_ptr => f2
RETURN
END SELECT
END SUBROUTINE assign_pointer
DOUBLE PRECISION FUNCTION f1(x)
IMPLICIT NONE
DOUBLE PRECISION, INTENT(IN) :: x
f1 = 2*x
END FUNCTION f1
DOUBLE PRECISION FUNCTION f2(x)
IMPLICIT NONE
DOUBLE PRECISION, INTENT(IN) :: x
f2 = 4*x
END FUNCTION f2
PROGRAM pointer_test
USE func_interface
IMPLICIT NONE
DOUBLE PRECISION f1, f2
EXTERNAL f1, f2
PROCEDURE (func), POINTER :: func_ptr => NULL ()
CALL assign_pointer( 1, func_ptr )
WRITE(*, '(1PE12.4)') func_ptr(5.2D1)
END PROGRAM pointer_test
Error Message :
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x7F32AFB92667
#1 0x7F32AFB92C34
#2 0x7F32AF14F19F
#3 0x4007CE in assign_pointer_
#4 0x40085B in MAIN__ at pointer_test.f90:0
Speicherzugriffsfehler
The answer by innoSPG gives the essential aspects of the solution: extend what the module includes to make an explicit interface available in the main program for the subroutine assign_pointer. I'll give a little more detail and address a difficulty suggested in a comment.
First, look at the (simplified) subroutine definition:
subroutine assign_pointer(i, func_ptr)
use func_interface ! func is given in here
procedure(func), pointer, intent(inout) :: func_ptr
integer, intent(in) :: i
end subroutine assign_pointer
The dummy argument func_ptr of this subroutine has the pointer attribute. As given elsewhere such an attribute requires an explicit interface in a scope referencing the subroutine. That other answer shows how that can be arranged (and there are many other questions and answer around that to be found).
The subroutine and functions are external procedures and do not automatically have an explicit interface available.
You then asked
Although I thought that using USE func_interface is explicitly defining the pointer.. what is the mistake in this thought?
The module func_interface contains the abstract interface func. This abstract interface is used in the declaration of the procedure pointers. However, it's the subroutine assign_pointer, as noted above, which is problematic. One can see that the dummy argument
procedure(), pointer, intent(inout) :: func_ptr
(which has implicit interface) is wholly independent of the module, but still there is a requirement for the subroutine's interface to be explicit in a calling scope.
So, the abstract interface is only one small part of the way to get this program to work.
And even that abstract interface may be unnecessary. Depending on how f1 and f2 are to be made available we may be able to write the module as:
module full_mod
contains
function f1(..)
end function f1
function f2(..)
end function f2
subroutine assign_pointer(i, func_ptr)
procedure(f1), pointer, intent(inout) :: func_ptr
integer, intent(in) :: i
! f1 and f2 available from the host module
end subroutine assign_pointer
end module
use full_mod
implicit none
procedure(f1), pointer :: func_ptr => NULL()
...
end
That is, f1 and f2 may themselves be used to give the interface of a procedure pointer, when those functions are in scope.
And a final note: the dummy argument func_ptr may not have explicit initialization. A line such as
procedure(func), pointer, intent(inout) :: func_ptr => NULL()
is trying to do exactly that. It is trying to say that func_ptr is initially disassociated. As can be seen in my code lump above the => NULL() should be removed. Either standard pointer assignment should be used
procedure(func), pointer, intent(inout) :: func_ptr
func_ptr => NULL()
or we can note that the explicit initialization in the main program
procedure(func), pointer :: func_ptr => NULL()
is allowed and as the dummy argument has the intent(inout) attribute it retains that not-associated status on entry to the subroutine.
The comments from francescalus and Vladimir are what you need. Below I suggest a simple reorganization of your code where I put all the functions in the existing module. I also commented the external statements because they become useless with functions in a module.
You will find the following comment on many fortran question on S.O. but it is worth putting it here again. When starting new project, you should stick to modern programming techniques. It is better to put procedures in module instead of using the external. That will automatically build the interface for you and do some checking at compile time.
Now if you are going to use some functions that exist already and you are not modifying them, you need to supply explicit interface.
Thank to francescalus comment, I modify the call to the selected function in the main program, to call only if it is initialized. To avoid that, the default case can be processed in the procedure assign_pointer.
MODULE func_interface
ABSTRACT INTERFACE
FUNCTION func(z)
DOUBLE PRECISION func
DOUBLE PRECISION, INTENT (IN) :: z
END FUNCTION func
END INTERFACE
CONTAINS
SUBROUTINE assign_pointer(i, func_ptr)
! USE func_interface
IMPLICIT NONE
PROCEDURE (func), POINTER, INTENT(INOUT) :: func_ptr => NULL ()
INTEGER, INTENT (IN) :: i
!DOUBLE PRECISION f1, f2
!EXTERNAL f1, f2
SELECT CASE ( i )
CASE ( 1 )
func_ptr => f1
RETURN
CASE ( 2 )
func_ptr => f2
RETURN
END SELECT
END SUBROUTINE assign_pointer
DOUBLE PRECISION FUNCTION f1(x)
IMPLICIT NONE
DOUBLE PRECISION, INTENT(IN) :: x
f1 = 2*x
END FUNCTION f1
DOUBLE PRECISION FUNCTION f2(x)
IMPLICIT NONE
DOUBLE PRECISION, INTENT(IN) :: x
f2 = 4*x
END FUNCTION f2
END MODULE func_interface
PROGRAM pointer_test
USE func_interface
IMPLICIT NONE
!DOUBLE PRECISION f1, f2
!EXTERNAL f1, f2
PROCEDURE (func), POINTER :: func_ptr => NULL ()
CALL assign_pointer( 1, func_ptr )
IF(associated(func_ptr))then
WRITE(*, '(1PE12.4)') func_ptr(5.2D1)
ELSE
! manage the cas
END IF
END PROGRAM pointer_test
I created a fortran 90 program that I used on a linux machine and compiled using gfortran. It worked fine on the linux machine with gfortran but provides the error
error 327 - In the INTERFACE to SECANTMETHOD (from MODULE SECMETH), the ninth dummy argument (F) was of type REAL(KIND=2) FUNCTION, whereas the actual argument is of type REAL(KIND=2)
when using the Plato compiler (FTN95). Does anyone know how I would need to change my code to work in Plato? I tried to read up on this error and there was some mention of pointers but from what I tried that did not work. I have figured out some workarounds but they make it so that the subroutine can no longer accept any function as an argument - which is pretty much useless. Any help would be greatly appreciated. My code is below.
!--! A module to define a real number precision.
module types
integer, parameter :: dp=selected_real_kind(15)
end module types
module secFuncs
contains
function colebrookWhite(T)
use types
real(dp) :: colebrookWhite
real(dp), intent(in) :: T
colebrookwhite=25-T**2
return
end function colebrookWhite
end module secFuncs
module secMeth
contains
subroutine secantMethod(xolder,xold,xnew,epsi1,epsi2,maxit,exitFlag,numit,f)
use types
use secFuncs
implicit none
interface
function f(T)
use types
real(dp) :: f
real(dp), intent(in) :: T
end function f
end interface
real(dp), intent(in) :: epsi1, epsi2
real(dp), intent(inout) :: xolder, xold
real(dp), intent(out) :: xnew
integer, intent(in) :: maxit
integer, intent(out) :: numit, exitFlag
real(dp) :: fxold, fxolder, fxnew
integer :: i
fxolder = f(xolder)
fxold = f(xold)
i = 0
do
i = i + 1
xnew = xold - fxold*(xold-xolder)/(fxold-fxolder)
fxnew = f(xnew)
if (i == maxit) then
exitFlag = 1
numit = i
return
else if (abs(fxnew) < epsi1) then
exitFlag = 2
numit = i
return
else if (abs(xnew - xold) < epsi2) then
exitFlag = 3
numit = i
return
end if
xolder = xold
xold = xnew
fxolder = fxold
fxold = fxnew
end do
end subroutine secantMethod
end module secMeth
program secantRoots
use types
use secMeth
use secFuncs
implicit none
real(dp) :: x1, x2, xfinal, epsi1, epsi2
integer :: ioerror, maxit, numit, exitFlag
do
write(*,'(A)',advance="no")"Please enter two initial root estimates, 2epsi's, and maxit: "
read(*,*,iostat=ioerror) x1, x2, epsi1, epsi2, maxit
if (ioerror /= 0) then
write(*,*)"Invalid input."
else
exit
end if
end do
call secantMethod(x1,x2,xfinal,epsi1,epsi2,maxit,exitFlag,numit,colebrookWhite)
if (exitFlag == 1) then
write(*,*)"The maximum number of iterations was reached."
else if (exitFlag == 2) then
write(*,'(a,f5.3,a,i3,a)')"The root is ", xfinal, ", which was reached in ", numit, " iterations."
else if (exitFlag == 3) then
write(*,'(a,i3,a)')"There is slow or no progress at ", numit, " iterations."
end if
end program secantRoots
Current gfortran detects the error in the call to the secantMethod procedure, where you have parentheses, but no argument list, following the colebrookWhite function name.
If you want to pass a function as an argument (as opposed to the result of evaluating a function), which is what you want to do here, you do not follow the function name with a parenthesis pair.
call secantMethod(x1,x2,xfinal,epsi1,epsi2,maxit,exitFlag,numit,colebrookWhite )
! ^
I ended up just switching from Plato to Geany IDE (I actually like Geany WAY better now that I've used it for a couple hours), setting up gfortran with Geany, and the code works with that setup. I'm guessing the reason I'm getting the error with Plato is that its compiler is actually a fortran95 compiler while gfortran is a fortran90 compiler. It took a while to get everything working but once I downloaded mingw-w64 for gfortran and set the path user (not system) environment variable to the correct location everything works great. I would still be interested in seeing if there is a way to get the code working with the FTN95 compiler, but in the end I'm still sticking with gfortran and Geany.
I am attempting to use PGFortran for CUDA. I installed PGFortran on my computer and linked everything up to the best of my knowledge. To get going I decided to follow a tutorial listed here. When trying to compile the code:
module mathOps
contains
attributes(global) subroutine saxpy(x, y, a)
implicit none
real :: x(:), y(:)
real, value :: a
integer :: i, n
n = size(x)
i = blockDim%x * (blockIdx%x - 1) + threadIdx%x
if (i <= n) y(i) = y(i) + a*x(i)
end subroutine saxpy
end module mathOps
program testSaxpy
use mathOps
use cudafor
implicit none
integer, parameter :: N = 40000
real :: x(N), y(N), a
real, device :: x_d(N), y_d(N)
type(dim3) :: grid, tBlock
tBlock = dim3(256,1,1)
grid = dim3(ceiling(real(N)/tBlock%x),1,1)
x = 1.0; y = 2.0; a = 2.0
x_d = x
y_d = y
call saxpy<<<grid, tblock="">>>(x_d, y_d, a)
y = y_d
write(*,*) 'Max error: ', maxval(abs(y-4.0))
end program testSaxpy
I got:
PGF90-S-0034-Syntax error at or near identifier saxpy (main.cuf: 29)
0 inform, 0 warnings, 1 severes, 0 fatal for testsaxpy
The error points to the line call saxpy<<<grid, tblock="">>>(x_d, y_d, a). For some reason it apparently hates the fact that I am using <<< and >>>? Going by the tutorial those triple chevrons are meant to be there:
The information between the triple chevrons is the execution
configuration, which dictates how many device threads execute the
kernel in parallel.
Removing these chevrons would not make any sense since they are the purpose of the program. So why does PGFortran dislike this?
As for the compilation. I have followed the tutorial by using
pgf90 -o saxpy main.cuf. But since that gave an error I also tried pgf90 -Mcuda -o saxpy main.cuf. Same results.
There does seem to be a text error in that blog at the kernel invocation line:
call saxpy<<<grid, tblock="">>>(x_d, y_d, a)
tblock="" is not correct. You'll notice elsewhere in that blog text, the kernel invocation line is given correctly as:
call saxpy<<<grid,tBlock>>>(x_d, y_d, a)
So if you change that line accordingly in your actual code, I think you'll have better results.
Why does GCC not warn me when I forget to specify the return type of a interface function? For me this behavior seams unexpected. What do you say to this?
This is the test-program (uncoment Line 6 and it works as it should):
program returntest
implicit none
interface
function givehalf(Y)
double precision :: Y
!double precision :: givehalf !<-- Uncomment this line
end function givehalf
end interface
double precision :: temp
temp=givehalf(5.151515d0)
print*, 'result= ',temp
end program returntest
function givehalf(Y)
implicit none
double precision :: Y
double precision :: givehalf
print*, 'Y= ',Y
givehalf=Y/2.0d0
print*, 'return Y/2',givehalf
return
end function givehalf
The result is this:
user#bapf028dl:/media/disk> gfortran44 -Wall return-test.f90
user#bapf028dl:/media/disk> ./a.out
Y= 5.1515149999999998
return Y/2 2.5757574999999999
result= -1.0579199790954590
user#bapf028dl:/media/disk> ifort return-test.f90
user#bapf028dl:/media/disk> ./a.out
Y= 5.15151500000000
return Y/2 2.57575750000000
result= 2.57575750350952
edit: It is really a bug. It gives a type error in gfortran 4.6 and 4.7.
Also I would recommend you to use a module for your functions. You have only one place to change.
This is not a bug. The interface body inside an interface block forms a separate scope, so you should include an implicit none statement there to prevent yourself from making such errors. Without it the implicit typing rules are in effect, so the function is expected to return a real.
interface
function givehalf(Y)
implicit none !<-- now you should get an error during compilation
double precision :: Y
!double precision :: givehalf !<-- Uncomment this line
end function givehalf
end interface