2016-02-02 4 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. Как вызвать функцию CUDA от C

Я думаю, ваш вопрос, вероятно, вращается вокруг первой части, и, как таковая, она не является специфичной для CUDA. Для второй части, конечно, здесь много примеров на теге cuda, а также cuda sample codes и programming guide.

Один из способов, который может помочь упростить первую часть, - использовать ISO_C_BINDINGbuiltin module, который встроен во многие текущие распределения fortran. Этот модуль определяет несколько типов, которые полезны для передачи данных между C и Fortran.

Затем вы можете создать блок INTERFACE, чтобы определить параметры функции C, которые вы хотите вызвать из fortran. Вот пример работал:

$ 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)

Notes/Другие варианты:

  1. Если вам нужно только позвонить CUDA runtime API, вы можете вызывать их непосредственно из fortran, не требуя каких-либо файлов C/C++ (если вы создаете свои собственные привязки). Пример here.

  2. Если вам нужно только вызвать функции библиотеки CUSPARSE или CUBLAS, для вас созданы некоторые привязки, которые включены в дистрибутив CUDA. Эти привязки по умолчанию для linux устанавливаются по адресу /usr/local/cuda/src. Проработанный пример связывания cublas содержится в the cublas documentation.

  3. Если вам нужно вызвать другие функции библиотеки CUDA непосредственно из fortran, создавать свои привязки не сложно. Обрабатываемый пример: here для простого набора операций в CUSOLVER.

  4. Вы также можете написать код CUDA Fortran. (Here - пример.) Для этого требуется CUDA Fortran compiler from PGI.

  5. Вы также можете написать код OpenACC Fortran. Для этого требуется один из доступных компиляторов OpenACC, например, из PGI.PGI бесплатно для академического использования или пробная версия доступна here

Смежные вопросы