2016-02-02 128 views
1

将CUDA代码与Fortran和C代码(混合语言编程)结合使用的方式是什么。 Fortran代码调用一个C函数,该函数又调用CUDA内核。例如。混合语言CUDA编程

Fortran函数:

if(flag.eq.1) call c_func 

C函数:

void c_func() 
{ 
    /* copy data to device 
    .... 
    cuda_kernel<<< kernel parameters>>>(); 

    /* copy data from device to Host 
    ........ 
} 

什么是编译这种类型的代码的方式吗?

+2

你只想调用C函数(调用一些CUDA,但你不CUDA从Fortran的直接互动?)还有的吨关于这个问题。只需在右上角的搜索行中搜索C和Fortran即可。 http://stackoverflow.com/questions/tagged/fortran+c你有没有尝试过自己? –

+0

或者如果你需要更多的参与,你应该提供更多的信息到底应该是什么。 –

回答

3

我相信有很多可能的方法来解决这个问题。但是按照你给出的例子,它应该是相当简单的。

任务可分为两个部分:

  1. 如何调用C函数从Fortran语言
  2. 如何从C
  3. 调用CUDA功能

我认为你的问题很可能围绕围绕第一部分,因此它并不是CUDA特有的。对于第二部分课程,这里有许多cuda标签的示例,以及cuda sample codesprogramming guide

可能有助于精简第一部分的一种方法是使用许多当前Fortran发行版中内置的ISO_C_BINDINGbuiltin module。这个模块定义了许多在C和Fortran之间传递数据的类型。

然后,您可以创建一个INTERFACE块来定义您希望从fortran调用的C函数的参数。下面是一个样例:

$ cat cuda_test.f90 
!======================================================================================================================= 
!Interface to cuda C functions 
!======================================================================================================================= 
module cuda_test 

    use iso_c_binding 

    interface 
    ! 
    integer(c_int) function cudatestfunc(idata, isize) bind(C, name="cudatestfunc") 
     use iso_c_binding 
     implicit none 
     type(c_ptr),value :: idata 
     integer(c_int),value :: isize 
    end function cudatestfunc 
    ! 
    end interface 

end module cuda_test 



!======================================================================================================================= 
program main 
!======================================================================================================================= 

    use iso_c_binding 

    use cuda_test 

    type(c_ptr) :: mydata 
    integer*4, target :: mysize,myresult 
    integer*4,dimension(:),allocatable,target :: darray 
    mysize = 100 
    allocate(darray(mysize)) 
    darray = (/ (1, I = 1, mysize) /) 
    mydata = c_loc(darray) 
    myresult = cudatestfunc(mydata, mysize) 

    write (*, '(A, I10)') " result: ", myresult 
    write (*,*) 

end program main 
$ cat cuda_test.cu 
#include <stdio.h> 

#define cudaCheckErrors(msg) \ 
    do { \ 
     cudaError_t __err = cudaGetLastError(); \ 
     if (__err != cudaSuccess) { \ 
      fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \ 
       msg, cudaGetErrorString(__err), \ 
       __FILE__, __LINE__); \ 
      fprintf(stderr, "*** FAILED - ABORTING\n"); \ 
      exit(1); \ 
     } \ 
    } while (0) 

__global__ void testkernel(int *data, int size){ 

    for (int i = 1; i < size; i++) data[0] += data[i]; 
} 
extern "C" { 
int cudatestfunc(int *data, int size){ 

    int *d_data; 
    cudaMalloc(&d_data, size*sizeof(int)); 
    cudaMemcpy(d_data, data, size*sizeof(int), cudaMemcpyHostToDevice); 
    testkernel<<<1,1>>>(d_data, size); 
    int result; 
    cudaMemcpy(&result, d_data, sizeof(int), cudaMemcpyDeviceToHost); 
    cudaCheckErrors("cuda error"); 
    return result; 
} 
} 
$ gfortran -c cuda_test.f90 -o cuda_testf.o     
$ nvcc -c cuda_test.cu -o cuda_testc.o      
$ gfortran cuda_testc.o cuda_testf.o -o cuda_test -L/usr/local/cuda/lib64 -lcudart -lstdc++ 
$ ./cuda_test 
    result:  100 

$ 

注意事项/(在RHEL 6.2,GNU 4.4.7,CUDA 7.0测试)其他选项:

  1. 如果你只需要调用CUDA运行时API函数,您可以直接从Fortran中调用这些函数,而无需任何C/C++文件(如果您创建自己的绑定)。示例here

  2. 如果您只需调用CUSPARSE或CUBLAS库函数,则会为您创建一些绑定,这些绑定将包含在CUDA分发中。 Linux上缺省的那些绑定安装在/usr/local/cuda/srcthe cublas documentation包含cublas绑定的工作示例。

  3. 如果您需要直接从fortran中调用其他CUDA库函数,创建自己的绑定并不难。对于CUSOLVER中的一组简单操作,一个可行的示例是here

  4. 你也可以直接写CUDA Fortran的代码。 (Here就是一个例子。)这需要CUDA Fortran compiler from PGI

  5. 您也可以编写OpenACC Fortran代码。这需要一个可用的OpenACC编译器,例如来自PGI的编译器。一个PGI免费为学术使用或试用版可供here