C语言 混合语言 CUDA 编程



CUDA代码与Fortran和C代码(混合语言编程(相结合的方法是什么?Fortran 代码调用一个 C 函数,而 C 函数又调用 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
  ........
}

编译此类代码的方法是什么?

我相信

有很多可能的方法。 但是按照您给出的示例,它应该相当简单。

该任务可以分为两部分:

  1. 如何从 Fortran 调用 C 函数
  2. 如何从 C 调用 CUDA 函数

我认为您的问题可能围绕第一部分,因此它并不是真正的 CUDA 特定。 当然,对于第二部分,cuda 标签上有很多示例,以及 cuda 示例代码和编程指南。

一种可能有助于简化第一部分的方法是使用内置于许多当前 fortran 发行版中的ISO_C_BINDING内置模块。 此模块定义了许多类型,这些类型对于在 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 - ABORTINGn"); 
            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++ 文件(如果您创建自己的绑定(。 这里的例子。

  2. 如果您只需要调用 CUSPARSE 或 CUBLAS 库函数,则可以为您创建一些绑定,这些绑定包含在 CUDA 发行版中。 默认情况下,Linux 上的这些绑定安装在 /usr/local/cuda/src . cublas 绑定的一个工作示例包含在 cublas 文档中。

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

  4. 您也可以直接编写 CUDA Fortran 代码。(下面是一个示例。 这需要PGI的CUDA Fortran编译器。

  5. 你也可以编写OpenACC Fortran代码。 这需要可用的OpenACC编译器之一,例如PGI的编译器。 PGI免费学术使用或试用版可在此处获得

最新更新