Context: First I noticed that the cuRAND interface subroutines cannot be defined in a different module from the one where there will be used, I will really like to understand why? That withstanding in my code I did just that. I really don’t know how CUDA Fortran interfaces with the c cuRAND Library, but there should be fortran equivalent of
#include <curand_kernel.h>
. Because at runtime I get a linking error:
nvlink error : Undefined reference to 'curand_init' in 'host_subs_m.o'
nvlink error : Undefined reference to 'curand_uniform' in 'host_subs_m.o'
where host_subs_m is the module where the cuRAND device API interface subroutines are defined as you can see below:
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
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
Any ideas how I can solve this linking issue?
Hi egodfred,
The problem here is that there isn’t a symbol in the curand library called “curand_init” or “curand_uniform”. Since these routines are compiled by nvcc as C++ code, they will have a C++ mangled names in the library. For example:
% nm libcurand_static.a | grep curand_init
0000000000001e00 T _Z11curand_initPjjP18curandStateSobol32
0000000000001f80 T _Z11curand_initPjjjP27curandStateScrambledSobol32
0000000000001790 T _Z11curand_initPjyP15curandStateTest
0000000000001dd0 T _Z11curand_initPjyP17curandStateXORWOW
0000000000002100 T _Z11curand_initPyyP18curandStateSobol64
0000000000002290 T _Z11curand_initPyyyP27curandStateScrambledSobol64
0000000000000e70 T _Z11curand_inityyyP15curandStateTest
0000000000001db0 T _Z11curand_inityyyP17curandStateXORWOW
000000000000bce0 T _Z11curand_inityyyP19curandStateMRG32k3a
00000000000010c0 T _Z11curand_inityyyP24curandStatePhilox4_32_10
0000000000001cf0 T _Z20_curand_init_scratchyyyP17curandStateXORWOWPj
Made worse here is that there are multiple versions of “curand_init”, depending upon the arguments. You could use the “pggdecode” utility to decipher which symbol corresponds to the version you want and put that name in the “bind”, but the names could change between each CUDA release.
What you might consider doing is writing a C wrapper (compiled with nvcc) for each of these routines that simply calls the cuRAND device routine. It would add a bit overhead but should allow you to link. Granted, I have not tried this myself so don’t know if you would encounter other issues.
Note that typically folks will pre-compute a list of random numbers via the cuRAND host interfaces and then use the list in their kernels.
Hope this helps,
Mat
Didn’t get much information on how to use the pggdecode utility from the pgiref manual. Can you please tell me how I can get the specific names for this routines on my system. Thanks
To use pggdecode, either pipe the mangled names to it, or copy them on to the command line.
For example:
% nm libcurand_static.a | grep curand_init | pggdecode
0000000000001e00 T curand_init(unsigned int *, unsigned int, curandStateSobol32 *)
0000000000001f80 T curand_init(unsigned int *, unsigned int, unsigned int, curandStateScrambledSobol32 *)
0000000000001790 T curand_init(unsigned int *, unsigned long long, curandStateTest *)
0000000000001dd0 T curand_init(unsigned int *, unsigned long long, curandStateXORWOW *)
0000000000002100 T curand_init(unsigned long long *, unsigned long long, curandStateSobol64 *)
0000000000002290 T curand_init(unsigned long long *, unsigned long long, unsigned long long, curandStateScrambledSobol64 *)
0000000000000e70 T curand_init(unsigned long long, unsigned long long, unsigned long long, curandStateTest *)
0000000000001db0 T curand_init(unsigned long long, unsigned long long, unsigned long long, curandStateXORWOW *)
000000000000bce0 T curand_init(unsigned long long, unsigned long long, unsigned long long, curandStateMRG32k3a *)
00000000000010c0 T curand_init(unsigned long long, unsigned long long, unsigned long long, curandStatePhilox4_32_10 *)
0000000000001cf0 T _curand_init_scratch(unsigned long long, unsigned long long, unsigned long long, curandStateXORWOW *, unsigned int *)
% pggdecode
_Z11curand_initPjjP18curandStateSobol32
curand_init(unsigned int *, unsigned int, curandStateSobol32 *)