저는 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에 행렬에 대한 포인터를 포함하는 장치 배열을 전달해야하기 때문에, 계속 진행하는 방법을 모르겠습니다.
아무도 통찰력을 제공 할 수 있습니까?
감사합니다.
마음을 $? –