cuRAND device API Issues 2

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 *)
  • Mat