2014-04-10 3 views
0

저는 cuBLAS 일괄 LU와 cuSPARSE를 사용하는 포트란 코드를 ADI 전처리 기와 함께 BiCG 반복 솔버의 일환으로 배치했습니다. 계산 기능 3.5 및 CUDA 5.5가있는 Kepler K20X를 사용하고 있습니다. 내가 PGI의 CUDA 포트란없이이 일을 해요, 그래서 난 내 자신의 인터페이스를 쓰고 있어요 : 나는 cudaHostAlloc와 호스트의 메모리를 고정 할당Fortran에서 OpenACC와 cublasDgetrfBatched를 연결하는 방법은 무엇입니까?

FUNCTION cublasDgetrfBatched(handle, n, dA, ldda, dP, dInfo, nbatch) BIND(C, NAME="cublasDgetrfBatched") 
    USE, INTRINSIC :: ISO_C_BINDING 
    INTEGER(KIND(CUBLAS_STATUS_SUCCESS)) :: cublasDgetrfBatched 
    TYPE(C_PTR), VALUE :: handle 
    INTEGER(C_INT), VALUE :: n 
    TYPE(C_PTR), VALUE :: dA 
    INTEGER(C_INT), VALUE :: ldda 
    TYPE(C_PTR), VALUE :: dP 
    TYPE(C_PTR), VALUE :: dInfo 
    INTEGER(C_INT), VALUE :: nbatch 
END FUNCTION cublasDgetrfBatched 

을, 행렬의 장치 메모리 및 장치를 포함하는 장치 배열을 할당 행렬 포인터는 비동기식 장치에 각각 행렬 복사 동작을 수행하고 비동기식 하나 우측으로 역 치환을 수행하기 위해 호스트로 다시 분해 행렬과 피봇 복사

REAL(8), POINTER, DIMENSION(:,:,:) :: A 
INTEGER, DIMENSION(:,:), POINTER :: ipiv 
TYPE(C_PTR) :: cPtr_A, cPtr_ipiv 
TYPE(C_PTR), ALLOCATABLE, DIMENSION(:), TARGET :: dPtr_A 
TYPE(C_PTR) :: dPtr_ipiv, dPtr_A_d, dPtr_info 
INTEGER(C_SIZE_T) :: sizeof_A, sizeof_ipiv 

... 

stat = cudaHostAlloc(cPtr_A, sizeof_A, cudaHostAllocDefault) 
CALL C_F_POINTER(cPtr_A, A, (/m,m,nbatch/)) 
stat = cudaHostAlloc(cPtr_ipiv, sizeof_ipiv, cudaHostAllocDefault) 
CALL C_F_POINTER(cPtr_ipiv, ipiv, (/m,nbatch/)) 

ALLOCATE(dPtr_A(nbatch)) 
DO ibatch=1,nbatch 
    stat = cudaMalloc(dPtr_A(ibatch), m*m*sizeof_double) 
END DO 
stat = cudaMalloc(dPtr_A_d, nbatch*sizeof_cptr) 
stat = cublasSetVector(nbatch, sizeof_cptr, C_LOC(dPtr_A(1)), 1, dPtr_A_d, 1) 
stat = cudaMalloc(dPtr_ipiv, m*nbatch*sizeof_cint) 
stat = cudaMalloc(dPtr_info, nbatch*sizeof_cint) 

... 

!$OMP PARALLEL DEFAULT(shared) PRIVATE(stat, ibatch) 
!$OMP DO 
DO ibatch = 1,nbatch 
    stat = cublasSetMatrixAsync(m, m, sizeof_double, C_LOC(A(1,1,ibatch)), m, dPtr_A(ibatch), m, mystream) 
END DO 
!$OMP END DO 
!$OMP END PARALLEL 

... 

stat = cublasDgetrfBatched(cublas_handle, m, dPtr_A_d, m, dPtr_ipiv, dPtr_info, nbatch) 

... 

stat = cublasGetMatrixAsync(m, nbatch, sizeof_cint, dPtr_ipiv, m, C_LOC(ipiv(1,1)), m, mystream) 

!$OMP PARALLEL DEFAULT(shared) PRIVATE(ibatch, stat) 
!$OMP DO 
DO ibatch = 1,nbatch 
    stat = cublasGetMatrixAsync(m, m, sizeof_double, dPtr_A(ibatch), m, C_LOC(A(1,1,ibatch)), m, mystream) 
END DO 
!$OMP END DO 
!$OMP END PARALLEL 

... 

!$OMP PARALLEL DEFAULT(shared) PRIVATE(ibatch, x, stat) 
!$OMP DO 
DO ibatch = 1,nbatch 
    x = rhs(:,ibatch) 
    CALL dgetrs('N', m, 1, A(1,1,ibatch), m, ipiv(1,ibatch), x(1), m, info) 
    rhs(:,ibatch) = x 
END DO 
!$OMP END DO 
!$OMP END PARALLEL 

... 

나는이 마지막 단계를 수행하지 않아도되지만 cublasDtrsmBatched 루틴은 행렬 크기를 32로 제한하고 mi ne는 크기 80입니다 (일괄 처리 된 Dtrsv는 더 좋을 것이지만 이것은 존재하지 않습니다). 여러 개의 개별 cublasDtrsv 커널을 시작하는 비용으로 인해 장치의 back-sub를 수행 할 수 없습니다.

cublasDgetrfBatched 및 cusparseDgtsvStridedBatch 호출 사이에 수행해야하는 다른 작업이 있습니다. 이들 중 대부분은 현재 일괄 처리 수준에서 루프를 병렬 처리하는 데 사용되는 OpenMP를 사용하여 호스트에서 수행되고 있습니다. 행렬의 각각의 행렬 - 벡터 승산 등의 동작의 일부는, 예를 들어 분해되는 OpenACC과 장치에 계산되고 :

!$ACC DATA COPYIN(A) COPYIN(x) COPYOUT(Ax) 

... 

!$ACC KERNELS 
    DO ibatch = 1,nbatch 
    DO i = 1,m 
     Ax(i,ibatch) = zero 
    END DO 
    DO j = 1,m 
     DO i = 1,m 
     Ax(i,ibatch) = Ax(i,ibatch) + A(i,j,ibatch)*x(j,ibatch) 
     END DO 
    END DO 
    END DO 
!$ACC END KERNELS 

... 

!$ACC END DATA 

난과 GPU에 대한 계산 대신하려는 OpenACC,하지만 이렇게하려면 두 인터페이스 할 수 있어야합니다. 다음과 같은 뭔가 :

!$ACC DATA COPYIN(A) CREATE(info,A_d) COPYOUT(ipiv) 

!$ACC HOST_DATA USE_DEVICE(A) 
DO ibatch = 1,nbatch 
    A_d(ibatch) = acc_deviceptr(A(1,1,ibatch)) 
END DO 
!$ACC END HOST_DATA 

... 

!$ACC HOST_DATA USE_DEVICE(ipiv,info) 
stat = cublasDgetrfBatched(cublas_handle, m, A_d, m, ipiv, info, nbatch) 
!$ACC END HOST_DATA 

... 

!$ACC END DATA 

내가 host_data 대부분의 경우에 적합 할 것 host_device 조항으로 구성 알지만, 실제로 장치에 CUBLAS에 행렬에 대한 포인터를 포함하는 장치 배열을 전달해야하기 때문에, 계속 진행하는 방법을 모르겠습니다.

아무도 통찰력을 제공 할 수 있습니까?

감사합니다.

답변

1

!! 장치에 모든 것을 넣으십시오! ! $ ACC DATA COPYIN (A) CREATE (info, A_d) COPYOUT (ipiv)

!! 장치 A_d 어레이 채우는! ACC 병렬 루프 가 A_d (ibatch)가 = nbatch ibatch = 1, (1,1, ibatch) END가 ! $ ACC 병렬

...

종료 하는가 $

!! 장치 ! $ ACC HOST_DATA USE_DEVICE (A_d, ipiv, 정보) 합계 = cublasDgetrfBatched (cublas_handle, m, A_d, m, ipiv, 정보, nbatch) ! $ ACC END HOST_DATA

에 A_d의 장치 주소를 보내

...

!$ ACC END DATA


         or 

! 장치에 A_d를 제외한 모든 것을 넣으십시오! ! $ ACC DATA COPYIN (A) 작성 (정보) COPYOUT (ipiv)

!! , ibatch = 1 않는 호스트 A_d 어레이 채우는 nbatch A_d (ibatch) = acc_deviceptr (A (1,1 ibatch)) END

마십시오! A_d를 기기에 복사하십시오. ! $ acc data copyin (A_d) ...

!! 장치 ! $ ACC HOST_DATA USE_DEVICE (A_d, ipiv, 정보) 합계 = cublasDgetrfBatched (cublas_handle, m, A_d, m, ipiv, 정보, nbatch) 에 A_d 등의 장치 주소를 보내! $ ACC END HOST_DATA

... ! 설명의 일부 단어를 제공하는 ACC 엔드 데이터

! $ ACC END DATA

+2

마음을 $? –

관련 문제