Actually cuda can be programmed in Fortran and C . Cuda C is available in free whereas Cuda Fortran need to be paid for its use. Thus it is better to use cuda C.If our host code is
in C programming language then it is not a problem to use cuda C. However if we have a host code in fortran , then there are two option for us of using cuda fortran or cuda C. As cuda
C is freely available, we can use cuda C.
first we need to install nvida driver and cuda c toolkit . Installation of cuda c and nvidia driver is written in earlier post here.
now the next step to implement cuda is first we need to call the C function from fortran using C wrapper as
1) create a fortran file fortest.f95
PROGRAM fortest ! simple program which creates 2 vectors and adds them in a cuda function IMPLICIT NONE integer*4 :: i integer*4, parameter :: N=8 real*4, Dimension(N) :: a, b DO i=1,N a(i)=i*1.0 b(i)=2.0 END DO print *, 'a = ', (a(i), i=1,N) CALL kernel_wrapper(a, b, N) // calling of C function from fortran print *, 'a + 2 = ', (a(i), i=1,N) END PROGRAM
2) create cuda file names as cudatest.cu
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <cuda.h> #include <cuda_runtime.h> // simple kernel function that adds two vectors __global__ void vect_add(float *a, float *b, int N) { int idx = threadIdx.x; if (idx<N) a[idx] = a[idx] + b[idx]; } // function called from main fortran program
extern "C" void kernel_wrapper_(float *a, float *b, int *Np) { float *a_d, *b_d; // declare GPU vector copies int blocks = 1; // uses 1 block of int N = *Np; // N threads on GPU // Allocate memory on GPU cudaMalloc( (void **)&a_d, sizeof(float) * N ); cudaMalloc( (void **)&b_d, sizeof(float) * N ); // copy vectors from CPU to GPU cudaMemcpy( a_d, a, sizeof(float) * N, cudaMemcpyHostToDevice ); cudaMemcpy( b_d, b, sizeof(float) * N, cudaMemcpyHostToDevice ); // call function on GPU vect_add<<< blocks, N >>>( a_d, b_d, N); // copy vectors back from GPU to CPU cudaMemcpy( a, a_d, sizeof(float) * N, cudaMemcpyDeviceToHost ); cudaMemcpy( b, b_d, sizeof(float) * N, cudaMemcpyDeviceToHost ); // free GPU memory cudaFree(a_d); cudaFree(b_d); return; }3)Compile Fortran file with gfortran complier
$ gfortran –c fortest.f95
4)This create fortest.o file in current working directory
5)Compile CUDA file with nvcc complier
$ nvcc –c cudatest.cu
6) This create cudatest.o file in current working directory
7)Link and compile these two object file
$ gfortran –o <your executable file> fortest.o cudatest.o –L<your CUDA library path> -lcudart –lstdc++
Example:
final_file <my executable file> /usr/local/cuda-6.5/lib64 <my CUDA library path>
$ gfortran –o final_file fortest.o cudatest.o –L /usr/local/cuda-
6.5/lib64 -cudart –lstdc++
8)This will create executable file name as <your executable file>
in current working directory
Example:
In my case final_file is created
9) Finally run this newly created executed file
./<your executable file>
Example:
$ ./final_file
OUTPUT