I am trying to develop code for Monte Carlo simulations and want to use the curand library in my fortran code. I wrote a test program based off the example device code at: https://www.pgroup.com/doc/pgi17cudaint.pdf just to get a feel for how it interface with CUDA’s C++ libraries.
From my understanding, the error that the compiler has been giving me is that it is having trouble linking to the library:
nvlink error : Undefined reference to '__pgicudalib_curandUniformXORWOW' in 'test.o'
nvlink error : Undefined reference to '__pgicudalib_curandInitXORWOW' in 'test.o'
I would like to know how I can properly link the curand library or edit my code to make this work. I’m sure I am making some stupid mistake.
The interface looks like this:
module curan_m
integer, public :: CURAND_RNG_PSEUDO_DEFAULT = 100
integer, public :: CURAND_RNG_PSEUDO_XORWOW = 101
integer, public :: CURAND_RNG_PSEUDO_MTGP32 = 141
integer, public :: CURAND_RNG_QUASI_DEFAULT = 200
integer, public :: CURAND_RNG_QUASI_SOBOL32 = 201
integer, public :: CURAND_RNG_QUASI_SOBOL64 = 203
integer, public:: CURAND_ORDERING_PSEUDO_BEST = 100
integer, public:: CURAND_ORDERING_PSEUDO_SEEDED = 102
integer, public :: CURAND_ORDERING_QUASI_DEFAULT = 201
interface curandCreateGenerator
subroutine curandCreateGenerator ( &
generator, rng_type) &
bind(C,name='curandCreateGenerator')
use iso_c_binding
integer(c_size_t) :: generator
integer(c_int), value :: rng_type
end subroutine curandCreateGenerator
end interface curandCreateGenerator
interface curandSetGeneratorOrdering
subroutine curandSetGeneratorOrdering ( &
generator, order) &
bind(C,name='curandSetGeneratorOrdering')
use iso_c_binding
integer(c_size_t) :: generator
integer(c_int), value :: order
end subroutine curandSetGeneratorOrdering
end interface curandSetGeneratorOrdering
interface curandSetPseudoRandomGeneratorSeed
subroutine curandSetPseudoRandomGeneratorSeed ( &
generator, seed) &
bind(C,name='curandSetPseudoRandomGeneratorSeed')
use iso_c_binding
integer(c_size_t), value :: generator
integer(c_long_long), value :: seed
end subroutine curandSetPseudoRandomGeneratorSeed
end interface curandSetPseudoRandomGeneratorSeed
interface curandGenerateUniform
subroutine curandGenerateUniform ( &
generator, odata, numele) &
bind(C,name='curandGenerateUniform')
use iso_c_binding
integer(c_size_t), value :: generator
!pgi$ ignore_tr odata
real(c_float), device:: odata(*)
integer(c_size_t), value :: numele
end subroutine curandGenerateUniform
subroutine curandGenerateUniformDouble ( &
generator, odata, numele) &
bind(C,name='curandGenerateUniformDouble')
use iso_c_binding
integer(c_size_t), value :: generator
!pgi$ ignore_tr odata
real(c_double), device:: odata(*)
integer(c_size_t), value :: numele
end subroutine curandGenerateUniformDouble
end interface curandGenerateUniform
interface curandDestroyGenerator
subroutine curandDestroyGenerator (generator) &
bind(C,name='curandDestroyGenerator')
use iso_c_binding
integer(c_size_t), value :: generator
end subroutine curandDestroyGenerator
end interface curandDestroyGenerator
interface curand_init
attributes(device) subroutine curand_init(seed,sequence,offset,state) &
bind(C,name='curand_init')
use iso_c_binding
integer(c_long_long),value :: seed
integer(c_long_long),value :: sequence
integer(c_long_long),value :: offset
!pgi$ ignore_tr state
real(c_float), device :: state(*)
end subroutine curand_init
attributes(device) subroutine curandInitXORWOW(seed, sequence, offset, state)
integer(8) :: seed
integer(8) :: sequence
integer(8) :: offset
TYPE(curandStateXORWOW) :: state
end subroutine curandInitXORWOW
end interface curand_init
interface curand
attributes(device) subroutine curand(state) &
bind(C,name='curand')
use iso_c_binding
!pgi$ ignore_tr state
real(c_float),device :: state(*)
end subroutine curand
end interface curand
interface curand_uniform
attributes(device) subroutine curand_uniform(state) &
bind(C,name='curand_uniform')
use iso_c_binding
!pgi$ ignore_tr state
real(c_float),device :: state(*)
end subroutine curand_uniform
attributes(device) subroutine curand_uniform_double(state) &
bind(C,name='curand_uniform_double')
use iso_c_binding
!pgi$ ignore_tr state
real(c_double),device :: state(*)
end subroutine curand_uniform_double
end interface curand_uniform
interface curand_normal
attributes(device) subroutine curand_normal(state) &
bind(C,name='curand_normal')
use iso_c_binding
!pgi$ ignore_tr state
real(c_float),device :: state(*)
end subroutine curand_normal
attributes(device) subroutine curand_normal_double(state) &
bind(C,name='curand_normal_double')
use iso_c_binding
!pgi$ ignore_tr state
real(c_double),device :: state(*)
end subroutine curand_normal_double
end interface curand_normal
end module curan_m
My program is just this:
module monte
use curand_device
contains
attributes(global) subroutine Carlo(dX,n)
use cudafor
implicit none
integer :: seed, offset, seq, id
integer, value :: n
real, device :: dX(4096)
type(curandStateXORWOW) :: h
seed = 1111
offset = 0
seq = 0
call curand_init(seed,offset,seq,h)
id = (blockidx%x-1)*blockdim%x + threadidx%x
if (id < n) then
dX(id) = curand_uniform(h)
end if
end subroutine Carlo
end module monte
program rnd
use cudafor
use curand_device
use curan_m
real:: x(4096)
real, device :: dX(4096)
integer :: n = 4096
x = 0
dX = x
call Carlo<<<32,128>>>(dX,n)
x = dX
print *, x(1)
end program rnd
And I compiled it using:
pgfortran -c curan_m.cuf
pgfortran -o test test.cuf curan_m.o -lcurand