2014-03-13 3 views
1

우선, 저는 Fortran/C/CUDA에서 처음 접했습니다. 둘째, cuBLAS를 사용하여 GPU에서 행렬 벡터 곱셈을 수행하는 Fortran/C 프로그램에서 작업하고 있습니다. 행렬 내용을 업데이트해야하기 전에 하나의 행렬에 여러 개의 벡터 (최대 1000 개)를 곱해야합니다. 그러나 현재 가지고있는 버전은 새로운 벡터가 GPU로 전송 될 때마다 매트릭스를 재 할당해야합니다 (매트릭스가 변경되지 않았기 때문에 매우 낭비적이고 느립니다).C에서 Fortran으로 장치 할당 행렬에 대한 포인터를 반환

모든 벡터에 대해 행렬을 재 할당 할 필요없이 행렬에 벡터를 곱할 수 있기를 원합니다. GPU에 행렬을 할당하는 별도의 C 함수를 호출하고 Fortran 주 프로그램에 대한 포인터를 반환 한 다음 행렬 벡터 곱셈을 수행하는 또 다른 C 함수를 호출하는 아이디어가 있습니다. ISO_C_BINDING 사용

는, 변수 i로 부동 소수점 수에 대한 포인터를 리턴 :

type(C_PTR) :: ptr 

및 I는 행렬 벡터 C 함수로이를 전달하려고하면 포트란

C에서

call cudaFunction(ptr,vector, N) 

extern "C" void cudaFunction_(float *mat, float *vector, int *N) 

모든 것이 컴파일되고 실행되지만 cublasSgemv 실행은 실행되지 않습니다. 왜 이런 일이 일어날 지에 대한 아이디어가 있습니까? 관련 게시물 몇 종류를 본 적이 있지만 반환 된 포인터를 C로 보내지 않으므로이 문제가 발생합니다 (믿습니다).

미리 감사드립니다.

답변

2

나는 바퀴를 재발 명하지 말고,이 목적으로 제공되는 cublas fortran bindings을 사용하는 것이 좋습니다.

"썽킹"래퍼는 원하는 것이 아닙니다. Fortran에서 cublas 호출을 사용할 때마다 필요에 따라 암시 적 복사 작업을 수행합니다.

"넌 썽킹"래퍼가 필요하므로 복사 작업을 명시 적으로 제어 할 수 있습니다. Get/SetMatrixGet/SetVector의 포트란을 사용하여 데이터를 앞뒤로 복사 할 수 있습니다.

cublas 설명서에 포함 된 썽킹 래퍼를 사용하는 방법을 보여주는 샘플 코드 (예제 B.2)가 있습니다.

휠을 다시 발명하려는 경우에도 래퍼는 C와 Fortran간에 이동하는 데 필요한 구문 작업을 수행하는 방법을 보여줍니다.

cublasf : 표준 리눅스 CUDA에

은 래퍼는 /usr/local/cuda/src 에 비 썽킹 래퍼 여기 /usr/local/cuda/src/fortran.c

있는 완전히 예를 일이다 있으며, 설치합니다.F :

 program cublas_fortran_example 
     implicit none 
     integer i, j 

c  helper functions 
     integer cublas_init 
     integer cublas_shutdown 
     integer cublas_alloc 
     integer cublas_free 
     integer cublas_set_vector 
     integer cublas_get_vector 
c  selected blas functions 
     double precision cublas_ddot 
     external cublas_daxpy 
     external cublas_dscal 
     external cublas_dcopy 
     double precision cublas_dnrm2 
c  cublas variables 
     integer cublas_status 
     real*8 x(30), y(30) 
     double precision alpha, beta 
     double precision nrm 
     integer*8 d_x, d_y, d_alpha, d_beta, d_nrm 
     integer*8 dsize1, dlength1, dlength2 
     double precision dresult 



     write(*,*) "testing cublas fortran example" 

c  initialize cublas library 
c  CUBLAS_STATUS_SUCCESS=0 
     cublas_status = cublas_init() 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS Library initialization failed" 
     write(*,*) "cublas_status=",cublas_status 
     stop 
     endif 
c  initialize data 
     do j=1,30 
     x(j) = 1.0 
     y(j) = 2.0 
     enddo 
     dsize1 = 8 
     dlength1 = 30 
     dlength2 = 1 
     alpha = 2.0 
     beta = 3.0 
c  allocate device storage 
     cublas_status = cublas_alloc(dlength1, dsize1, d_x) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS device malloc failed" 
     stop 
     endif 
     cublas_status = cublas_alloc(dlength1, dsize1, d_y) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS device malloc failed" 
     stop 
     endif 
     cublas_status = cublas_alloc(dlength2, dsize1, d_alpha) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS device malloc failed" 
     stop 
     endif 
     cublas_status = cublas_alloc(dlength2, dsize1, d_beta) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS device malloc failed" 
     stop 
     endif 
     cublas_status = cublas_alloc(dlength2, dsize1, d_nrm) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS device malloc failed" 
     stop 
     endif 

c  copy data from host to device 

     cublas_status = cublas_set_vector(dlength1, dsize1, x, dlength2, 
    >  d_x, dlength2) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS copy to device failed" 
     write(*,*) "cublas_status=",cublas_status 
     stop 
     endif 
     cublas_status = cublas_set_vector(dlength1, dsize1, y, dlength2, 
    >  d_y, dlength2) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS copy to device failed" 
     write(*,*) "cublas_status=",cublas_status 
     stop 
     endif 

     dresult = cublas_ddot(dlength1, d_x, dlength2, d_y, dlength2) 
     write(*,*) "dot product result=",dresult 

     dresult = cublas_dnrm2(dlength1, d_x, dlength2) 
     write(*,*) "nrm2 of x result=",dresult 

     dresult = cublas_dnrm2(dlength1, d_y, dlength2) 
     write(*,*) "nrm2 of y result=",dresult 

     call cublas_daxpy(dlength1, alpha, d_x, dlength2, d_y, dlength2) 
     cublas_status = cublas_get_vector(dlength1, dsize1, d_y, dlength2, 
    >  y, dlength2) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS copy to host failed" 
     write(*,*) "cublas_status=",cublas_status 
     stop 
     endif 
     write(*,*) "daxpy y(1) =", y(1) 
     write(*,*) "daxpy y(30) =", y(30) 


     call cublas_dscal(dlength1, beta, d_x, dlength2) 
     cublas_status = cublas_get_vector(dlength1, dsize1, d_x, dlength2, 
    >  x, dlength2) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS copy to host failed" 
     write(*,*) "cublas_status=",cublas_status 
     stop 
     endif 
     write(*,*) "dscal x(1) =", x(1) 
     write(*,*) "dscal x(30) =", x(30) 


     call cublas_dcopy(dlength1, d_x, dlength2, d_y, dlength2) 
     cublas_status = cublas_get_vector(dlength1, dsize1, d_y, dlength2, 
    >  y, dlength2) 
     if (cublas_status /= 0) then 
     write(*,*) "CUBLAS copy to host failed" 
     write(*,*) "cublas_status=",cublas_status 
     stop 
     endif 
     write(*,*) "dcopy y(1) =", y(1) 
     write(*,*) "dcopy y(30) =", y(30) 

c  deallocate GPU memory and exit 
     cublas_status = cublas_free(d_x) 
     cublas_status = cublas_free(d_y) 
     cublas_status = cublas_free(d_alpha) 
     cublas_status = cublas_free(d_beta) 
     cublas_status = cublas_free(d_nrm) 
     cublas_status = cublas_shutdown() 
     stop 
     end 

컴파일/실행 :

$ gfortran -c -o cublasf.o cublasf.f 
$ gcc -c -DCUBLAS_GFORTRAN -I/usr/local/cuda/include -I/usr/local/cuda/src -o fortran.o /usr/local/cuda/src/fortran.c 
$ gfortran -L/usr/local/cuda/lib64 -lcublas -o cublasf cublasf.o fortran.o 
$ ./cublasf 
testing cublas fortran example 
dot product result= 60.0000000000000 
nrm2 of x result= 5.47722557505166 
nrm2 of y result= 10.9544511501033 
daxpy y(1) = 4.00000000000000 
daxpy y(30) = 4.00000000000000 
dscal x(1) = 3.00000000000000 
dscal x(30) = 3.00000000000000 
dcopy y(1) = 3.00000000000000 
dcopy y(30) = 3.00000000000000 
$ 

CUDA 5.0, RHEL 5.5

+0

은 매우 빠르고 매우 도움이 응답을 주셔서 감사합니다. 나는 몇 가지 후속 질문을하고있다. 1) 우분투 13.10을 실행 중이며 인텔 포트란 (ifort) 컴파일러를 사용해야합니다. 나는 위의 코드를 실행하면, GCC 및 gfortran을 사용하여, 나는 오류의 다양한 말을 얻을 : fortran.o을 : 기능에서 'cublas_init_' fortran.c :(텍스트 + 0x5을). cublasInit '에 대한 정의되지 않은 참조를 ' (위의 예를 복사하여 붙여 넣었습니까?) 또한, 이것을 ifort와 함께 사용하는 방법이 있습니까? fortran_common.h에서 컴파일러 오류가 계속 발생하고 정의되지 않았습니다. – Dylan

+0

어떤 버전의 CUDA를 사용하고 있습니까? 귀하의 cuda 라이브러리는 어디에 설치되어 있습니까? 링크 작업이 cublas 라이브러리를 찾지 못하는 것 같습니다. 'ifort'에 대해서'-DCUBLAS_GFORTRAN'을'-DCUBLAS_INTEL_FORTRAN'으로 변경하십시오. 다른 변경이 필요할 수도 있습니다. 'ifort'와 함께 사용할 수 있지만 구문 변경이 필요할 수 있습니다. –

+0

나는 Cuda 5.5를 사용하고 있으며 위의 예에서 적절하게 변경된 /usr/local/cuda-5.5/에 설치되어 있습니다. 나는 -DCUBLAS_INTEL_FORTRAN을 시도 할 것이다. 다시 한 번 감사드립니다! – Dylan

관련 문제