Я уверен, что существует много возможных подходов к этому. Но, следуя приведенному примеру, это должно быть довольно просто.
Задача может быть разделена на две части:
- Как вызвать функцию C из Fortran
- Как вызвать функцию CUDA от C
Я думаю, ваш вопрос, вероятно, вращается вокруг первой части, и, как таковая, она не является специфичной для CUDA. Для второй части, конечно, здесь много примеров на теге cuda, а также cuda sample codes и programming guide.
Один из способов, который может помочь упростить первую часть, - использовать ISO_C_BINDING
builtin 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/Другие варианты:
Если вам нужно только позвонить CUDA runtime API, вы можете вызывать их непосредственно из fortran, не требуя каких-либо файлов C/C++ (если вы создаете свои собственные привязки). Пример here.
Если вам нужно только вызвать функции библиотеки CUSPARSE или CUBLAS, для вас созданы некоторые привязки, которые включены в дистрибутив CUDA. Эти привязки по умолчанию для linux устанавливаются по адресу /usr/local/cuda/src
. Проработанный пример связывания cublas содержится в the cublas documentation.
Если вам нужно вызвать другие функции библиотеки CUDA непосредственно из fortran, создавать свои привязки не сложно. Обрабатываемый пример: here для простого набора операций в CUSOLVER.
Вы также можете написать код CUDA Fortran. (Here - пример.) Для этого требуется CUDA Fortran compiler from PGI.
Вы также можете написать код OpenACC Fortran. Для этого требуется один из доступных компиляторов OpenACC, например, из PGI.PGI бесплатно для академического использования или пробная версия доступна here
Вы хотите просто вызвать функцию C (которая вызывает некоторые CUDA, но не взаимодействуют с CUDA из Fortran непосредственно?) Есть ТОННЫ вопросы об этом. Просто найдите C и Fortran в верхней строке поиска. http://stackoverflow.com/questions/tagged/fortran+c Вы сами что-нибудь пробовали? –
Если вам нужно что-то более активное, вам следует предоставить более подробную информацию о том, что именно должно быть. –