0

ADI前提条件付きのBiCG反復ソルバーの一部として、cuBLASバッチLUおよびcuSPARSEバッチ三重対角ソルバーを使用するFortranコードに取り組んできました。計算機能3.5およびCUDA 5.5のKepler K20Xを使用しています。PGI の CUDA Fortran を使用せずにこれを行っているため、独自のインターフェイスを作成しています。

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

cudaHostAlloc を使用してホストに固定メモリを割り当て、マトリックス用のデバイス メモリとマトリックスへのデバイス ポインターを含むデバイス配列を割り当て、各マトリックスをデバイスに非同期にコピーし、操作を実行してから、分解されたマトリックスとピボットを非同期にコピーします。ホストに戻り、単一の右辺で後方置換を実行します。

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 に制限しており、私のサイズは 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

OpenACC を使用して GPU にもっと多くの計算を配置したいのですが、そのためには 2 つをインターフェースできる必要があります。次のようなもの:

!$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_device 句を含む host_data コンストラクトが適切であることはわかっていますが、デバイス上のマトリックスへのポインターを含むデバイス配列を実際に cuBLAS に渡す必要があるため、どうすればよいかわかりません。

誰でも洞察を提供できますか?

ありがとう

4

1 に答える 1

1

!! すべてをデバイスに置く !$ACC DATA COPYIN(A) CREATE(info,A_d) COPYOUT(ipiv)

!! デバイス A_d 配列に入力します !$ACC parallel loop DO ibatch = 1,nbatch A_d(ibatch) = A(1,1,ibatch) END DO !$ACC end parallel

...

!! A_dのデバイスアドレスをデバイスに送信 !$ACC HOST_DATA USE_DEVICE(A_d,ipiv,info) stat = cublasDgetrfBatched(cublas_handle, m, A_d, m, ipiv, info, nbatch) !$ACC END HOST_DATA

...

!$ACC 終了データ


                                       or

!! A_d 以外のすべてをデバイスに置く !$ACC DATA COPYIN(A) CREATE(info) COPYOUT(ipiv)

!! ホスト A_d 配列に入力します DO ibatch = 1,nbatch A_d(ibatch) = acc_deviceptr( A(1,1,ibatch) ) END DO

!! A_d をデバイスにコピー !$acc data copyin( A_d ) ...

!! A_dなどのデバイスアドレスをデバイスに送信 !$ACC HOST_DATA USE_DEVICE(A_d,ipiv,info) stat = cublasDgetrfBatched(cublas_handle, m, A_d, m, ipiv, info, nbatch) !$ACC END HOST_DATA

... !$acc 終了データ

!$ACC 終了データ

于 2014-07-07T17:37:49.973 に答える